Gerçek sayfalarda ve statik ön sayfalarda pre_get_posts kullanma


19

pre_get_postsGerç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. $postdöngü, döngüdeki ilk mesaja $postve döngüden sonraki döngüdeki son mesaja ayarlanır. Ne gerek $postgeçerli sayfa nesnesi, yani sorgulanan nesne olarak ayarlanır.

Ayrıca, $wp_the_query->postve $wp_query->postnormal 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 $injectPageIntoLoopsayfa 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 wpbenim preGetPostsyö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ç preGetPostsyöntem

add_action( 'wp', [$this, 'wp'] );

Bundan $wp_the_query->post, $wp_query->postve $posttüm sayfa nesnesini tutar.

DÖNGÜ SONRASI

Dönemin ardından benim büyük sorunum burada. Globalleri wpkanca ve yöntemle hackledikten sonra ,

  • $wp_the_query->postve $wp_query->postbeklendiğ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 wpyöntemi çengel denedim loop_end. Takma wpyöntemini get_sidebareylem ç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->postve $wp_query->postolarak 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_postsgerçek sayfa ve statik ön sayfasında ve hala bütünlüğünü korumak $wp_the_query->post, $wp_query->postve $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->postve $postne 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_postsTam 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


Ne yapmaya çalışıyorsunuz, hedefleriniz veya fonksiyonel gereksinimleriniz? Anlayabildiğim kadarıyla hiçbir yerde ifade etmiyorsun.
adelval

Yanıtlar:


13

Sonunda çalıştım, ama sorumun koduyla değil. Tüm fikri tamamen hurdaya attım ve yeni bir yöne dönmeye başladım.

NOT:

Birisi sorumdaki sorunları çözebiliyorsa, bir cevap göndermekten çekinmeyin. Ayrıca, başka çözümleriniz varsa, bir cevap göndermekten çekinmeyin.

YENİDEN İŞLENMİŞ SINIF VE ÇÖZÜM:

Burada yapmaya çalıştığım şey, ana sorguyu tamamen değiştirmek ve (a) küreselleri doğrudan değiştirmek, (b) küresel değer konusuna girmek ve (c) dahil olmak üzere yukarıdaki tüm sorunlara takılı kalmak yerine enjeksiyon sonrası kullanmaktı. sayfa şablonlarını yeniden atama.

Sonrası enjeksiyon kullanarak, ben tam sonrası bütünlüğünü, yani tutmak mümkün değilim $wp_the_query->post, $wp_query->post, $postsve $postşablona boyunca kalmak sabiti. Bu değişkenlerin her biri geçerli sayfa nesnesine başvurur (gerçek sayfalarda olduğu gibi). Bu şekilde, kırıntılar gibi işlevler geçerli sayfanın bir tür arşiv değil gerçek bir sayfa olduğunu bilir.

Gerçi sayfalandırma için ayarlamak için biraz ( filtreler ve eylemler aracılığıyla) ana sorguyu değiştirmek zorunda kaldı , ama biz buna gelecektir.

ENJEKSİYON SONRASI SORGULAMA

Enjeksiyon sonrası başarmak için, enjeksiyon için gerekli direkleri döndürmek için özel bir sorgu kullandım. Ayrıca $found_pages, ana sorgudan çalışma sayfalama almak için ana sorguyu ayarlamak için özel sorgu özelliğini kullandım. Mesajlar loop_endeylem yoluyla ana sorguya enjekte edilir .

Özel sorguyu sınıf dışında erişilebilir ve kullanılabilir hale getirmek için birkaç işlem başlattım.

  • Sayfalama işlevlerini bağlamak için sayfalandırma kancaları :

    • pregetgostsforgages_before_loop_pagination

    • pregetgostsforgages_after_loop_pagination

  • Döngüdeki mesajları sayan özel sayaç . Bu eylemler, yazıların posta numarasına göre döngü içinde görüntülenme şeklini değiştirmek için kullanılabilir.

    • pregetgostsforgages_counter_before_template_part

    • pregetgostsforgages_counter_after_template_part

  • Sorgu nesnesine ve geçerli posta nesnesine erişmek için genel kanca

    • pregetgostsforgages_current_post_and_object

Bu kancalar, başlangıçtaki asıl amacım olan sayfa şablonunun kendisinde herhangi bir değişiklik yapmanız gerekmediği için size toplam bir deneyim sunar. Bir sayfa, bir eklenti veya işlev dosyasından tamamen değiştirilebilir, bu da bu çözümü çok dinamik hale getirir.

Ayrıca get_template_part()mesajları görüntülemek için kullanılacak bir şablon parçası yüklemek için kullandım. Günümüzde çoğu tema şablon parçalarını kullanmaktadır, bu da bunu sınıfta çok yararlı kılmaktadır. Temanız kullanılıyorsa content.php, yüklemek contentiçin basitçe geçebilirsiniz .$templatePartcontent.php

