¿Cómo puedo agregar un campo de carga de imágenes directamente a un panel de escritura personalizado?

19 nov 2010, 20:31:26
Vistas: 114K
Votos: 67

He agregado una nueva página bajo "Páginas" en el panel de administración de WordPress y añadido varios campos personalizados. También me gustaría poder agregar un campo para cargar imágenes en el editor de páginas - ¿hay alguna manera de hacer esto a través de campos personalizados?

¿O necesito tomar un enfoque diferente si necesito esta funcionalidad?

2
Comentarios

revisa el plugin tdo-forms, quizás esta es la solución más sencilla

bueltge bueltge
19 nov 2010 21:07:43

Esta pregunta probablemente esté relacionada: http://wordpress.stackexchange.com/questions/4291/how-to-display-category-information-from-a-custom-post

hakre hakre
19 nov 2010 23:41:55
Todas las respuestas a la pregunta 2
4
112

Para cualquiera que quiera saber más sobre la carga de archivos, aquí hay una guía rápida que cubre los temas principales y puntos problemáticos. Esto está escrito teniendo en mente WordPress 3.0 en un sistema Linux, y el código es solo una descripción general básica para enseñar los conceptos. Estoy seguro de que algunas personas aquí podrían ofrecer consejos para mejorar la implementación.

Definir el Enfoque Básico

Hay al menos tres formas de asociar imágenes con entradas: usando un campo post_meta para almacenar la ruta de la imagen, usando un campo post_meta para almacenar el ID de la biblioteca de medios de la imagen (más sobre esto después), o asignando la imagen a la entrada como un archivo adjunto. Este ejemplo usará un campo post_meta para almacenar el ID de la biblioteca de medios de la imagen. Los resultados pueden variar.

Codificación Multipart

Por defecto, los formularios de creación y edición de WordPress no tienen enctype. Si deseas cargar un archivo, necesitarás agregar un "enctype='multipart/form-data'" a la etiqueta del formulario; de lo contrario, la colección $_FILES no se enviará en absoluto. En WordPress 3.0, hay un gancho para eso. En algunas versiones anteriores (no estoy seguro de los detalles específicos) tienes que reemplazar la etiqueta del formulario.

function xxxx_add_edit_form_multipart_encoding() {

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

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

Crear la Meta Box y el Campo de Carga

No profundizaré mucho en la creación de meta boxes ya que la mayoría de ustedes probablemente ya saben cómo hacerlo, pero solo diré que necesitas una meta box simple con un campo de archivo en ella. En el ejemplo siguiente he incluido código para buscar una imagen existente y mostrarla si existe. También he incluido una funcionalidad simple de error/retroalimentación que pasa errores usando un campo post_meta. Querrás cambiar esto para usar la clase WP_Error... es solo para demostración.

function xxxx_render_image_attachment_box($post) {

    // Ver si hay una imagen existente. (Estamos asociando imágenes con entradas guardando el 'ID de adjunto' de la imagen como un valor meta de la entrada)
    // Por cierto, así es también como encontrarías cualquier archivo cargado para mostrar en el 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 . '" alt="Imagen adjunta existente" title="Imagen adjunta" />';
        echo '</div>';

    }

    // Si hay una imagen existente, mostrarla
    if($existing_image_id) {

        echo '<div>ID de Imagen Adjunta: ' . $existing_image_id . '</div>';

    } 

    echo 'Cargar una imagen: <input type="file" name="xxxx_image" id="xxxx_image" />';

    // Ver si hay un mensaje de estado para mostrar (estamos usando esto para mostrar errores durante el proceso de carga, aunque deberíamos usar la clase WP_error)
    $status_message = get_post_meta($post->ID,'_xxxx_attached_image_upload_feedback', true);

    // Mostrar un mensaje de error si hay uno
    if($status_message) {

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

    }

    // Poner una bandera oculta. Esto ayuda a diferenciar entre guardados manuales y auto-guardados (en auto-guardados, el archivo no se pasaría).
    echo '<input type="hidden" name="xxxx_manual_save_flag" value="true" />';

}

