web-dev-qa-db-fra.com

Comment puis-je ajouter un champ de téléchargement d'image directement à un panneau d'écriture personnalisé?

J'ai ajouté une nouvelle page sous "Pages" dans l'administrateur wordpress et ajouté plusieurs champs personnalisés. J'aimerais également pouvoir ajouter un champ d'image de téléchargement à l'éditeur de page. Existe-t-il un moyen de le faire via des champs personnalisés?

Ou dois-je prendre une direction différente si j'ai besoin de cette capacité?

61
Will

Pour ceux qui souhaitent en savoir plus sur le téléchargement de fichiers, voici un bref aperçu des principaux sujets et points critiques. Ceci est écrit avec WordPress 3.0 sur une machine Linux à l’esprit, et le code n’est qu’un aperçu de base pour enseigner les concepts. Je suis sûr que certaines personnes ici pourraient donner des conseils pour améliorer la mise en œuvre.

Décrivez votre approche de base

Il existe au moins trois façons d'associer des images à des publications: utiliser un champ post_meta pour stocker le chemin de l'image, utiliser un champ post_meta pour stocker l'ID de la bibliothèque multimédia de l'image (plus de détails plus tard) ou attribuer l'image à la publication en pièce jointe. . Cet exemple utilisera un champ post_meta pour stocker l'ID de la bibliothèque multimédia de l'image. YMMV.

Encodage en plusieurs parties

Par défaut, les formulaires de création et de modification de WordPress n’ont aucun type d’enctype. Si vous souhaitez télécharger un fichier, vous devez ajouter un "enctype = 'multipart/form-data" "à la balise de formulaire - sinon la collection $ _FILES ne sera pas poussée du tout. Dans WordPress 3.0, il existe un crochet pour cela. Dans certaines versions précédentes (vous n'êtes pas sûr des détails), vous devez remplacer la balise de formulaire par une chaîne.

function xxxx_add_edit_form_multipart_encoding() {

    echo ' enctype="multipart/form-data"';

}
add_action('post_edit_form_tag', 'xxxx_add_edit_form_multipart_encoding');

Créer la méta-boîte et le champ de téléchargement

Je n'entrerai pas beaucoup dans la création de méta-boîtes car la plupart d'entre vous savent probablement déjà comment le faire, mais je dirai simplement que vous n'avez besoin que d'une simple méta-boîte contenant un champ de fichier. Dans l'exemple ci-dessous, j'ai inclus du code permettant de rechercher une image existante et de l'afficher, le cas échéant. J'ai également inclus une fonctionnalité simple d'erreur/retour qui transmet les erreurs à l'aide d'un champ post_meta. Vous voudrez changer ceci pour utiliser la classe WP_Error ... c'est juste pour la démonstration.

function xxxx_render_image_attachment_box($post) {

    // See if there's an existing image. (We're associating images with posts by saving the image's 'attachment id' as a post meta value)
    // Incidentally, this is also how you'd find any uploaded files for display on the frontend.
    $existing_image_id = get_post_meta($post->ID,'_xxxx_attached_image', true);
    if(is_numeric($existing_image_id)) {

        echo '<div>';
            $arr_existing_image = wp_get_attachment_image_src($existing_image_id, 'large');
            $existing_image_url = $arr_existing_image[0];
            echo '<img src="' . $existing_image_url . '" />';
        echo '</div>';

    }

    // If there is an existing image, show it
    if($existing_image_id) {

        echo '<div>Attached Image ID: ' . $existing_image_id . '</div>';

    } 

    echo 'Upload an image: <input type="file" name="xxxx_image" id="xxxx_image" />';

    // See if there's a status message to display (we're using this to show errors during the upload process, though we should probably be using the WP_error class)
    $status_message = get_post_meta($post->ID,'_xxxx_attached_image_upload_feedback', true);

    // Show an error message if there is one
    if($status_message) {

        echo '<div class="upload_status_message">';
            echo $status_message;
        echo '</div>';

    }

    // Put in a hidden flag. This helps differentiate between manual saves and auto-saves (in auto-saves, the file wouldn't be passed).
    echo '<input type="hidden" name="xxxx_manual_save_flag" value="true" />';

}



