J'ai fait des recherches assez approfondies sur la façon d'utiliser pre_get_posts
sur les pages vraies et les pages de garde statiques, et il semble qu'il n'y ait pas de méthode infaillible.
La meilleure option que j'ai trouvée à ce jour était celle d'un post réalisé par @birgire sur Stackoverflow . Je l'ai réécrit dans une classe de démonstration et rendu le code un peu plus dynamique
class PreGeTPostsForPages
{
/**
* @var string|int $pageID
* @access protected
* @since 1.0.0
*/
protected $pageID;
/**
* @var bool $injectPageIntoLoop
* @access protected
* @since 1.0.0
*/
protected $injectPageIntoLoop;
/**
* @var array $args
* @access protected
* @since 1.0.0
*/
protected $args;
/**
* @var int $validatedPageID
* @access protected
* @since 1.0.0
*/
protected $validatedPageID = 0;
/**
* Constructor
*
* @param string|int $pageID = NULL
* @param bool $injectPageIntoLoop = false
* @param array| $args = []
* @since 1.0.0
*/
public function __construct(
$pageID = NULL,
$injectPageIntoLoop = true,
$args = []
) {
$this->pageID = $pageID;
$this->injectPageIntoLoop = $injectPageIntoLoop;
$this->args = $args;
}
/**
* Private method validatePageID()
*
* Validates the page ID passed
*
* @since 1.0.0
*/
private function validatePageID()
{
$validatedPageID = filter_var( $this->pageID, FILTER_VALIDATE_INT );
$this->validatedPageID = $validatedPageID;
}
/**
* Public method init()
*
* This method is used to initialize our pre_get_posts action
*
* @since 1.0.0
*/
public function init()
{
// Load the correct actions according to the value of $this->keepPageIntegrity
add_action( 'pre_get_posts', [$this, 'preGetPosts'] );
}
/**
* Protected method pageObject()
*
* Gets the queried object to use that as page object
*
* @since 1.0.0
*/
protected function pageObject()
{
global $wp_the_query;
return $wp_the_query->get_queried_object();
}
/**
* Public method preGetPosts()
*
* This is our call back method for the pre_get_posts action.
*
* The pre_get_posts action will only be used if the page integrity is
* not an issue, which means that the page will be altered to work like a
* normal archive page. Here you have the option to inject the page object as
* first post through the_posts filter when $this->injectPageIntoLoop === true
*
* @since 1.0.0
*/
public function preGetPosts( \WP_Query $q )
{
// Make sure that we are on the main query and the desired page
if ( is_admin() // Only run this on the front end
|| !$q->is_main_query() // Only target the main query
|| !is_page( $this->validatedPageID ) // Run this only on the page specified
)
return;
// Remove the filter to avoid infinte loops
remove_filter( current_filter(), [$this, __METHOD__] );
// METHODS:
$this->validatePageID();
$this->pageObject();
$queryArgs = $this->args;
// Set default arguments which cannot be changed
$queryArgs['pagename'] = NULL;
// We have reached this point, lets do what we need to do
foreach ( $queryArgs as $key=>$value )
$q->set(
filter_var( $key, FILTER_SANITIZE_STRING ),
$value // Let WP_Query handle the sanitation of the values accordingly
);
// Set $q->is_singular to 0 to get pagination to work
$q->is_singular = false;
// FILTERS:
add_filter( 'the_posts', [$this, 'addPageAsPost'], PHP_INT_MAX );
add_filter( 'template_include', [$this, 'templateInclude'], PHP_INT_MAX );
}
/**
* Public callback method hooked to 'the_posts' filter
* This will inject the queried object into the array of posts
* if $this->injectPageIntoLoop === true
*
* @since 1.0.0
*/
public function addPageAsPost( $posts )
{
// Inject the page object as a post if $this->injectPageIntoLoop == true
if ( true === $this->injectPageIntoLoop )
return array_merge( [$this->pageObject()], $posts );
return $posts;
}
/**
* Public call back method templateInclude() for the template_include filter
*
* @since 1.0.0
*/
public function templateInclude( $template )
{
// Remove the filter to avoid infinte loops
remove_filter( current_filter(), [$this, __METHOD__] );
// Get the page template saved in db
$pageTemplate = get_post_meta(
$this->validatedPageID,
'_wp_page_template',
true
);
// Make sure the template exists before we load it, but only if $template is not 'default'
if ( 'default' !== $pageTemplate ) {
$locateTemplate = locate_template( $pageTemplate );
if ( $locateTemplate )
return $template = $locateTemplate;
}
/**
* If $template returned 'default', or the template is not located for some reason,
* we need to get and load the template according to template hierarchy
*
* @uses get_page_template()
*/
return $template = get_page_template();
}
}
$init = new PreGeTPostsForPages(
251, // Page ID
false,
[
'posts_per_page' => 3,
'post_type' => 'post'
]
);
$init->init();
Cela fonctionne bien et page comme prévu en utilisant ma propre fonction de pagination .
En raison de la fonction, je perds l’intégrité de la page, ce qui encombrent d’autres fonctions en fonction de l’objet page stocké dans $post
. $post
avant que la boucle soit définie sur la première publication de la boucle et $post
sur la dernière publication de la boucle, après la boucle, comme prévu. Ce dont j'ai besoin, c'est que $post
est défini sur l'objet de la page en cours, c'est-à-dire l'objet interrogé.
De plus, $wp_the_query->post
et $wp_query->post
conservent la première publication de la boucle et non l'objet interrogé comme sur une page normale
J'utilise ce qui suit (en dehors de ma classe) pour vérifier mes globales avant et après la boucle
add_action( 'wp_head', 'printGlobals' );
add_action( 'wp_footer', 'printGlobals' );
function printGlobals()
{
$global_test = 'QUERIED OBJECT: ' . $GLOBALS['wp_the_query']->queried_object_id . '</br>';
$global_test .= 'WP_THE_QUERY: ' . $GLOBALS['wp_the_query']->post->ID . '</br>';
$global_test .= 'WP_QUERY: ' . $GLOBALS['wp_query']->post->ID . '</br>';
$global_test .= 'POST: ' . $GLOBALS['post']->ID . '</br>';
$global_test .= 'FOUND_POSTS: ' . $GLOBALS['wp_query']->found_posts . '</br>';
$global_test .= 'MAX_NUM_PAGES: ' . $GLOBALS['wp_query']->max_num_pages . '</br>';
?><pre><?php var_dump( $global_test ); ?></pre><?php
}
Avant la boucle, le problème est partiellement résolu en définissant $injectPageIntoLoop
sur true, qui injecte l'objet page en tant que première page de la boucle. Ceci est très utile si vous devez afficher les informations de la page avant les messages demandés, mais si vous ne le souhaitez pas, vous êtes foutu.
Je peux résoudre le problème avant la boucle en piratant directement les globals, ce que je n’aime pas vraiment. J'attache la méthode suivante à wp
dans ma méthode preGetPosts
public function wp()
{
$page = get_post( $this->pageID );
$GLOBALS['wp_the_query']->post = $page;
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
$GLOBALS['post'] = $page;
}
et dans la méthode preGetPosts
add_action( 'wp', [$this, 'wp'] );
À partir de là, $wp_the_query->post
, $wp_query->post
et $post
contiennent tous les objets de la page.
C'est là que réside mon gros problème, après la boucle. Après avoir piraté les globals via le hook et la méthode wp
,
$wp_the_query->post
et $wp_query->post
sont remis à la première publication de la boucle, comme prévu
$post
est défini sur le dernier message de la boucle.
Ce dont j'ai besoin, c'est que tous les trois soient redéfinis sur l'objet interrogé/l'objet de la page en cours.
J'ai essayé de relier la méthode wp
à loop_end
action, ce qui ne fonctionne pas. Accrocher la méthode wp
à l'action get_sidebar
fonctionne, mais il est trop tard.
add_action( 'get_sidebar', [$this, 'wp'] );
L'exécution de printGlobals()
immédiatement après la boucle dans le modèle confirme que $wp_the_query->post
et $wp_query->post
sont toujours définis sur le premier message et $post
sur le dernier message.
Je peux ajouter manuellement le code dans la méthode wp
après la boucle dans le modèle, mais l’idée n’est pas de modifier directement les fichiers du modèle, car la classe devrait pouvoir être transférée dans un plugin entre thèmes.
Existe-t-il un moyen approprié de résoudre ce problème en exécutant pre_get_posts
sur une page réelle et une page de garde statique tout en conservant l’intégrité de $wp_the_query->post
, $wp_query->post
et $post
(ayant ceux définis sur l’objet demandé) avant et après la boucle.
Il semble y avoir une confusion sur ce dont j'ai besoin et pourquoi j'en ai besoin
Ce dont j'ai besoin
Je dois conserver les valeurs de $wp_the_query->post
, $wp_query->post
et $post
quel que soit le modèle, et cette valeur doit être l'objet interrogé. A ce stade, avec le code que j'ai posté, les valeurs de ces trois variables ne tiennent pas l'objet page, mais plutôt les objets post de la boucle. J'espère que c'est assez clair.
J'ai posté un code que vous pouvez utiliser pour tester ces variables
Pourquoi j'en ai besoin
J'ai besoin d'un moyen fiable pour ajouter des publications via pre_get_posts
aux modèles de page et aux pages de garde statiques sans modifier les fonctionnalités de la page complète. À ce stade, en l'état actuel du code, il coupe ma fonction de fil d'Ariane et la fonction de page associée après la boucle en raison de $post
qui contient le "mauvais" objet de publication.
Surtout, je ne veux pas modifier directement les modèles de page. Je veux pouvoir ajouter des publications à un modèle de page sansAUCUNE MODIFICATIONdu modèle
Je l'ai finalement fait fonctionner, mais pas avec le code dans ma question. J'ai totalement abandonné cette idée et recommencé dans une nouvelle direction.
Si quelqu'un est capable de résoudre les problèmes de ma question, n'hésitez pas à poster une réponse. De plus, si vous avez d'autres solutions, n'hésitez pas à poster une réponse.
Ce que j’ai essayé de faire ici, c’est d’utiliser post-injection, plutôt que de modifier complètement la requête principale et de rester bloqué sur tous les problèmes ci-dessus, y compris (a) modifier directement les paramètres globaux, réaffecter des modèles de page.
En utilisant la post-injection, je suis capable de conserver une intégrité post-complète. Ainsi, $wp_the_query->post
, $wp_query->post
, $posts
et $post
restent constants dans tout le modèle. Chacune de ces variables fait référence à l'objet de la page en cours (comme c'est le cas avec les pages vraies). De cette façon, les fonctions comme le fil d'Ariane savent que la page en cours est une vraie page et non une sorte d'archive.
Je devais modifier légèrement la requête principale (à travers des filtres et des actions) pour ajuster la pagination, mais nous y arriverons.
Afin de réaliser la post-injection, j'ai utilisé une requête personnalisée pour renvoyer les messages nécessaires à l'injection. J'ai également utilisé la propriété $found_pages
de la requête personnalisée pour ajuster celle de la requête principale afin que la pagination fonctionne à partir de la requête principale. Les messages sont injectés dans la requête principale via l'action loop_end
.
Afin de rendre la requête personnalisée accessible et utilisable en dehors de la classe, j'ai introduit quelques actions.
Crochets de pagination pour accrocher les fonctions de pagination:
pregetgostsforgages_before_loop_pagination
pregetgostsforgages_after_loop_pagination
Compteur personnalisé qui compte les posts dans la boucle. Ces actions peuvent être utilisées pour modifier le mode d'affichage des publications dans la boucle en fonction du numéro de publication.
pregetgostsforgages_counter_before_template_part
pregetgostsforgages_counter_after_template_part
Crochet général pour accéder à l'objet de requête et à l'objet de publication en cours
pregetgostsforgages_current_post_and_object
Ces crochets vous offrent une expérience totale de manipulation, étant donné que vous n'avez rien à changer dans le modèle de page lui-même, ce qui était mon intention initiale depuis le début. Une page peut être complètement modifiée à partir d'un plugin ou d'un fichier de fonction, ce qui rend cette solution très dynamique.
J'ai également utilisé get_template_part()
afin de charger un modèle, qui sera utilisé pour afficher les publications. Aujourd'hui, la plupart des thèmes utilisent des modèles, ce qui est très utile en classe. Si votre thème utilise content.php
, vous pouvez simplement passer content
à $templatePart
pour charger content.php
.
Si vous avez besoin d'une prise en charge post-format pour les parties de modèle, c'est simple: vous pouvez simplement passer content
à $templatePart
et définir $postFormatSupport
à true
. Par conséquent, la partie de modèle content-video.php
sera chargée pour une publication au format de publication video
.
Les modifications suivantes ont été apportées à la requête principale via les filtres et actions respectifs:
Afin de paginer la requête principale:
La valeur de la propriété $found_posts
de la requête d'injecteur est transmise à celle de l'objet de requête principal via le filtre found_posts
.
La valeur du paramètre utilisateur passé posts_per_page
est définie pour la requête principale via pre_get_posts
.
$max_num_pages
est calculé en utilisant le nombre de publications dans $found_posts
et posts_per_page
. Étant donné que is_singular
est vrai sur les pages, il empêche la clause LIMIT
d'être définie. Définir simplement is_singular
sur false a posé quelques problèmes. J'ai donc décidé de définir la clause LIMIT
via le filtre post_limits
. J'ai gardé la offset
de la clause LIMIT
définie sur 0
pour éviter les 404 sur les pages avec la pagination activée.
Cela prend en charge la pagination et tout problème pouvant découler de la post-injection.
L'objet de page en cours peut être affiché sous forme de publication en utilisant la boucle par défaut de la page, séparée et placée au-dessus des publications injectées. Si vous n'en avez pas besoin, vous pouvez simplement définir $removePageFromLoop
sur true, ce qui empêchera le contenu de la page d'être affiché.
À ce stade, j'utilise CSS pour masquer l'objet de la page via les actions loop_start
et loop_end
, car je ne trouve pas d'autre moyen de le faire. L'inconvénient de cette méthode est que tout élément lié à un crochet d'action the_post
dans la requête principale sera également masqué.
La classe PreGetPostsForPages
peut être améliorée et doit également être correctement nommée. Bien que vous puissiez simplement le déposer dans le fichier de fonctions de votre thème, il serait préférable de le déposer dans un plugin personnalisé.
Utilisez, modifiez et abusez comme bon vous semble. Le code est bien commenté, il devrait donc être facile à suivre et à ajuster
class PreGetPostsForPages
{
/**
* @var string|int $pageID
* @access protected
* @since 1.0.0
*/
protected $pageID;
/**
* @var string $templatePart
* @access protected
* @since 1.0.0
*/
protected $templatePart;
/**
* @var bool $postFormatSupport
* @access protected
* @since 1.0.0
*/
protected $postFormatSupport;
/**
* @var bool $removePageFromLoop
* @access protected
* @since 1.0.0
*/
protected $removePageFromLoop;
/**
* @var array $args
* @access protected
* @since 1.0.0
*/
protected $args;
/**
* @var array $mergedArgs
* @access protected
* @since 1.0.0
*/
protected $mergedArgs = [];
/**
* @var NULL|\stdClass $injectorQuery
* @access protected
* @since 1.0.0
*/
protected $injectorQuery = NULL;
/**
* @var int $validatedPageID
* @access protected
* @since 1.0.0
*/
protected $validatedPageID = 0;
/**
* Constructor method
*
* @param string|int $pageID The ID of the page we would like to target
* @param string $templatePart The template part which should be used to display posts
* @param string $postFormatSupport Should get_template_part support post format specific template parts
* @param bool $removePageFromLoop Should the page content be displayed or not
* @param array $args An array of valid arguments compatible with WP_Query
*
* @since 1.0.0
*/
public function __construct(
$pageID = NULL,
$templatePart = NULL,
$postFormatSupport = false,
$removePageFromLoop = false,
$args = []
) {
$this->pageID = $pageID;
$this->templatePart = $templatePart;
$this->postFormatSupport = $postFormatSupport;
$this->removePageFromLoop = $removePageFromLoop;
$this->args = $args;
}
/**
* Public method init()
*
* The init method will be use to initialize our pre_get_posts action
*
* @since 1.0.0
*/
public function init()
{
// Initialise our pre_get_posts action
add_action( 'pre_get_posts', [$this, 'preGetPosts'] );
}
/**
* Private method validatePageID()
*
* Validates the page ID passed
*
* @since 1.0.0
*/
private function validatePageID()
{
$validatedPageID = filter_var( $this->pageID, FILTER_VALIDATE_INT );
$this->validatedPageID = $validatedPageID;
}
/**
* Private method mergedArgs()
*
* Merge the default args with the user passed args
*
* @since 1.0.0
*/
private function mergedArgs()
{
// Set default arguments
if ( get_query_var( 'paged' ) ) {
$currentPage = get_query_var( 'paged' );
} elseif ( get_query_var( 'page' ) ) {
$currentPage = get_query_var( 'page' );
} else {
$currentPage = 1;
}
$default = [
'suppress_filters' => true,
'ignore_sticky_posts' => 1,
'paged' => $currentPage,
'posts_per_page' => get_option( 'posts_per_page' ), // Set posts per page here to set the LIMIT clause etc
'nopaging' => false
];
$mergedArgs = wp_parse_args( (array) $this->args, $default );
$this->mergedArgs = $mergedArgs;
}
/**
* Public method preGetPosts()
*
* This is the callback method which will be hooked to the
* pre_get_posts action hook. This method will be used to alter
* the main query on the page specified by ID.
*
* @param \stdClass WP_Query The query object passed by reference
* @since 1.0.0
*/
public function preGetPosts( \WP_Query $q )
{
if ( !is_admin() // Only target the front end
&& $q->is_main_query() // Only target the main query
&& $q->is_page( filter_var( $this->validatedPageID, FILTER_VALIDATE_INT ) ) // Only target our specified page
) {
// Remove the pre_get_posts action to avoid unexpected issues
remove_action( current_action(), [$this, __METHOD__] );
// METHODS:
// Initialize our method which will return the validated page ID
$this->validatePageID();
// Initiale our mergedArgs() method
$this->mergedArgs();
// Initiale our custom query method
$this->injectorQuery();
/**
* We need to alter a couple of things here in order for this to work
* - Set posts_per_page to the user set value in order for the query to
* to properly calculate the $max_num_pages property for pagination
* - Set the $found_posts property of the main query to the $found_posts
* property of our custom query we will be using to inject posts
* - Set the LIMIT clause to the SQL query. By default, on pages, `is_singular`
* returns true on pages which removes the LIMIT clause from the SQL query.
* We need the LIMIT clause because an empty limit clause inhibits the calculation
* of the $max_num_pages property which we need for pagination
*/
if ( $this->mergedArgs['posts_per_page']
&& true !== $this->mergedArgs['nopaging']
) {
$q->set( 'posts_per_page', $this->mergedArgs['posts_per_page'] );
} elseif ( true === $this->mergedArgs['nopaging'] ) {
$q->set( 'posts_per_page', -1 );
}
// FILTERS:
add_filter( 'found_posts', [$this, 'foundPosts'], PHP_INT_MAX, 2 );
add_filter( 'post_limits', [$this, 'postLimits']);
// ACTIONS:
/**
* We can now add all our actions that we will be using to inject our custom
* posts into the main query. We will not be altering the main query or the
* main query's $posts property as we would like to keep full integrity of the
* $post, $posts globals as well as $wp_query->post. For this reason we will use
* post injection
*/
add_action( 'loop_start', [$this, 'loopStart'], 1 );
add_action( 'loop_end', [$this, 'loopEnd'], 1 );
}
}
/**
* Public method injectorQuery
*
* This will be the method which will handle our custom
* query which will be used to
* - return the posts that should be injected into the main
* query according to the arguments passed
* - alter the $found_posts property of the main query to make
* pagination work
*
* @link https://codex.wordpress.org/Class_Reference/WP_Query
* @since 1.0.0
* @return \stdClass $this->injectorQuery
*/
public function injectorQuery()
{
//Define our custom query
$injectorQuery = new \WP_Query( $this->mergedArgs );
// Update the thumbnail cache
update_post_thumbnail_cache( $injectorQuery );
$this->injectorQuery = $injectorQuery;
return $this->injectorQuery;
}
/**
* Public callback method foundPosts()
*
* We need to set found_posts in the main query to the $found_posts
* property of the custom query in order for the main query to correctly
* calculate $max_num_pages for pagination
*
* @param string $found_posts Passed by reference by the filter
* @param stdClass \WP_Query Sq The current query object passed by refence
* @since 1.0.0
* @return $found_posts
*/
public function foundPosts( $found_posts, \WP_Query $q )
{
if ( !$q->is_main_query() )
return $found_posts;
remove_filter( current_filter(), [$this, __METHOD__] );
// Make sure that $this->injectorQuery actually have a value and is not NULL
if ( $this->injectorQuery instanceof \WP_Query
&& 0 != $this->injectorQuery->found_posts
)
return $found_posts = $this->injectorQuery->found_posts;
return $found_posts;
}
/**
* Public callback method postLimits()
*
* We need to set the LIMIT clause as it it is removed on pages due to
* is_singular returning true. Witout the limit clause, $max_num_pages stays
* set 0 which avoids pagination.
*
* We will also leave the offset part of the LIMIT cluase to 0 to avoid paged
* pages returning 404's
*
* @param string $limits Passed by reference in the filter
* @since 1.0.0
* @return $limits
*/
public function postLimits( $limits )
{
$posts_per_page = (int) $this->mergedArgs['posts_per_page'];
if ( $posts_per_page
&& -1 != $posts_per_page // Make sure that posts_per_page is not set to return all posts
&& true !== $this->mergedArgs['nopaging'] // Make sure that nopaging is not set to true
) {
$limits = "LIMIT 0, $posts_per_page"; // Leave offset at 0 to avoid 404 on paged pages
}
return $limits;
}
/**
* Public callback method loopStart()
*
* Callback function which will be hooked to the loop_start action hook
*
* @param \stdClass \WP_Query $q Query object passed by reference
* @since 1.0.0
*/
public function loopStart( \WP_Query $q )
{
/**
* Although we run this action inside our preGetPosts methods and
* and inside a main query check, we need to redo the check here aswell
* because failing to do so sets our div in the custom query output as well
*/
if ( !$q->is_main_query() )
return;
/**
* Add inline style to hide the page content from the loop
* whenever $removePageFromLoop is set to true. You can
* alternatively alter the page template in a child theme by removing
* everything inside the loop, but keeping the loop
* Example of how your loop should look like:
* while ( have_posts() ) {
* the_post();
* // Add nothing here
* }
*/
if ( true === $this->removePageFromLoop )
echo '<div style="display:none">';
}
/**
* Public callback method loopEnd()
*
* Callback function which will be hooked to the loop_end action hook
*
* @param \stdClass \WP_Query $q Query object passed by reference
* @since 1.0.0
*/
public function loopEnd( \WP_Query $q )
{
/**
* Although we run this action inside our preGetPosts methods and
* and inside a main query check, we need to redo the check here as well
* because failing to do so sets our custom query into an infinite loop
*/
if ( !$q->is_main_query() )
return;
// See the note in the loopStart method
if ( true === $this->removePageFromLoop )
echo '</div>';
//Make sure that $this->injectorQuery actually have a value and is not NULL
if ( !$this->injectorQuery instanceof \WP_Query )
return;
// Setup a counter as wee need to run the custom query only once
static $count = 0;
/**
* Only run the custom query on the first run of the loop. Any consecutive
* runs (like if the user runs the loop again), the custom posts won't show.
*/
if ( 0 === (int) $count ) {
// We will now add our custom posts on loop_end
$this->injectorQuery->rewind_posts();
// Create our loop
if ( $this->injectorQuery->have_posts() ) {
/**
* Fires before the loop to add pagination.
*
* @since 1.0.0
*
* @param \stdClass $this->injectorQuery Current object (passed by reference).
*/
do_action( 'pregetgostsforgages_before_loop_pagination', $this->injectorQuery );
// Add a static counter for those who need it
static $counter = 0;
while ( $this->injectorQuery->have_posts() ) {
$this->injectorQuery->the_post();
/**
* Fires before get_template_part.
*
* @since 1.0.0
*
* @param int $counter (passed by reference).
*/
do_action( 'pregetgostsforgages_counter_before_template_part', $counter );
/**
* Fires before get_template_part.
*
* @since 1.0.0
*
* @param \stdClass $this->injectorQuery-post Current post object (passed by reference).
* @param \stdClass $this->injectorQuery Current object (passed by reference).
*/
do_action( 'pregetgostsforgages_current_post_and_object', $this->injectorQuery->post, $this->injectorQuery );
/**
* Load our custom template part as set by the user
*
* We will also add template support for post formats. If $this->postFormatSupport
* is set to true, get_post_format() will be automatically added in get_template part
*
* If you have a template called content-video.php, you only need to pass 'content'
* to $template part and then set $this->postFormatSupport to true in order to load
* content-video.php for video post format posts
*/
$part = '';
if ( true === $this->postFormatSupport )
$part = get_post_format( $this->injectorQuery->post->ID );
get_template_part(
filter_var( $this->templatePart, FILTER_SANITIZE_STRING ),
$part
);
/**
* Fires after get_template_part.
*
* @since 1.0.0
*
* @param int $counter (passed by reference).
*/
do_action( 'pregetgostsforgages_counter_after_template_part', $counter );
$counter++; //Update the counter
}
wp_reset_postdata();
/**
* Fires after the loop to add pagination.
*
* @since 1.0.0
*
* @param \stdClass $this->injectorQuery Current object (passed by reference).
*/
do_action( 'pregetgostsforgages_after_loop_pagination', $this->injectorQuery );
}
}
// Update our static counter
$count++;
}
}
Vous pouvez maintenant lancer la classe (également dans votre fichier de plugin ou de fonctions) comme suit pour cibler la page avec l'ID 251, sur laquelle nous afficherons 2 publications par page à partir du type de publication post
.
$query = new PreGetPostsForPages(
251, // Page ID we will target
'content', //Template part which will be used to display posts, name should be without .php extension
true, // Should get_template_part support post formats
false, // Should the page object be excluded from the loop
[ // Array of valid arguments that will be passed to WP_Query/pre_get_posts
'post_type' => 'post',
'posts_per_page' => 2
]
);
$query->init();
Comme je l'ai mentionné précédemment, la requête sur l'injecteur contient quelques actions permettant d'ajouter une mise en page et/ou un style personnalisé.
Dans l'exemple suivant, j'ai ajouté la pagination après la boucle à l'aide de ma propre fonction de pagination à partir de la réponse liée . De plus, en utilisant mon compteur personnalisé, j'ai ajouté un <div>
à pour afficher mes publications sur deux colonnes.
Voici les actions que j'ai utilisées
add_action( 'pregetgostsforgages_counter_before_template_part', function ( $counter )
{
$class = $counter%2 ? ' right' : ' left';
echo '<div class="entry-column' . $class . '">';
});
add_action( 'pregetgostsforgages_counter_after_template_part', function ( $counter )
{
echo '</div>';
});
add_action( 'pregetgostsforgages_after_loop_pagination', function ( \WP_Query $q )
{
paginated_numbers();
});
Notez que la pagination est définie par la requête principale, et non par la requête d'injecteur. Les fonctions intégrées telles que the_posts_pagination()
devraient également fonctionner.
C'est le résultat final
Tout fonctionne comme prévu sur les premières pages statiques avec ma fonction de pagination sans aucune modification supplémentaire.
Cela peut sembler beaucoup de frais généraux, et peut-être, mais les pros l'emportent sur les inconvénients.
BIG PRO'S
Il n'est pas nécessaire de modifier le modèle de page pour une page spécifique. Cela rend tout dynamique et peut facilement être transféré entre les thèmes sans apporter de modifications au code, tant que tout est fait dans un plugin.
Tout au plus, il vous suffit de créer une partie de modèle content.php
dans votre thème si votre thème n'en contient pas encore.
Toute pagination qui fonctionne sur la requête principale fonctionnera sur la page sans aucun type de modification ni aucun élément supplémentaire de la requête en cours de transmission à la fonction.
Il y a d'autres avantages auxquels je ne peux pas penser maintenant, mais ce sont les plus importants.