¿Cómo agregar el metabox de Atributos de Página y Plantillas de Página al editor de Posts?

10 oct 2010, 20:40:15
Vistas: 34K
Votos: 14

(Nota del moderador: El título original era "¿Cómo puedo agregar el selector 'Atributos de Página' y/o 'Atributos de Página > Plantilla' al editor de POSTS?")

WordPress actualmente solo permite asignar una "plantilla" a las Páginas (es decir, post_type=='page'). Me gustaría extender esta funcionalidad a los Posts también (es decir, post_type=='post').

¿Cómo puedo agregar el metabox "Atributos de Página" y más específicamente, el selector de plantillas al editor de posts?

Asumo que este es código que colocaré en mi functions.php para mi tema.

ACTUALIZACIÓN: He logrado agregar el menú desplegable de plantillas codificadas manualmente a mi editor de posts, simplemente agregando el HTML del select box a mi caja de opciones meta personalizadas existente. Este es el código que estoy usando para eso...

add_meta_box('categorydiv2', __('Opciones del Post'), 'post_categories_meta_box_modified', 'post', 'side', 'high');

Y aquí está la función que escribe las opciones y el cuadro de selección de plantilla...

//agrega la caja de categorías personalizada
function post_categories_meta_box_modified() {
    global $post;
    if( get_post_meta($post->ID, '_noindex', true) ) $noindexChecked = " checked='checked'";
    if( get_post_meta($post->ID, '_nofollow', true) ) $nofollowChecked = " checked='checked'";
?>
<div id="categories-all" class="ui-tabs-panel">
    <ul id="categorychecklist" class="list:category categorychecklist form-no-clear">
        <li id='noIndex' class="popular-category"><label class="selectit"><input value="noIndex" type="checkbox" name="chk_noIndex" id="chk_noIndex"<?php echo $noindexChecked ?> /> noindex</label></li> 
        <li id='noFollow' class="popular-category"><label class="selectit"><input value="noFollow" type="checkbox" name="chk_noFollow" id="chk_noFollow"<?php echo $nofollowChecked ?> /> nofollow</label></li>
    </ul>

    <p><strong>Plantilla</strong></p> 
    <label class="screen-reader-text" for="page_template">Plantilla del Post</label><select name="page_template" id="page_template"> 
    <option value='default'>Plantilla Predeterminada</option> 
    <option value='template-wide.php' >Sin Barra Lateral</option>
    <option value='template-salespage.php' >Página de Ventas</option>
    </select>
</div>
<?php
}

Y finalmente, el código para capturar los valores seleccionados al guardar...

function save_post_categories_meta($post_id) {
    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $post_id;
    $noIndex = $_POST['chk_noIndex'];
    $noFollow = $_POST['chk_noFollow'];
    update_post_meta( $post_id, '_noindex', $noIndex );
    update_post_meta( $post_id, '_nofollow', $noFollow );
    return $post_id;
}

Ahora, creo que todo lo que queda es (1) capturar la plantilla seleccionada y agregarla al meta del post para este post y (2) modificar index.php y single.php para que use la plantilla elegida.

2
Comentarios

@Scott B: Bueno, escribí toda mi respuesta antes de ver que tú también estabas trabajando en ello, y parece que has tomado un rumbo algo diferente al de tu pregunta original con tus opciones de nofollow y noindex. Espero que lo que hice todavía tenga valor para ti. Si no, tal vez ayude a otros.

MikeSchinkel MikeSchinkel
11 oct 2010 02:14:37

Sí, has respondido la pregunta. Tomé un enfoque un poco diferente una vez que me di cuenta de que no necesitaba analizar el directorio y podía codificar los valores para mis plantillas específicas. Aún es probable que necesite tomar prestado parte de tu código para que WP realmente use la plantilla asignada correcta para la publicación.

Scott B Scott B
11 oct 2010 19:36:46
Todas las respuestas a la pregunta 2
7
15

Lamento ser el portador de malas noticias, pero WordPress codifica la funcionalidad de Plantilla de Página exclusivamente para el tipo de contenido "page", al menos en la v3.0 (esto podría cambiar en versiones futuras, pero no hay una iniciativa específica que yo conozca para modificarlo todavía. Así que esta es una de las pocas veces que me cuesta encontrar una solución sin modificar el núcleo.)

