Añadir configuración a un tipo de publicación personalizado

5 ago 2016, 12:10:18
Vistas: 15.3K
Votos: 3

Tengo un tipo de publicación personalizado llamado Portfolio. Está asociado con tres taxonomías personalizadas. Todo esto funciona correctamente.

Sin embargo, para la página de archivo, necesito añadir algunas configuraciones personalizadas. Debido a una limitación en el proyecto, no puedo escribir un plugin; todos los cambios deben hacerse en el tema.

He conseguido que aparezca la subpágina de configuración en el menú (fue fácil) siguiendo esta guía, y las configuraciones aparecen en la página sin problemas. El problema ahora es que no se guardan.

Solo he añadido una configuración (header_text) hasta que pueda resolver el problema de guardado.

Supongo que $option_group probablemente sea el problema.

Si hago var_dump($_POST) obtengo:

array (size=6)
  'option_page' => string 'edit.php?post_type=rushhour_projects&page=projects_archive' (length=58)
  'action' => string 'update' (length=6)
  '_wpnonce' => string '23c70a3029' (length=10)
  '_wp_http_referer' => string '/wp-admin/edit.php?post_type=rushhour_projects&page=projects_archive' (length=68)
  'rushhour_projects_archive' => 
    array (size=1)
      'header_text' => string 'asdf' (length=4)
  'submit' => string 'Save Changes' (length=12)

Aquí está el registro del tipo de publicación personalizado:

if ( ! function_exists('rushhour_post_type_projects') ) :

// Añadir Portfolio Projects a WordPress
add_action( 'init', 'rushhour_post_type_projects', 0 );

// Registrar Custom Post Type para Portfolio Projects
function rushhour_post_type_projects()
{
    $labels = array(
        'name'                  => _x( 'Portfolio', 'Post Type General Name', 'rushhour' ),
        'singular_name'         => _x( 'Project', 'Post Type Singular Name', 'rushhour' ),
        'menu_name'             => __( 'Portfolio Projects', 'rushhour' ),
        'name_admin_bar'        => __( 'Portfolio Project', 'rushhour' ),
        'archives'              => __( 'Portfolio Archives', 'rushhour' ),
        'parent_item_colon'     => __( 'Parent Project:', 'rushhour' ),
        'all_items'             => __( 'All Projects', 'rushhour' ),
        'add_new_item'          => __( 'Add New Project', 'rushhour' ),
        'add_new'               => __( 'Add New', 'rushhour' ),
        'new_item'              => __( 'New Project', 'rushhour' ),
        'edit_item'             => __( 'Edit Project', 'rushhour' ),
        'update_item'           => __( 'Update Project', 'rushhour' ),
        'view_item'             => __( 'View Project', 'rushhour' ),
        'search_items'          => __( 'Search Projects', 'rushhour' ),
        'not_found'             => __( 'Not found', 'rushhour' ),
        'not_found_in_trash'    => __( 'Not found in Trash', 'rushhour' ),
        'featured_image'        => __( 'Featured Image', 'rushhour' ),
        'set_featured_image'    => __( 'Set featured image', 'rushhour' ),
        'remove_featured_image' => __( 'Remove featured image', 'rushhour' ),
        'use_featured_image'    => __( 'Use as featured image', 'rushhour' ),
        'insert_into_item'      => __( 'Insert into project', 'rushhour' ),
        'uploaded_to_this_item' => __( 'Uploaded to this project', 'rushhour' ),
        'items_list'            => __( 'Projects list', 'rushhour' ),
        'items_list_navigation' => __( 'Projects list navigation', 'rushhour' ),
        'filter_items_list'     => __( 'Filter projects list', 'rushhour' ),
        );
    $rewrite = array(
        'slug'                  => 'portfolio',
        'with_front'            => true,
        'pages'                 => true,
        'feeds'                 => true,
        );
    $args = array(
        'label'                 => __( 'Project', 'rushhour' ),
        'description'           => __( 'Portfolio projects for Global VDC.', 'rushhour' ),
        'labels'                => $labels,
        'supports'              => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions', ),
        'taxonomies'            => array( 'rushhour_clients', 'rushhour_locations', 'rushhour_project_type' ),
        'hierarchical'          => false,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 5,
        'menu_icon'             => 'dashicons-portfolio',
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => true,
        'can_export'            => true,
        'has_archive'           => 'portfolio',
        'exclude_from_search'   => false,
        'publicly_queryable'    => true,
        'rewrite'               => $rewrite,
        'capability_type'       => 'page',
        );
    register_post_type( 'rushhour_projects', $args );
}
endif;

