web-dev-qa-db-fra.com

Comment contrôler la sortie d'un type d'article personnalisé sans modifier le thème?

J'ai un type de publication personnalisé 'propriétés' pour lequel j'aimerais contrôler la sortie HTML. Pour plus de simplicité, concentrons-nous sur la vue archive .

Comme exemple de base, voici à quoi ressemble une boucle dans un fichier archive.php:

<?php while ( have_posts() ) : the_post(); ?>
    <h2><?php the_title(); ?></h2>
    <div><?php the_content(); ?></div>
<?php endwhile; ?>

J'aimerais pouvoir modifier la sortie de la boucle avec mes propriétés personnalisées HTML sans ajouter de nouveau modèle ni utiliser de code abrégé - sans intervention de l'utilisateur. Pour être clair, j'aimerais remplacer les <h2> et <div> dans l'exemple ci-dessus, et rien avant/après.

Remarque: Ce qui précède n'est qu'un exemple. Je voudrais contrôler la sortie de la boucle quel que soit le thème .

En ce moment, j'utilise la mise en tampon de sortie pour capturer la sortie de loop_start à loop_end et la remplacer par la mienne, mais cela peut potentiellement créer des conflits avec d'autres plugins.

Existe-t-il un moyen accepté/meilleur de procéder?

5
Andy Adams

Il y a deux tableaux d’action-référence très souvent oubliés: loop_start/_end().

Activez simplement la mise en mémoire tampon de sortie et vous êtes prêt.

add_action( 'loop_start', 'wpse75307_plugin_loop' );
add_action( 'loop_end', 'wpse75307_plugin_loop' );
/**
 * Callback function triggered during:
 * + 'loop_start'/`have_posts()` after the last post gets rendered
 * + 'loop_end'/`the_post()` before the 1st post gets rendered
 * @param  object \WP_Query Passed by reference
 * @return 
 */
function wpse75307_plugin_loop( &$obj )
{
    # if ( is_main_query() )
    # DO STUFF ... OR DONT
    global $post;

    // Start output buffering at the beginning of the loop and abort
    if ( 'loop_start' === current_filter() )
        return ob_start();

    // At the end of the loop, we end the buffering and save into a var
    # if ( is_main_query() )
    # DO STUFF ... OR DONT
    $loop_content = ob_get_flush();

    // You can do something with $loop_content...
    // Add your own loop, or...
    // Whatever you can imagine
}

Remarque: je ne le ferais pas comme cela, mais comme vous l'avez dit, vous voulez exactement ce niveau de priorité, voilà.

4
kaiser

Vous pouvez changer la boucle via hook, comme ceci pour cpt 'my_post_type'

// $this? - example was used in class-structures
// add custom post type to wp loop
add_filter( 'pre_get_posts', array( $this, 'add_to_query') );

// ads to query
function add_to_query( $query ) {

    if ( is_admin() || is_preview() )
        return;

    if ( ! isset( $query -> query_vars['suppress_filters'] ) )
        $query -> query_vars['suppress_filters'] = FALSE;

    // conditional tags for restrictions
    if ( is_home() || is_front_page() && ( FALSE == $query -> query_vars['suppress_filters'] ) ) 
        $query->set( 'post_type', array( 'post', 'my_post_type' ) );

    return $query;
}
0
bueltge

J'ai également essayé de trouver une solution à ce problème: j'ai un plugin avec des types de publication personnalisés. Ces types de publication personnalisés nécessitent une archive personnalisée, mais la création d'un fichier de modèle spécifique signifie que cela ne fonctionnerait pas avec tous les thèmes.

L’alternative la plus proche que je connaisse qui n’a pas été mentionnée ci-dessus est de lire le fichier archive/index.php lors de l’activation du plugin (et du changement de thème) et de copier le fichier archive.php dans votre dossier de plugin avec le nom correspondant, être spécifique à votre type de message personnalisé.

Ensuite, demandez à votre plugin de modifier automatiquement le fichier de modèle personnalisé pour injecter votre propre code de boucle.

