Jak mogę dodać pole przesyłania obrazu bezpośrednio do niestandardowego panelu zapisu?

62

Dodałem nową stronę pod „Pages” w wordpress admin i dodałem kilka niestandardowych pól. Chciałbym również móc dodać pole do przesłania obrazu do edytora stron - czy jest jakiś sposób to zrobić za pomocą niestandardowych pól?

Czy może muszę obrać inny kierunek, jeśli potrzebuję tej umiejętności?

Będzie
źródło
sprawdź wtyczkę tdo-form, być może jest to łatwe rozwiązanie
bueltge
To pytanie jest prawdopodobnie powiązane: wordpress.stackexchange.com/questions/4291/…
hakre

Odpowiedzi:

108

Dla każdego, kto chce dowiedzieć się więcej o przesyłaniu plików, oto szybki podkład obejmujący najważniejsze tematy i problemy. Zostało to napisane z myślą o WordPress 3.0 na Linux-ie, a kod jest tylko podstawowym przeglądem do nauczania pojęć. Jestem pewien, że niektórzy ludzie tutaj mogą zaoferować porady dotyczące poprawy wdrażania.

Przedstaw swoje podstawowe podejście

Istnieją co najmniej trzy sposoby kojarzenia obrazów z postami: użycie pola post_meta do przechowywania ścieżki obrazu, użycie pola post_meta do przechowywania identyfikatora biblioteki multimediów obrazu (więcej na ten temat później) lub przypisanie obrazu do postu jako załącznika . W tym przykładzie użyto pola post_meta do przechowywania identyfikatora biblioteki multimediów obrazu. YMMV.

Kodowanie wieloczęściowe

Domyślnie formularze do tworzenia i edycji WordPress nie mają żadnego typu. Jeśli chcesz przesłać plik, musisz dodać „enctype = 'multipart / form-data” do tagu formularza - w przeciwnym razie kolekcja $ _FILES w ogóle nie zostanie przepchnięta. W WordPress 3.0 jest na to haczyk. W niektórych wcześniejszych wersjach (nie jestem pewien szczegółów) musisz ciąg zastąpić tag formularza.

function xxxx_add_edit_form_multipart_encoding() {

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

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

Utwórz Meta Box i prześlij pole

Nie będę się zbytnio zajmował tworzeniem meta-boxów, ponieważ większość z was prawdopodobnie już wie, jak to zrobić, ale powiem tylko, że potrzebujesz tylko prostej meta-boxu z polem pliku. W poniższym przykładzie zawarłem trochę kodu, aby wyszukać istniejący obraz i wyświetlić go, jeśli taki istnieje. Dołączyłem także kilka prostych funkcji błędów / sprzężenia zwrotnego, które przekazują błędy za pomocą pola post_meta. Będziesz chciał to zmienić, aby użyć klasy WP_Error ... to tylko dla celów demonstracyjnych.

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');

Obsługa przesyłania plików

To jest duże - w rzeczywistości obsługuje przesyłanie plików, podpinając się do akcji save_post. Poniżej zamieściłem mocno skomentowaną funkcję, ale chciałbym zwrócić uwagę na dwie kluczowe funkcje WordPress, których używa:

wp_handle_upload () robi całą magię, no cóż, obsługi przesyłania. Po prostu przekazujesz mu odniesienie do swojego pola w tablicy $ _FILES i tablicę opcji (nie przejmuj się zbytnio o nie - jedyną ważną, którą musisz ustawić, jest test_form = false. Zaufaj mi). Ta funkcja nie dodaje jednak przesłanego pliku do biblioteki multimediów. Po prostu wykonuje przesyłanie i zwraca ścieżkę nowego pliku (a także pełny adres URL). Jeśli występuje problem, zwraca błąd.

wp_insert_attachment () dodaje obraz do biblioteki multimediów i generuje wszystkie odpowiednie miniatury. Po prostu przekazujesz mu szereg opcji (tytuł, status postu itp.) Oraz ścieżkę LOKALNĄ (nie URL) do właśnie przesłanego pliku. Wspaniałą rzeczą w umieszczaniu obrazów w bibliotece multimediów jest to, że możesz później łatwo usunąć wszystkie pliki, wywołując wp_delete_attachment i przekazując mu identyfikator biblioteki multimediów elementu (co robię w funkcji poniżej). Dzięki tej funkcji będziesz także musiał użyć wp_generate_attachment_metadata () i wp_update_attachment_metadata (), które robią dokładnie to, czego oczekujesz - generują metadane dla elementu multimedialnego.

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);

Uprawnienia, własność i bezpieczeństwo

Jeśli masz problemy z przesyłaniem, może to mieć związek z uprawnieniami. Nie jestem ekspertem od konfiguracji serwera, więc popraw mnie, jeśli ta część jest niepewna.

Po pierwsze, upewnij się, że twój folder wp-content / uploads istnieje i jest własnością apache: apache. Jeśli tak, powinieneś być w stanie ustawić uprawnienia na 744 i wszystko powinno po prostu działać. Własność jest ważna - nawet ustawienie perms na 777 czasami nie pomoże, jeśli katalog nie jest właściwie własnością.

Należy również rozważyć ograniczenie typów plików przesyłanych i wykonywanych przy użyciu pliku htaccess. Uniemożliwia to przesyłanie plików, które nie są obrazami, oraz wykonywanie skryptów zamaskowanych jako obrazy. Prawdopodobnie powinieneś google uzyskać więcej autorytatywnych informacji, ale możesz zrobić proste ograniczenie typu pliku, takie jak:

<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
order deny,allow
deny from all
</Files>
MathSmath
źródło
Dziękuję bardzo MathSmath! Dokładnie to, czego potrzebowałem. Chciałbym móc wyrazić uznanie dla tej odpowiedzi!
Michał Mau
Doskonałe wyjaśnienie! Jedyną rzeczą, którą byłbym bardzo wdzięczny za rozwinięcie, jest to, jak uniemożliwić dostęp do określonych plików publicznie. Innymi słowy, jeśli chcesz utworzyć określony typ postu, w którym wszystkie przesłane pliki są dostępne tylko dla użytkowników o określonych możliwościach. Czy mógłbyś rozwinąć tę kwestię?
NetConstructor.com,
3
Każdy, kto chce przesyłać pliki na interfejsie użytkownika, musi dołączyć następujący kod, aby uzyskać dostęp do funkcji wp_handle_upload ():if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );
Nick Budden,
@ NetConstructor.com Sugeruję, aby utworzyć pytanie, ponieważ wykracza to poza zakres tej odpowiedzi.
hitautodestruct
0

Kod podany przez @MathSmath jest poprawny. Jeśli jednak obsługujesz wiele pól przesyłania lub chcesz przesłać wiele plików, musisz je bardzo zmodyfikować.

Poza tym nie wykorzystuje biblioteki multimediów WordPress do przesyłania plików (co powoduje całą brudną robotę za sceną).

Proponuję rzucić okiem na wtyczkę taką jak Meta Box . Wtyczka obsługuje oba sposoby przesyłania plików:

  • Przez HTML5 input[type="file"], który wykorzystuje podobny kod powyżej (patrz dokumenty ) i
  • Przez WordPress Media Library (patrz dokumenty ).

Pomoże Ci to zredukować wysiłek związany z pisaniem i utrzymywaniem kodu, zwłaszcza gdy chcesz utworzyć wiele przesyłanych plików.

Oświadczenie: Jestem autorem Meta Box.

Anh Tran
źródło