Luego tengo una función para configurar la subpágina de administración:

if ( ! function_exists('rushhour_projects_admin_page') ) :

add_action( 'admin_menu' , 'rushhour_projects_admin_page' );

/**
 * Generar subpágina de menú para configuraciones
 *
 * @uses rushhour_projects_options_display()
 */
function rushhour_projects_admin_page()
{
    add_submenu_page(
        'edit.php?post_type=rushhour_projects',
        __('Portfolio Projects Options', 'rushhour'),
        __('Portfolio Options', 'rushhour'),
        'manage_options',
        'projects_archive',
        'rushhour_projects_options_display');
}
endif;

Los dos elementos anteriores funcionan sin problemas.

El problema, creo, está en alguna parte de las siguientes funciones para registrar y guardar las configuraciones:

if ( ! function_exists('rushhour_projects_options_display') ) :
/**
 * Mostrar el formulario en la subpágina de configuración de Rush Hour Projects.
 *
 * Usado por 'rushhour_projects_admin_page'.
 */
function rushhour_projects_options_display()
{
    // Crear un encabezado en el contenedor 'wrap' predeterminado de WordPress
    echo '<div class="wrap">';

    settings_errors();

    echo '<form method="post" action="">';

    var_dump( get_option('rushhour_projects_archive') );

    settings_fields( 'edit.php?post_type=rushhour_projects&page=projects_archive' );

    do_settings_sections( 'edit.php?post_type=rushhour_projects&page=projects_archive' );

    submit_button();

    echo '</form></div><!-- .wrap -->';
}
endif;

add_action( 'admin_init', 'rushhour_projects_settings' );

/**
 * Registrar configuraciones y añadir secciones y campos a la página de administración.
 */
function rushhour_projects_settings()
{
    if ( false == get_option( 'rushhour_projects_archive' ) )
        add_option( 'rushhour_projects_archive' );

    add_settings_section(
        'projects_archive_header', // $id de la sección
        __('Portfolio Project Archive Page Settings', 'rushhour'),
        'rushhour_project_settings_section_title', // Callback
        'edit.php?post_type=rushhour_projects&page=projects_archive' // Slug de la página de configuración
        );

    add_settings_field(
        'header_text',          // $id del campo
        __('Header Text', 'rushhour'),          // $title de la configuración
        'projects_archive_header_text_callback',
        'edit.php?post_type=rushhour_projects&page=projects_archive',   // Slug de la página de configuración
        'projects_archive_header',          // $id de la sección
        array('Text to display in the archive header.')
        );

    register_setting(
        'edit.php?post_type=rushhour_projects&page=projects_archive', // $option_group
        'rushhour_projects_archive',  // $option_name
        'rushhour_projects_archive_save_options'
        );
}

/**
 * Callback para la sección de configuraciones.
 *
 * Comentado hasta que las configuraciones funcionen.
 * 
 * @param  array $args Obtiene el $id, $title y $callback.
 */
function rushhour_project_settings_section_title( $args ) {
    // printf( '<h2>%s</h2>', apply_filters( 'the_title', $args['title'] ) );
}

/**
 * Callbacks para los campos de configuración.
 */
function projects_archive_header_text_callback($args)
{
    $options = get_option('rushhour_projects_archive');

    printf( '<input class="widefat" id="header_text" name="rushhour_projects_archive[header_text]" type="textarea" value="%1$s" />',
        $options );
}