function xxxx_setup_meta_boxes() {

    // Add the box to a particular custom content type page
    add_meta_box('xxxx_image_box', 'Upload Image', 'xxxx_render_image_attachment_box', 'post', 'normal', 'high');

}
add_action('admin_init','xxxx_setup_meta_boxes');

Gestion du téléchargement de fichier

Il s’agit du gros problème: gérer le téléchargement du fichier en s’accrochant à l’action save_post. J'ai inclus une fonction très commentée ci-dessous, mais j'aimerais noter les deux fonctions clés de WordPress qu'il utilise:

wp_handle_upload () fait toute la magie de, eh bien, gérer le téléchargement. Vous lui transmettez simplement une référence à votre champ dans le tableau $ _FILES et un tableau d’options (ne vous inquiétez pas trop à leur sujet. Le seul élément important à définir est test_form = false. Faites-moi confiance.). Cette fonction n’ajoute toutefois pas le fichier téléchargé à la médiathèque. Il effectue simplement le téléchargement et renvoie le chemin d'accès du nouveau fichier (et, également, l'URL complète). En cas de problème, une erreur est renvoyée.

wp_insert_attachment () ajoute l'image à la médiathèque et génère toutes les vignettes appropriées. Vous venez de lui transmettre un tableau d’options (titre, statut du message, etc.), ainsi que le chemin LOCAL (et non l’URL) du fichier que vous venez de télécharger. L'avantage de placer vos images dans la médiathèque est que vous pouvez facilement supprimer tous les fichiers ultérieurement en appelant wp_delete_attachment et en lui transmettant l'ID de la médiathèque de l'élément (ce que je suis en train de faire dans la fonction ci-dessous). Avec cette fonction, vous devrez également utiliser wp_generate_attachment_metadata () et wp_update_attachment_metadata (), qui font exactement ce que vous attendez d'eux: générer des métadonnées pour l'élément multimédia.

