pre_get_posts
Gerçek sayfalarda ve statik ön sayfalarda nasıl kullanılacağına dair oldukça kapsamlı bir araştırma yaptım ve aptalca bir yöntem yok gibi görünüyor.
Bugüne kadar bulduğum en iyi seçenek Stackoverflow'da @birgire tarafından yapılan bir gönderiydi . Bir demo sınıfına yeniden yazdım ve kodu biraz daha dinamik hale getirdim
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();
Bu, kendi sayfalandırma işlevimi kullanarak beklendiği gibi iyi çalışıyor .
SORUNLAR:
İşlev nedeniyle, depolanan sayfa nesnesine dayanan diğer işlevlerin sayfa bütünlüğünü kaybederim $post
. $post
döngü, döngüdeki ilk mesaja $post
ve döngüden sonraki döngüdeki son mesaja ayarlanır. Ne gerek $post
geçerli sayfa nesnesi, yani sorgulanan nesne olarak ayarlanır.
Ayrıca, $wp_the_query->post
ve $wp_query->post
normal bir sayfaya olarak döngü içinde ilk mesajını değil sorgulanan nesne tutan
Döngüden önce ve sonra globallerimi kontrol etmek için aşağıdakileri ( sınıfımın dışında ) kullanıyorum
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
}
DÖNGÜ ÖNCESİ:
Döngüden önce, sorun kısmen $injectPageIntoLoop
sayfa nesnesini döngüdeki ilk sayfa olarak enjekte eden true değerine ayarlanarak çözülür . İstenilen yayınlardan önce sayfa bilgisini göstermeniz gerekiyorsa, ancak bunu istemiyorsanız oldukça kullanışlıdır.
Gerçekten sevmediğim küreselleri hackleyerek sorunu döngüden önce çözebilirim. Aşağıdaki yöntemi wp
benim preGetPosts
yöntem içine kanca
public function wp()
{
$page = get_post( $this->pageID );
$GLOBALS['wp_the_query']->post = $page;
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
$GLOBALS['post'] = $page;
}
ve iç preGetPosts
yöntem
add_action( 'wp', [$this, 'wp'] );
Bundan $wp_the_query->post
, $wp_query->post
ve $post
tüm sayfa nesnesini tutar.
DÖNGÜ SONRASI
Dönemin ardından benim büyük sorunum burada. Globalleri wp
kanca ve yöntemle hackledikten sonra ,
$wp_the_query->post
ve$wp_query->post
beklendiği gibi döngüdeki ilk gönderiye geri ayarlandı$post
, döngüdeki son gönderiye ayarlanır.
Ne gerek üç sorgulanan nesne / geçerli sayfa nesnesi için ayarlanmış olmasıdır.
Ben işe yaramaz, eylem wp
yöntemi çengel denedim loop_end
. Takma wp
yöntemini get_sidebar
eylem çalışır, ancak çok geç.
add_action( 'get_sidebar', [$this, 'wp'] );
printGlobals()
Şablondaki döngüden hemen sonra çalıştırılması , ilk gönderinin ve son gönderinin hala $wp_the_query->post
ve $wp_query->post
olarak ayarlandığını onaylar $post
.
wp
Şablon içinde döngü sonra yöntem içinde kodu el ile ekleyebilirsiniz , ancak fikir temalar arasında bir eklenti içinde aktarılabilir olması gerektiği gibi şablon dosyaları doğrudan değiştirmek değil.
Bir çalışma bu sorunu çözmek için herhangi bir uygun yolu var mı pre_get_posts
gerçek sayfa ve statik ön sayfasında ve hala bütünlüğünü korumak $wp_the_query->post
, $wp_query->post
ve $post
( sorgulanan nesneye bu dizi sahip öncesi ve döngü sonra).
DÜZENLE
Neye ihtiyacım olduğu ve neden ihtiyacım olduğu konusunda karışıklık var gibi görünüyor
Neye ihtiyacım var
Ben değerlerini korumak gerekir $wp_the_query->post
, $wp_query->post
ve $post
ne olursa olsun şablona karşısında ve bu değer sorgulanan nesne olmalıdır. Bu aşamada, gönderdiğim kodla, bu üç değişkenin değerleri sayfa nesnesini değil, döngüdeki yazı nesnelerini tutuyor. Umarım bu yeterince açıktır.
Bu değişkenleri test etmek için kullanabileceğiniz kod yayınladım
Neden ihtiyacım var
pre_get_posts
Tam sayfa işlevselliğini değiştirmeden sayfa şablonlarına ve statik ön sayfalara yayın eklemek için güvenilir bir yola ihtiyacım var . Bu aşamada, söz konusu kod durduğu gibi, döngüden sonra $post
"yanlış" posta nesnesini tutan döngü kırıntı özelliğini ve ilgili sayfa özelliğini bozuyor .
En önemlisi, sayfa şablonlarını doğrudan değiştirmek istemiyorum. Şablonda HERHANGİ değişiklik yapmadan bir sayfa şablonuna yayın ekleyebilmek istiyorum