single - {$ post_type} - {slug} .php para tipos de publicaciones personalizadas

19

Mi parte favorita de Wordpress jerarquía de plantillas es la capacidad de crear rápidamente archivos de plantilla para páginas por babosa, sin tener que editar la página en Wordpress para seleccionar una plantilla.

Actualmente podemos hacer esto:

  

page- {slug} .php

Pero me gustaría poder hacer esto:

  

single- {post_type} - {slug} .php

De modo que, por ejemplo, en un tipo de publicación llamado review , podría hacer una plantilla para una publicación llamada "Mi gran revisión" en single-review-my-great-review.php

¿Alguien ha configurado esto antes? single-{post_type}-{slug}.php

    
pregunta supertrue 02.02.2012 - 17:36

6 respuestas

18

A) La base en el núcleo

Como puede ver en la explicación de Jerarquía de plantillas del Códice , single-{$post_type}.php ya está soportado.

B) Extendiendo la jerarquía central

Ahora, con mucho gusto, hay algunos filtros y enlaces dentro de /wp-includes/template-loader.php .

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • Y: un filtro específico dentro de get_query_template( $type, ... ) llamado: "$type}_template"

B.1) Cómo funciona

  1. Dentro del archivo del cargador de plantillas, la plantilla se carga con una consulta var / wp_query conditional: is_*() .
  2. Los condicionales entonces se activan (en caso de una plantilla "única"): is_single() && $template = get_single_template()
  3. Esto dispara entonces get_query_template( $type, $templates ) , donde $type es single
  4. Luego tenemos el filtro "{$type}_template"

C) La solución

Como solo queremos extender la jerarquía con una plantilla que se cargue antes de la plantilla "single-{$object->post_type}.php" real, interceptaremos la jerarquía y agregaremos una nueva plantilla al principio de la matriz de plantillas.

// Extend the hierarchy
function add_posttype_slug_template( $templates )
{

    $object = get_queried_object();

    // New 
    $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
    // Like in core
    $templates[] = "single-{$object->post_type}.php";
    $templates[] = "single.php";

    return locate_template( $templates );    
}
// Now we add the filter to the appropriate hook
function intercept_template_hierarchy()
{
    add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
}
add_action( 'template_redirect', 'intercept_template_hierarchy', 20 );

NOTA: (Si quieres usar algo diferente a la barra de objetos predeterminada) Tendrás que ajustar $slug de acuerdo con tu estructura de permalink. Solo usa lo que necesites del (object) $post global.

Entradas Trac

Como actualmente el enfoque anterior no es no (solo puede filtrar la ruta de acceso absoluta ubicada de esta manera), aquí hay una lista de boletos de trac:

respondido por el kaiser 02.02.2012 - 18:25
3

Siguiendo la imagen de Jerarquía de plantillas , no veo tal opción.

Así que aquí está cómo lo haría:

Solución 1 (la mejor en mi opinión)

Cree un archivo de plantilla y asócielo a la revisión

 <?php
 /*
 Template Name: My Great Review
 */
 ?>

Al agregar el archivo de plantilla php a tu directorio de temas, aparecerá como una opción de plantilla en la página de edición de tu publicación.

Solución 2

Esto probablemente podría lograrse usando template_redirect hook.