function xxxx_update_post($post_id, $post) {

    // Get the post type. Since this function will run for ALL post saves (no matter what post type), we need to know this.
    // It's also important to note that the save_post action can runs multiple times on every post save, so you need to check and make sure the
    // post type in the passed object isn't "revision"
    $post_type = $post->post_type;

    // Make sure our flag is in there, otherwise it's an autosave and we should bail.
    if($post_id && isset($_POST['xxxx_manual_save_flag'])) { 

        // Logic to handle specific post types
        switch($post_type) {

            // If this is a post. You can change this case to reflect your custom post slug
            case 'post':

                // HANDLE THE FILE UPLOAD

                // If the upload field has a file in it
                if(isset($_FILES['xxxx_image']) && ($_FILES['xxxx_image']['size'] > 0)) {

                    // Get the type of the uploaded file. This is returned as "type/extension"
                    $arr_file_type = wp_check_filetype(basename($_FILES['xxxx_image']['name']));
                    $uploaded_file_type = $arr_file_type['type'];

                    // Set an array containing a list of acceptable formats
                    $allowed_file_types = array('image/jpg','image/jpeg','image/gif','image/png');

                    // If the uploaded file is the right format
                    if(in_array($uploaded_file_type, $allowed_file_types)) {

                        // Options array for the wp_handle_upload function. 'test_upload' => false
                        $upload_overrides = array( 'test_form' => false ); 

                        // Handle the upload using WP's wp_handle_upload function. Takes the posted file and an options array
                        $uploaded_file = wp_handle_upload($_FILES['xxxx_image'], $upload_overrides);

                        // If the wp_handle_upload call returned a local path for the image
                        if(isset($uploaded_file['file'])) {

                            // The wp_insert_attachment function needs the literal system path, which was passed back from wp_handle_upload
                            $file_name_and_location = $uploaded_file['file'];

                            // Generate a title for the image that'll be used in the media library
                            $file_title_for_media_library = 'your title here';

                            // Set up options array to add this file as an attachment
                            $attachment = array(
                                'post_mime_type' => $uploaded_file_type,
                                'post_title' => 'Uploaded image ' . addslashes($file_title_for_media_library),
                                'post_content' => '',
                                'post_status' => 'inherit'
                            );

                            // Run the wp_insert_attachment function. This adds the file to the media library and generates the thumbnails. If you wanted to attch this image to a post, you could pass the post id as a third param and it'd magically happen.
                            $attach_id = wp_insert_attachment( $attachment, $file_name_and_location );
                            require_once(ABSPATH . "wp-admin" . '/includes/image.php');
                            $attach_data = wp_generate_attachment_metadata( $attach_id, $file_name_and_location );
                            wp_update_attachment_metadata($attach_id,  $attach_data);

                            // Before we update the post meta, trash any previously uploaded image for this post.
                            // You might not want this behavior, depending on how you're using the uploaded images.
                            $existing_uploaded_image = (int) get_post_meta($post_id,'_xxxx_attached_image', true);
                            if(is_numeric($existing_uploaded_image)) {
                                wp_delete_attachment($existing_uploaded_image);
                            }

                            // Now, update the post meta to associate the new image with the post
                            update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                            // Set the feedback flag to false, since the upload was successful
                            $upload_feedback = false;


                        } else { // wp_handle_upload returned some kind of error. the return does contain error details, so you can use it here if you want.

                            $upload_feedback = 'There was a problem with your upload.';
                            update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                        }

                    } else { // wrong file type

                        $upload_feedback = 'Please upload only image files (jpg, gif or png).';
                        update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                    }

                } else { // No file was passed

                    $upload_feedback = false;

                }

                // Update the post meta with any feedback
                update_post_meta($post_id,'_xxxx_attached_image_upload_feedback',$upload_feedback);

            break;

            default:

        } // End switch

    return;

} // End if manual save flag

    return;

}
add_action('save_post','xxxx_update_post',1,2);

Autorisations, propriété et sécurité

Si vous rencontrez des difficultés pour télécharger, il se peut que vous ayez à passer par des autorisations. Je ne suis pas un expert en configuration de serveur, donc corrigez-moi s'il vous plaît.

Tout d’abord, assurez-vous que votre dossier wp-content/uploads existe et qu’il appartient à Apache: apache. Si tel est le cas, vous devriez pouvoir définir les autorisations sur 744 et tout devrait fonctionner. La propriété est importante - même le réglage des permanentes sur 777 ne sera parfois pas utile si le répertoire n'est pas correctement possédé.

Vous devriez également envisager de limiter les types de fichiers téléchargés et exécutés à l'aide d'un fichier htaccess. Cela empêche les personnes de télécharger des fichiers qui ne sont pas des images et d'exécuter des scripts déguisés en images. Vous devriez probablement google ceci pour plus d'informations faisant autorité, mais vous pouvez faire une limitation de type de fichier simple comme ceci:

<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
order deny,allow
deny from all
</Files>
108
MathSmath

Le code fourni par @MathSmath est correct. Toutefois, si vous gérez de nombreux champs de téléchargement ou souhaitez télécharger plusieurs fichiers, vous devez le modifier beaucoup.

De plus, il n’utilise pas la médiathèque WordPress pour le téléchargement de fichiers (ce qui fait tout le sale boulot derrière la scène).

Je vous suggère de jeter un coup d'œil à un plugin tel que Meta Box . Le plugin prend en charge les deux manières de télécharger des fichiers:

  • Via HTML5 input[type="file"], qui utilise un code similaire ci-dessus (voir docs ) et
  • Via la médiathèque WordPress (voir docs ).

Cela peut vous aider à réduire les efforts d'écriture et de maintenance du code, en particulier lorsque vous souhaitez créer plusieurs téléchargements.

Disclaimer: Je suis l'auteur de Meta Box.

0
Anh Tran