La solución que he encontrado es básicamente copiar el código relevante del núcleo de WordPress y modificarlo según nuestras necesidades. Aquí están los pasos (los números de línea corresponden a la v3.0.1):

  1. Copiar la función page_attributes_meta_box() de la línea 535 de /wp-admin/includes/meta-boxes.php y modificarla según convenga.

  2. Programar un hook add_meta_boxes para añadir el metabox creado en el paso #1.

  3. Copiar la función get_page_templates() de la línea 166 de /wp-admin/includes/theme.php y modificarla según convenga.

  4. Copiar la función page_template_dropdown() de la línea 2550 de /wp-admin/includes/template.php y modificarla según convenga.

  5. Añadir una Plantilla de Entrada a tu tema.

  6. Programar un hook save_post para guardar el nombre del archivo de plantilla al publicar.

  7. Programar un hook single_template para cargar la plantilla correspondiente a las entradas asociadas.

¡Manos a la obra!


1. Copiar la función page_attributes_meta_box()

Como primer paso, necesitas copiar la función page_attributes_meta_box() de la línea 535 de /wp-admin/includes/meta-boxes.php. Yo la he renombrado como post_template_meta_box(). Como solo pediste plantillas para entradas, omití el código para especificar una entrada padre y el orden, lo que simplifica mucho el código. También decidí usar postmeta en lugar de reutilizar la propiedad page_template para evitar incompatibilidades. Aquí está el código:

function post_template_meta_box($post) {
  if ( 'post' == $post->post_type && 0 != count( get_post_templates() ) ) {
    $template = get_post_meta($post->ID,'_post_template',true);
    ?>
<label class="screen-reader-text" for="post_template"><?php _e('Plantilla de Entrada') ?></label><select name="post_template" id="post_template">
<option value='default'><?php _e('Plantilla Predeterminada'); ?></option>
<?php post_template_dropdown($template); ?>
</select>
<?php
  } ?>
<?php
}

2. Programar un hook add_meta_boxes

El siguiente paso es añadir el metabox usando el hook add_meta_boxes:

add_action('add_meta_boxes','add_post_template_metabox');
function add_post_template_metabox() {
    add_meta_box('postparentdiv', __('Plantilla de Entrada'), 'post_template_meta_box', 'post', 'side', 'core');
}

3. Copiar la función get_page_templates()

Asumí que solo tendría sentido diferenciar entre plantillas de página y plantillas de entrada, de ahí la necesidad de una función get_post_templates() basada en get_page_templates() de la línea 166 de /wp-admin/includes/theme.php. Pero en lugar de usar el marcador Template Name:, esta función usa Post Template:, como se muestra abajo.

También excluí la inspección de functions.php y cambié las referencias de page a post para mayor claridad:

function get_post_templates() {
  $themes = get_themes();
  $theme = get_current_theme();
  $templates = $themes[$theme]['Template Files'];
  $post_templates = array();

  if ( is_array( $templates ) ) {
    $base = array( trailingslashit(get_template_directory()), trailingslashit(get_stylesheet_directory()) );

    foreach ( $templates as $template ) {
      $basename = str_replace($base, '', $template);
      if ($basename != 'functions.php') {
        // no permitir archivos de plantilla en subdirectorios
        if ( false !== strpos($basename, '/') )
          continue;

        $template_data = implode( '', file( $template ));

        $name = '';
        if ( preg_match( '|Post Template:(.*)$|mi', $template_data, $name ) )
          $name = _cleanup_header_comment($name[1]);

        if ( !empty( $name ) ) {
          $post_templates[trim( $name )] = $basename;
        }
      }
    }
  }

  return $post_templates;
}

4. Copiar la función page_template_dropdown()

De manera similar, copia page_template_dropdown() de la línea 2550 de /wp-admin/includes/template.php para crear post_template_dropdown(), cambiando la llamada a get_post_templates():

function post_template_dropdown( $default = '' ) {
  $templates = get_post_templates();
  ksort( $templates );
  foreach (array_keys( $templates ) as $template )
    : if ( $default == $templates[$template] )
      $selected = " selected='selected'";
    else
      $selected = '';
  echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
  endforeach;
}

5. Añadir una Plantilla de Entrada

El siguiente paso es añadir una plantilla de entrada para probar. Usando el marcador Post Template:, copia single.php de tu tema a single-test.php y añade este encabezado (modifica algo en single-test.php para distinguirlo de single.php):

/**
 * Post Template: Mi Plantilla de Prueba
 */