function xxxx_setup_meta_boxes() {

    // Agregar la caja a una página de tipo de contenido personalizado particular
    add_meta_box('xxxx_image_box', 'Cargar Imagen', 'xxxx_render_image_attachment_box', 'post', 'normal', 'high');

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

Manejo de la Carga de Archivos

Este es el más importante: manejar la carga de archivos conectándose a la acción save_post. He incluido una función con muchos comentarios a continuación, pero me gustaría señalar las dos funciones clave de WordPress que utiliza:

wp_handle_upload() hace toda la magia de, bueno, manejar la carga. Solo le pasas una referencia a tu campo en el array $_FILES y un array de opciones (no te preocupes demasiado por estas, la única importante que necesitas establecer es test_form=false. Confía en mí). Esta función, sin embargo, no agrega el archivo cargado a la biblioteca de medios. Simplemente realiza la carga y devuelve la ruta del nuevo archivo (y, convenientemente, también la URL completa). Si hay un problema, devuelve un error.

wp_insert_attachment() agrega la imagen a la biblioteca de medios y genera todas las miniaturas apropiadas. Solo le pasas un array de opciones (título, estado de la publicación, etc.) y la ruta LOCAL (no URL) al archivo que acabas de cargar. Lo genial de poner tus imágenes en la biblioteca de medios es que puedes eliminar fácilmente todos los archivos más tarde llamando a wp_delete_attachment y pasándole el ID de la biblioteca de medios del elemento (que estoy haciendo en la función a continuación). Con esta función, también necesitarás usar wp_generate_attachment_metadata() y wp_update_attachment_metadata(), que hacen exactamente lo que esperarías que hagan: generar metadatos para el elemento multimedia.

function xxxx_update_post($post_id, $post) {

    // Obtener el tipo de entrada. Ya que esta función se ejecutará para TODAS las guardadas de entradas (sin importar el tipo), necesitamos saber esto.
    // También es importante notar que la acción save_post puede ejecutarse múltiples veces en cada guardado de entrada, así que necesitas verificar y asegurarte
    // que el tipo de entrada en el objeto pasado no sea "revision"
    $post_type = $post->post_type;

    // Asegurarse de que nuestra bandera está ahí, de lo contrario es un auto-guardado y deberíamos salir.
    if($post_id && isset($_POST['xxxx_manual_save_flag'])) { 

        // Lógica para manejar tipos de entrada específicos
        switch($post_type) {

            // Si esto es una entrada. Puedes cambiar este caso para reflejar tu slug de entrada personalizada
            case 'post':

                // MANEJAR LA CARGA DE ARCHIVO

                // Si el campo de carga tiene un archivo en él
                if(isset($_FILES['xxxx_image']) && ($_FILES['xxxx_image']['size'] > 0)) {

                    // Obtener el tipo del archivo cargado. Esto se devuelve como "tipo/extensión"
                    $arr_file_type = wp_check_filetype(basename($_FILES['xxxx_image']['name']));
                    $uploaded_file_type = $arr_file_type['type'];

                    // Establecer un array que contiene una lista de formatos aceptables
                    $allowed_file_types = array('image/jpg','image/jpeg','image/gif','image/png');

                    // Si el archivo cargado es del formato correcto
                    if(in_array($uploaded_file_type, $allowed_file_types)) {

                        // Array de opciones para la función wp_handle_upload. 'test_upload' => false
                        $upload_overrides = array( 'test_form' => false ); 

                        // Manejar la carga usando la función wp_handle_upload de WP. Toma el archivo publicado y un array de opciones
                        $uploaded_file = wp_handle_upload($_FILES['xxxx_image'], $upload_overrides);

                        // Si la llamada wp_handle_upload devolvió una ruta local para la imagen
                        if(isset($uploaded_file['file'])) {

                            // La función wp_insert_attachment necesita la ruta del sistema literal, que fue devuelta por wp_handle_upload
                            $file_name_and_location = $uploaded_file['file'];

                            // Generar un título para la imagen que se usará en la biblioteca de medios
                            $file_title_for_media_library = 'tu título aquí';

                            // Configurar array de opciones para agregar este archivo como un adjunto
                            $attachment = array(
                                'post_mime_type' => $uploaded_file_type,
                                'post_title' => 'Imagen cargada ' . addslashes($file_title_for_media_library),
                                'post_content' => '',
                                'post_status' => 'inherit'
                            );

                            // Ejecutar la función wp_insert_attachment. Esto agrega el archivo a la biblioteca de medios y genera las miniaturas. Si quisieras adjuntar esta imagen a una entrada, podrías pasar el id de la entrada como un tercer parámetro y mágicamente sucedería.
                            $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);

                            // Antes de actualizar el meta de la entrada, eliminar cualquier imagen previamente cargada para esta entrada.
                            // Podrías no querer este comportamiento, dependiendo de cómo estés usando las imágenes cargadas.
                            $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);
                            }

                            // Ahora, actualizar el meta de la entrada para asociar la nueva imagen con la entrada
                            update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                            // Establecer la bandera de retroalimentación en false, ya que la carga fue exitosa
                            $upload_feedback = false;


                        } else { // wp_handle_upload devolvió algún tipo de error. El retorno contiene detalles del error, así que puedes usarlo aquí si quieres.

                            $upload_feedback = 'Hubo un problema con tu carga.';
                            update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                        }

                    } else { // tipo de archivo incorrecto

                        $upload_feedback = 'Por favor carga solo archivos de imagen (jpg, gif o png).';
                        update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                    }

                } else { // No se pasó ningún archivo

                    $upload_feedback = false;

                }

                // Actualizar el meta de la entrada con cualquier retroalimentación
                update_post_meta($post_id,'_xxxx_attached_image_upload_feedback',$upload_feedback);

            break;

            default:

        } // Fin switch

    return;

} // Fin if manual save flag

    return;

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