En el archivo functions.php:

 function my_redirect()
 {
      global $post;

      if( get_post_type( $post ) == "my_cpt" && is_single() )
      {
           if( file_exists( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' ) )
           {
                include( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' );
                exit;
           }
      }
 }
 add_action( 'template_redirect', 'my_redirect' );

EDIT

Se agregó file_exists check

    
respondido por el Shane 02.02.2012 - 18:06
2

La respuesta principal (de hace 4 años) ya no funciona, pero el códice de WordPress tiene la solución aquí :

<?php
function add_posttype_slug_template( $single_template )
{
    $object = get_queried_object();
    $single_postType_postName_template = locate_template("single-{$object->post_type}-{$object->post_name}.php");
    if( file_exists( $single_postType_postName_template ) )
    {
        return $single_postType_postName_template;
    } else {
        return $single_template;
    }
}
add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
?>
    
respondido por el skladany 09.06.2016 - 22:39
1

Usar plantillas de página

Otro enfoque para la escalabilidad sería duplicar la funcionalidad desplegable de la plantilla de página en el tipo de publicación page para su tipo de publicación personalizada.

Código reutilizable

La duplicación en el código no es una buena práctica. Las horas extraordinarias pueden causar una gran hinchazón en una base de código, lo que dificulta la administración del desarrollador. En lugar de crear una plantilla para cada slug, lo más probable es que necesites una plantilla de uno a varios que pueda reutilizarse en lugar de una plantilla de uno a uno.

El Código

# Define your custom post type string
define('MY_CUSTOM_POST_TYPE', 'my-cpt');

/**
 * Register the meta box
 */
add_action('add_meta_boxes', 'page_templates_dropdown_metabox');
function page_templates_dropdown_metabox(){
    add_meta_box(
        MY_CUSTOM_POST_TYPE.'-page-template',
        __('Template', 'rainbow'),
        'render_page_template_dropdown_metabox',
        MY_CUSTOM_POST_TYPE,
        'side', #I prefer placement under the post actions meta box
        'low'
    );
}

/**
 * Render your metabox - This code is similar to what is rendered on the page post type
 * @return void
 */
function render_page_template_dropdown_metabox(){
    global $post;
    $template = get_post_meta($post->ID, '_wp_page_template', true);
    echo "
        <label class='screen-reader-text' for='page_template'>Page Template</label>
            <select name='_wp_page_template' id='page_template'>
            <option value='default'>Default Template</option>";
            page_template_dropdown($template);
    echo "</select>";
}

/**
 * Save the page template
 * @return void
 */
function save_page_template($post_id){

    # Skip the auto saves
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    elseif ( defined( 'DOING_AJAX' ) && DOING_AJAX )
        return;
    elseif ( defined( 'DOING_CRON' ) && DOING_CRON )
        return;

    # Only update the page template meta if we are on our specific post type
    elseif(MY_CUSTOM_POST_TYPE === $_POST['post_type'])
        update_post_meta($post_id, '_wp_page_template', esc_attr($_POST['_wp_page_template']));
}
add_action('save_post', 'save_page_template');


/**
 * Set the page template
 * @param string $template The determined template from the WordPress brain
 * @return string $template Full path to predefined or custom page template
 */
function set_page_template($template){
    global $post;
    if(MY_CUSTOM_POST_TYPE === $post->post_type){
        $custom_template = get_post_meta($post->ID, '_wp_page_template', true);
        if($custom_template)
            #since our dropdown only gives the basename, use the locate_template() function to easily find the full path
            return locate_template($custom_template);
    }
    return $template;
}
add_filter('single_template', 'set_page_template');

Esta es una respuesta un poco tardía, pero pensé que sería valiosa ya que nadie en la web ha documentado este enfoque por lo que puedo decir. Espero que esto ayude a alguien.

    
respondido por el Brian Fegter 13.10.2012 - 08:29
1

En mi caso, tengo tipos de publicaciones personalizadas Álbum y Seguimiento vinculados por una taxonomía de Álbum. Quería poder usar diferentes plantillas individuales para las publicaciones de Álbum y Seguimiento dependiendo de su taxonomía de Álbum.

Sobre la base de la respuesta de Kaiser, escribí este código. Funciona bien.
Nota. No necesitaba el add_action ().

// Add an additional template option to the template hierarchy
add_filter( 'single_template', 'add_albumtrack_taxslug_template', 10, 1 );
function add_albumtrack_taxslug_template( $orig_template_path )
{
    // at this point, $orig_template_path is an absolute located path to the preferred single template.

    $object = get_queried_object();

    if ( ! (
        // specify another template option only for Album and Track post types.
        in_array( $object->post_type, array( 'gregory-cpt-album','gregory-cpt-track' )) &&
        // check that the Album taxonomy has been registered.
        taxonomy_exists( 'gregory-tax-album' ) &&
        // get the Album taxonomy term for the current post.
        $album_tax = wp_get_object_terms( $object->ID, 'gregory-tax-album' )
        ))
        return $orig_template_path;

    // assemble template name
    // assumption: only one Album taxonomy term per post. we use the first object in the array.
    $template = "single-{$object->post_type}-{$album_tax[0]->slug}.php";
    $template = locate_template( $template );
    return ( !empty( $template ) ? $template : $orig_template_path );
}

Ahora puedo crear plantillas llamadas single-gregory-cpt-track-tax-serendipity.php y single-gregory-cpt-album-tax-serendipity.php y WP las usará automáticamente; 'tax-serendipity' es la babosa para el primer término de taxonomía del Álbum.

como referencia, el gancho de filtro 'single_template' se declara en:
/wp-includes/theme.php: get_query_template()

Gracias Kaiser por el código de muestra.

Saludos, Gregory

    
respondido por el Gregory 18.04.2012 - 08:46
0

Actualización del código de Brians, descubrí que cuando no se usaba el cuadro desplegable, la opción de plantilla "predeterminada" se guardaba en wp_page_template, lo que provocó que intentara encontrar una plantilla llamada predeterminada. este cambio solo busca la opción "predeterminada" al guardar y elimina el meta de publicación en su lugar (útil si cambió la opción de la plantilla a la predeterminada)

elseif(MY_CUSTOM_POST_TYPE === $_POST['post_type']) {

if ( esc_attr($_POST['_wp_page_template']) === "default" ) :
    delete_post_meta($post_id, '_wp_page_template');
else :
    update_post_meta($post_id, '_wp_page_template', esc_attr($_POST['_wp_page_template']));
endif;
}
    
respondido por el Mark 29.05.2014 - 20:20