Şablon parçalar için son biçimi desteği gerekiyorsa, kolaydır - sadece geçebilir contentiçin $templatePartve set $postFormatSupportiçin true. Sonuç olarak, şablon bölümü content-video.phpyazı biçimine sahip bir yazı için yüklenecektir video.

ANA SORGULAMA

İlgili sorgu ve eylemler aracılığıyla ana sorguda aşağıdaki değişiklikler yapıldı:

  • Ana sorguyu sayfalamak için:

    • Enjektör sorgusunun $found_postsözellik değeri, found_postsfiltre aracılığıyla ana sorgu nesnesinin değerine iletilir .

    • Geçirilen kullanıcı parametresinin değeri, posts_per_pageüzerinden ana sorguya ayarlanır pre_get_posts.

    • $max_num_pages$found_posts ve içindeki yayınların miktarı kullanılarak hesaplanır posts_per_page. Çünkü is_singularsayfalarda doğrudur, bu engeller LIMIThüküm varlık kümesi. Sadece is_singularfalse değerine ayarlamak birkaç soruna neden oldu, bu yüzden LIMITmaddeyi post_limitsfiltreden geçirmeye karar verdim . Sayfalandırmanın açık olduğu sayfalarda 404'lerden kaçınmak offsetiçin LIMITyan tümceyi sakladım 0.

Bu, sayfalama ve enjeksiyon sonrası ortaya çıkabilecek herhangi bir sorunu halleder.

SAYFA NESNE

Geçerli sayfa nesnesi, sayfadaki varsayılan döngüyü kullanarak, enjekte edilen yayınların ayrı ve üst kısmında yazı olarak görüntülenebilir. Buna ihtiyacınız yoksa, sadece $removePageFromLooptrue olarak ayarlayabilirsiniz ; bu, sayfa içeriğinin görüntülenmesini gizler.

Bu aşamada, bunu yapmanın başka bir yolunu bulamadığım için sayfa nesnesini loop_startve loop_endeylemleri aracılığıyla gizlemek için CSS kullanıyorum . Bu yöntemin dezavantajı the_post, ana sorgu içindeki eylem kancasına bağlanan herhangi bir şeyin de gizlenmesidir.

SINIF

PreGetPostsForPagesSınıf geliştirilebilir ve düzgün yanı isimalanlı edilmelidir. Bunu temanızın işlevler dosyasına bırakabilirsiniz, ancak bunu özel bir eklentiye bırakmak daha iyi olacaktır.

Uygun gördüğünüz gibi kullanın, değiştirin ve kötüye kullanın. Kod iyi yorumlanmıştır, bu yüzden takip edilmesi ve ayarlanması kolay olmalıdır

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++;       
    }
}  

KULLANIM

Şimdi sınıfı ( eklenti veya fonksiyonlar dosyasında da ) aşağıdaki şekilde başlatabilirsiniz 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(); 

PAGİNASYON VE ÖZEL TARAMA EKLEME

Daha önce de belirttiğim gibi, sayfalama ve / veya özel stil eklemek için enjektör sorgusunda birkaç işlem vardır.

Aşağıdaki örnekte, bağlı yanıttan kendi sayfalandırma işlevimi kullanarak döngüden sonra sayfalandırma ekledim . Ayrıca, özel sayacımı kullanarak, <div>yayınlarımı iki sütunda görüntülemek için bir ekledim .

İşte kullandığım eylemler

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();    
});

Sayfalandırmanın enjektör sorgusu tarafından değil, ana sorgu tarafından ayarlandığını unutmayın; bu nedenle, yerleşik işlevlerin the_posts_pagination()de çalışması gerekir.

Bu sonuç

resim açıklamasını buraya girin

STATİK ÖN SAYFALAR

Her şey, başka değişiklikler gerektirmeden sayfalama işlevimle birlikte statik ön sayfalarda beklendiği gibi çalışır.

SONUÇ

Bu çok fazla bir yük gibi görünebilir ve olabilir, ancak profesyonel, con'nın büyük zamanından daha ağır basar.

BÜYÜK PRO'LAR

  • Belirli bir sayfanın sayfa şablonunu herhangi bir şekilde değiştirmeniz gerekmez. Bu, her şeyi dinamik hale getirir ve her şey bir eklentide yapıldığı sürece kodda herhangi bir değişiklik yapmadan temalar arasında kolayca aktarılabilir.

  • En fazla, temanızda yalnızca temanızda content.phphenüz bir şablon yoksa bir şablon parçası oluşturmanız gerekir .

  • Ana sorguda çalışan herhangi bir sayfa, herhangi bir değişiklik veya sorguya işlevden geçirilen herhangi bir değişiklik olmadan sayfada çalışır.

Şimdi düşünemediğim daha fazla profesyonel var, ama bunlar önemli olanlar.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.