Permisos, Propiedad y Seguridad

Si tienes problemas al cargar, podría estar relacionado con los permisos. No soy experto en configuración de servidores, así que por favor corríjanme si esta parte está mal.

Primero, asegúrate de que tu carpeta wp-content/uploads exista y sea propiedad de apache:apache. Si es así, deberías poder establecer los permisos en 744 y todo debería funcionar. La propiedad es importante: incluso establecer los permisos en 777 a veces no ayudará si el directorio no tiene el propietario adecuado.

También deberías considerar limitar los tipos de archivos cargados y ejecutados usando un archivo htaccess. Esto evita que las personas carguen archivos que no son imágenes y que ejecuten scripts disfrazados como imágenes. Probablemente deberías buscar en Google información más autorizada sobre esto, pero puedes hacer una limitación simple de tipo de archivo así:

<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
order deny,allow
deny from all
</Files>
23 nov 2010 02:28:22
Comentarios

¡Muchas gracias MathSmath! Justo lo que necesitaba. Ojalá pudiera dar más votos positivos a esta respuesta.

Michal Mau Michal Mau
25 ene 2011 06:21:30

¡Excelente explicación! Lo ÚNICO en lo que me gustaría que profundizaras es cómo hacer que archivos subidos específicos sean inaccesibles para el público. En otras palabras, si quisieras crear un tipo de entrada específico donde todos los archivos subidos solo sean accesibles por usuarios con una capacidad específica. ¿Podrías elaborar más sobre esto?

NetConstructor.com NetConstructor.com
25 ene 2011 13:25:17

Para cualquiera que quiera subir archivos en el frontend, necesitarás incluir el siguiente código para tener acceso a la función wp_handle_upload(): if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );

Nick Budden Nick Budden
10 nov 2011 19:27:56

@NetConstructor.com Te sugiero que crees una pregunta ya que eso está completamente fuera del alcance de esta respuesta.

hitautodestruct hitautodestruct
7 mar 2013 14:51:02
0

El código que proporcionó @MathSmath es correcto. Sin embargo, si manejas muchos campos de carga o deseas subir múltiples archivos, tendrás que modificarlo bastante.

Además, no utiliza la biblioteca de medios de WordPress para cargar archivos (que hace todo el trabajo pesado detrás de escena).

Te sugiero que eches un vistazo a un plugin como Meta Box. El plugin admite ambas formas de cargar archivos:

  • Mediante HTML5 input[type="file"], que utiliza un código similar al mencionado (consulta la documentación) y
  • Mediante la Biblioteca de Medios de WordPress (ver documentación).

Puede ayudarte a reducir el esfuerzo de escribir y mantener el código, especialmente cuando deseas crear múltiples cargas.

Aviso: Soy el autor de Meta Box.

24 ene 2018 04:57:44