single - {$ post_type} - {slug} .php para tipos de post personalizado

19

Minha parte favorita da hierarquia de modelos do Wordpress é a capacidade de criar rapidamente arquivos de modelo para páginas por slug, sem precisar editar a página no Wordpress para selecionar um modelo.

Atualmente, podemos fazer isso:

  

page- {slug} .php

Mas eu gostaria de poder fazer isso:

  

single- {post_type} - {slug} .php

Para que, por exemplo, em um tipo de post chamado review , eu poderia criar um modelo para uma postagem chamada "Minha ótima revisão" em single-review-my-great-review.php

Alguém já configurou isso antes? single-{post_type}-{slug}.php

    
por supertrue 02.02.2012 / 17:36

6 respostas

18

A) A base no núcleo

Como você pode ver na explicação da hierarquia de modelos do Codex , single-{$post_type}.php já é suportado.

B) Estendendo a Hierarquia principal

Agora, temos alguns filtros e ganchos dentro de /wp-includes/template-loader.php .

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

B.1) Como funciona

  1. Dentro do arquivo do carregador de modelos, o modelo é carregado por uma consulta var / wp_query condicional: is_*() .
  2. A condicional então dispara (no caso de um modelo "único"): is_single() && $template = get_single_template()
  3. Isso aciona, em seguida, get_query_template( $type, $templates ) , em que $type é single
  4. Então, temos o filtro "{$type}_template"

C) A solução

Como nós apenas queremos estender a hierarquia com um modelo que seja carregado antes do modelo "single-{$object->post_type}.php" real, interceptaremos a hierarquia e adicionaremos um novo modelo para o início da matriz de modelos.

// 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: (Se você quiser usar algo diferente do slug de objetos padrão) Você terá que ajustar $slug de acordo com a sua estrutura de permalink. Basta usar o que você precisa do global (object) $post .

Ingressos Trac

Como a abordagem acima é atualmente não suportada (você só pode filtrar o caminho localizado absoluto dessa forma), aqui está uma lista de tickets trac:

por kaiser 02.02.2012 / 18:25
3

Seguindo a imagem da Hierarquia de modelos , não vejo essa opção.

Então é assim que eu vou fazer isso:

Solução 1 (na minha opinião)

Crie um arquivo de modelo e associe-o à revisão

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

Adicionando o arquivo php do template no diretório do seu tema, ele aparecerá como uma opção de modelo na página de edição do seu post.

Solução 2

Isso provavelmente poderia ser alcançado usando template_redirect hook.

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

EDITAR

Adicionada file_exists check

    
por Shane 02.02.2012 / 18:06
2

A resposta principal (de 4 anos atrás) não funciona mais, mas o codex do WordPress tem a solução aqui :

<?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 );
?>
    
por skladany 09.06.2016 / 22:39
1

Use modelos de páginas

Outra abordagem para escalabilidade seria duplicar a funcionalidade suspensa do modelo de página no tipo de post page para seu tipo de postagem personalizado.

Código Reutilizável

Duplicação no código não é uma boa prática. As horas extras podem causar inchaço grave em uma base de código quando isso dificulta o gerenciamento de um desenvolvedor. Em vez de criar um modelo para cada slug, provavelmente você precisará de um modelo de um para muitos que possa ser reutilizado, em vez de um para um, post-to-template.

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

Essa é uma resposta tardia, mas achei que seria valiosa, pois ninguém na web documentou essa abordagem até onde eu sei. Espero que isso ajude alguém.

    
por Brian Fegter 13.10.2012 / 08:29
1

No meu caso, tenho os tipos de postagem personalizada de álbuns e faixas vinculados por uma taxonomia de álbuns. Eu queria poder usar modelos únicos diferentes para as publicações de álbuns e faixas, dependendo da taxonomia do álbum.

Com base na resposta da Kaiser acima, eu escrevi este código. Isso funciona bem. Nota. Eu não precisei do 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 );
}

Agora posso criar modelos nomeados single-gregory-cpt-track-tax-serendipity.php e single-gregory-cpt-album-tax-serendipity.php e o WP os usará automaticamente; 'tax-serendipity' é o slug do primeiro termo de taxonomia do Álbum.

para referência, o gancho de filtro 'single_template' é declarado em:
/wp-includes/theme.php: get_query_template()

Obrigado ao Kaiser pelo código de exemplo.

Felicidades, Gregory

    
por Gregory 18.04.2012 / 08:46
0

Atualização do código Brians, descobri que quando a caixa suspensa não estava sendo usada, a opção de modelo "padrão" estava sendo salva em wp_page_template, o que fazia com que tentasse encontrar um modelo chamado default. esta mudança apenas verifica a opção "default" ao salvar e exclui o post meta em vez disso (útil se você alterou a opção de modelo de volta ao padrão)

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;
}
    
por Mark 29.05.2014 / 20:20