Después de los pasos #1 al #5, verás el metabox "Plantillas de Entrada" en el editor de entradas:

Apariencia del Metabox de Plantillas de Entrada en WordPress 3.0
(fuente: mikeschinkel.com)

6. Programar un hook save_post

Ahora necesitas guardar el nombre del archivo de plantilla en postmeta al publicar. Aquí está el código:

add_action('save_post','save_post_template',10,2);
function save_post_template($post_id,$post) {
  if ($post->post_type=='post' && !empty($_POST['post_template']))
    update_post_meta($post->ID,'_post_template',$_POST['post_template']);
}

7. Programar un hook single_template

Finalmente, necesitas que WordPress use tus nuevas plantillas. Esto se hace con el hook single_template:

add_filter('single_template','get_post_template_for_template_loader');
function get_post_template_for_template_loader($template) {
  global $wp_query;
  $post = $wp_query->get_queried_object();
  if ($post) {
    $post_template = get_post_meta($post->ID,'_post_template',true);
    if (!empty($post_template) && $post_template!='default')
      $template = get_stylesheet_directory() . "/{$post_template}";
  }
  return $template;
}

¡Y eso es todo!

NOTA que no he considerado Tipos de Contenido Personalizados, solo post_type=='post'. En mi opinión, manejar tipos personalizados requeriría diferenciar entre ellos, y aunque no es complicado, no lo he implementado aquí.

11 oct 2010 02:11:33
Comentarios

¡Genial! Me fui a dormir con un código casi completo en mi editor con el mismo enfoque de copiar las funciones predeterminadas de WordPress (estaba completo, pero no lo publicaría ya que no lo probé). :)

sorich87 sorich87
11 oct 2010 10:57:00

@sorich87 - Ya conoces el viejo dicho, "El que se duerme, pierde!" En serio, estoy SOLO bromeando. Realmente solo hay una forma razonable de hacer que funcione, así que no es de extrañar que tu código sea el mismo.

MikeSchinkel MikeSchinkel
11 oct 2010 12:08:41

Mike, sigues sorprendiéndome. Muchas gracias por tomarte el tiempo para resolver esto.

Scott B Scott B
11 oct 2010 19:33:53

@sorich87 - Gracias por trabajar en ello. Realmente aprecio el esfuerzo.

Scott B Scott B
11 oct 2010 19:34:22

@MikeSchinkel: :) era casi exactamente lo mismo. @Scott B: ¡de nada!

sorich87 sorich87
11 oct 2010 19:47:04

@Scott B: No hay problema, me alegra poder ayudar. Busco preguntas razonablemente genéricas que potencialmente podrían ayudar a mucha gente e intento responderlas no solo para la persona que hace la pregunta, sino también para aquellos que puedan venir después.

MikeSchinkel MikeSchinkel
11 oct 2010 23:12:22

¿Alguien sabe si hay una mejor solución ahora en 2016?

JasonDavis JasonDavis
7 jul 2016 08:59:47
Mostrar los 2 comentarios restantes
0

WordPress te permite añadir Meta a las Categorías usando un plugin:

Para hacer esto necesitas añadir una de las diversas extensiones que agrega meta a las categorías (imitando lo que las páginas obtienen por defecto), Simple Term Meta hace el trabajo muy bien.

Nota: Se necesita WordPress 3.x para extender las Categorías.

Después de eso puedes usar:

  • add_term_meta
  • update_term_meta
  • get_term_meta

Usa Functions.php para añadir métodos que hagan lo que quieras, por ejemplo:

add_action('category_add_form_fields', 'category_metabox_add', 10, 1);

function category_metabox_add($tag) { ?>
    <div class="form-field">
        <label for="image-url"><?php _e('URL de la imagen') ?></label>
        <input name="image-url" id="image-url" type="text" value="" size="40" aria-required="true" />
        <p class="description"><?php _e('Esta imagen será la miniatura mostrada en la página de la categoría.'); ?></p>
    </div>
<?php } 

add_action('created_category', 'save_category_metadata', 10, 1);

function save_category_metadata($term_id)
{
    if (isset($_POST['image-url'])) 
        update_term_meta( $term_id, 'image-url', $_POST['image-url']);                  
}

Llamar a los nuevos campos en los temas es fácil:

<?php echo get_term_meta(get_query_var('cat'), 'image-url', true); ?>

Más detalles y ejemplos: http://www.wphub.com/adding-metadata-taxonomy-terms/

14 sept 2013 17:27:02