/**
 * Guardar opciones.
 */
function rushhour_projects_archive_save_options()
{
    if ( isset( $_POST['rushhour_projects_archive[header_text]'] ) )
    {
        update_option( 'rushhour_projects_archive', $_POST['rushhour_projects_archive[header_text]'] );
    }
}
3
Comentarios

Solo para comentar sobre "No puedo escribir un plugin", eso no es un problema. Normalmente, cualquier cosa que podrías poner en un plugin puede ir en el archivo functions.php del tema en su lugar, si eso se adapta mejor a tu situación.

Andy Macaulay-Brook Andy Macaulay-Brook
5 ago 2016 12:12:50

Hola, Andy. Gracias por tu respuesta. Tienes razón, no es un problema, pero pensé que era un parámetro que valía la pena mencionar para quienes respondan.

dotZak dotZak
5 ago 2016 12:14:25

Sí. Una pregunta muy completa y detallada. No puedo responder yo mismo en este momento, pero espero que mi voto positivo te atraiga algo de atención de alguien.

Andy Macaulay-Brook Andy Macaulay-Brook
5 ago 2016 12:22:23
Todas las respuestas a la pregunta 2
0

Bien, me molestó que no funcionara y decidí reescribirlo. No estoy seguro de cuál era la solución, pero sospecho dos cosas: el endpoint incorrecto para el formulario (debería ser options.php) y el $option_group y $option_name incorrectos (probablemente no coincidían correctamente).