<?php while (have_posts()) : the_post(); ?>     
    <?php if(is_search()): ?>
        <?php get_template_part( 'includes/loop' , 'search'); ?>
    <?php else: ?>
        <?php get_template_part( 'includes/loop' , 'index'); ?>
    <?php endif; ?>
<?php endwhile; ?>

par exemple. Dans le petit extrait ci-dessus d'un fichier index.php, recherchez la ligne while (have_posts () ...) et la ligne correspondante et remplacez tout le reste par votre code HTML en boucle personnalisé.

Je n'ai pas essayé cela, c'est juste une autre solution potentielle et j'apprécierais les commentaires si quelqu'un d'autre a utilisé cette approche.

0
Dave Hilditch

Si je me souviens bien, j’ai dérivé cette technique d’ici: Utilisez template_include avec des types de publication personnalisés .

Nous utilisons un plugin qui générera un "Modèle virtuel" pour un type de publication donné. Le filtre template_include rendra un fichier de modèle qui réside dans le dossier du plugin.

Vous devez affiner la fonction custom_template et le fichier modèle en fonction de vos besoins. J'espère que cela t'aides ;)


Fichier plugin

ajustez le nom post_type dans l'instanciation de la classe

<?php
! defined( 'ABSPATH' ) AND exit;
/*
Plugin Name: Virtual Template for CPT
Plugin URI: https://wordpress.stackexchange.com/q/75307/12615
Description: Use the plugin's template file to render an outsider loop.
Author: brasofilo
Author URI: https://wordpress.stackexchange.com/users/12615/brasofilo
Version: 2012.12.11
License: GPLv2
*/

$virtual_template = new VirtualTemplateForCPT_class( 'movies' );

class VirtualTemplateForCPT_class
{   
    private $pt;
    private $url;
    private $path;

    /**
     * Construct 
     *
     * @return void
     **/
    public function __construct( $pt )
    {       
        $this->pt = $pt;
        $this->url = plugins_url( '', __FILE__ );
        $this->path = plugin_dir_path( __FILE__ );
        add_action( 'init', array( $this, 'init_all' ) );
    }


    /**
     * Dispatch general hooks
     *
     * @return void
     **/
    public function init_all() 
    {
        add_action( 'wp_enqueue_scripts',   array( $this, 'frontend_enqueue' ) );
        add_filter( 'body_class',           array( $this, 'add_body_class' ) );
        add_filter( 'template_include',     array( $this, 'custom_template' ) );
    }

    /**
     * Use for custom frontend enqueues of scripts and styles
     * http://codex.wordpress.org/Plugin_API/Action_Reference/wp_enqueue_scripts
     *
     * @return void
     **/
    public function frontend_enqueue() 
    {
        global $post;
        if( $this->pt != get_post_type( $post->ID ) )
            return;         
    }

    /**
     * Add custom class to body tag
     * http://codex.wordpress.org/Function_Reference/body_class
     *
     * @param array $classes
     * @return array
     **/
    public function add_body_class( $classes ) 
    {
        global $post;
        if( $this->pt != get_post_type( $post->ID ) )
            return $classes;

        $classes[] = $this->pt . '-body-class';
        return $classes;
    }

    /**
     * Use the plugin template file to display the CPT
     * http://codex.wordpress.org/Conditional_Tags
     *
     * @param string $template
     * @return string
     **/
    public function custom_template( $template ) 
    {
        $post_types = array( $this->pt );
        $theme = wp_get_theme();

        if ( is_post_type_archive( $post_types ) )
            $template = $this->path . '/single-virtual-cpt.php';

        if ( is_singular( $post_types ) )
            $template = $this->path . '/single-virtual-cpt.php';

        return $template;
    }

}

Fichier modèle

single-virtual-cpt.php
_ {placé dans le même dossier que le fichier du plugin} _

<?php
/**
 * A custom -not from the theme- template
 *
 * @package WordPress
 * @subpackage Virtual_Template
 */

get_header(); 

while ( have_posts() ) : the_post(); $theID = $post->ID; 
    _e('This is a virtual template for the post:<br />');
    the_title();
endwhile; 
get_footer(); 

?>
</body>
</html>

Résultat

 virtual template in frontend 
cliquez pour agrandir

0
brasofilo