Para la posteridad, dejaré mi reescritura aquí y espero que ayude a otros. Algunas diferencias entre esta y la versión anterior.

  1. Ahora está en su propio archivo, así que no verás el tipo de entrada personalizado registrado.
  2. Usé un objeto para la página según el ejemplo 2 del codex de WordPress.
  3. Agregué una segunda opción para un cargador de medios usando este tutorial, que actualicé para usar wp_localize_script() para inyectar un objeto JSON y obtener algunos datos de PHP.
    <?php
    class RushHourProjectArchivesAdminPage
    {
        /**
         * Contiene los valores a usar en las devoluciones de llamada de los campos
         */
        private $options;

        public function __construct()
        {
            add_action( 'admin_menu', array( $this, 'add_submenu_page_to_post_type' ) );
            add_action( 'admin_init', array( $this, 'sub_menu_page_init' ) );
            add_action( 'admin_init', array( $this, 'media_selector_scripts' ) );
        }

        /**
         * Agrega una página de submenú al tipo de entrada personalizado
         */
        public function add_submenu_page_to_post_type()
        {
            add_submenu_page(
                'edit.php?post_type=rushhour_projects',
                __('Opciones de Proyectos de Portafolio', 'rushhour'),
                __('Opciones de Portafolio', 'rushhour'),
                'manage_options',
                'projects_archive',
                array($this, 'rushhour_projects_options_display'));
        }

        /**
         * Devuelve la página de opciones
         */
        public function rushhour_projects_options_display()
        {
            $this->options = get_option( 'rushhour_projects_archive' );

            wp_enqueue_media();

            echo '<div class="wrap">';

            printf( '<h1>%s</h1>', __('Opciones de Portafolio', 'rushhour' ) ); 

            echo '<form method="post" action="options.php">';

            settings_fields( 'projects_archive' );

            do_settings_sections( 'projects-archive-page' );

            submit_button();

            echo '</form></div>';
        }

        /**
         * Registra y agrega configuraciones
         */
        public function sub_menu_page_init()
        {
            register_setting(
                'projects_archive', // Grupo de opciones
                'rushhour_projects_archive', // Nombre de la opción
                array( $this, 'sanitize' ) // Sanitización
                );

            add_settings_section(
                'header_settings_section', // ID
                __('Configuraciones de Encabezado', 'rushhour'), // Título
                array( $this, 'print_section_info' ), // Callback
                'projects-archive-page' // Página
                );

            add_settings_field(
                'archive_description', // ID
                __('Descripción del Archivo', 'rushhour'), // Título
                array( $this, 'archive_description_callback' ), // Callback
                'projects-archive-page', // Página
                'header_settings_section' // Sección
                );

            add_settings_field(
                'image_attachment_id',
                __('Imagen de Fondo del Encabezado', 'rushhour'),
                array( $this, 'header_bg_image_callback' ),
                'projects-archive-page',
                'header_settings_section'
                );
        }

        /**
         * Sanitiza cada campo de configuración según sea necesario
         *
         * @param array $input Contiene todos los campos de configuración como claves de array
         */
        public function sanitize( $input )
        {
            $new_input = array();

            if( isset( $input['archive_description'] ) )
                $new_input['archive_description'] = sanitize_text_field( $input['archive_description'] );

            if( isset( $input['image_attachment_id'] ) )
                $new_input['image_attachment_id'] = absint( $input['image_attachment_id'] );

            return $new_input;
        }

        /**
         * Imprime el texto de la sección
         */
        public function print_section_info()
        {
            print 'Selecciona opciones para el encabezado de la página de archivo.';
        }

        /**
         * Obtiene el array de opciones de configuración e imprime uno de sus valores
         */
        public function archive_description_callback()
        {
            printf(
                '<input type="text" id="archive_description" name="rushhour_projects_archive[archive_description]" value="%s" />',
                isset( $this->options['archive_description'] ) ? esc_attr( $this->options['archive_description']) : ''
                );
        }

        /**
         * Obtiene el array de opciones de configuración e imprime uno de sus valores
         */
        public function header_bg_image_callback()
        {
            $attachment_id = $this->options['image_attachment_id'];

            // Vista previa de la imagen
            printf('<div class="image-preview-wrapper"><img id="image-preview" src="%s" ></div>', wp_get_attachment_url( $attachment_id ) );

            // Botón de carga de imagen
            printf( '<input id="upload_image_button" type="button" class="button" value="%s" />',
                __( 'Subir imagen', 'rushhour' ) );

            // Campo oculto que contiene el valor del ID de adjunto de la imagen
            printf( '<input type="hidden" name="rushhour_projects_archive[image_attachment_id]" id="image_attachment_id" value="%s">',
                $attachment_id );
        }

        public function media_selector_scripts()
        {
            $my_saved_attachment_post_id = get_option( 'media_selector_attachment_id', 0 );

            wp_register_script( 'sub_menu_media_selector_scripts', get_template_directory_uri() . '/admin/js/media-selector.js', array('jquery'), false, true );

            $selector_data = array(
                'attachment_id' => get_option( 'media_selector_attachment_id', 0 )
                );

            wp_localize_script( 'sub_menu_media_selector_scripts', 'selector_data', $selector_data );

            wp_enqueue_script( 'sub_menu_media_selector_scripts' );
        }
    }

Luego simplemente llama al objeto cuando is_admin() sea verdadero:

    if ( is_admin() )
         $my_settings_page = new RushHourProjectArchivesAdminPage();
8 ago 2016 12:04:47
2

Esto debería funcionar. Cambia

function rushhour_projects_archive_save_options()
{
    if ( isset( $_POST['rushhour_projects_archive[header_text]'] ) )
    {
        update_option( 'rushhour_projects_archive', $_POST['rushhour_projects_archive[header_text]'] );
    }
}

por

function rushhour_projects_archive_save_options()
{
    if ( isset( $_POST['rushhour_projects_archive']['header_text'] ) )
    {
        update_option( 'rushhour_projects_archive', $_POST['rushhour_projects_archive']['header_text'] );
    }
}
5 ago 2016 13:23:10
Comentarios

Oh. ¡Por supuesto! Lo intentaré y te haré saber cómo va. Gracias por eso.

dotZak dotZak
6 ago 2016 03:15:22

Esto no resolvió el problema. Acaba de pasar el fin de semana aquí, así que podré revisarlo esta mañana y te aviso si uso una versión refinada de tu respuesta o no.

dotZak dotZak
8 ago 2016 04:18:02