为单页循环保留 post 个过滤器

keep post filter for single page loop

我希望 wordpress 将查询过滤器保留在单页循环中。例如,当用户按类别 X 排序时,类别页面仅提供来自类别 X 的 posts。但是,当用户单击 post 并转到单个页面时,下一个post link 将循环所有 post。

这是 single.php 中的代码:

<?php if ( have_posts() ): ?>
        <?php while ( have_posts() ): the_post();
        ...
                        <!-- pagination functions here. -->
                        <div class="nav-previous pull-left">
                            <?php next_post_link('%link', '<span class="hidden-xs btn-black btn"><i class="fa fa-angle-left"></i> Next Question </span><span class="visible-xs btn btn-black"><i class="fa fa-angle-left"></i> Next </span>'); // next post ?>
                        </div>
                        <div class="nav-next pull-right">
                            <?php previous_post_link('%link', '<span class="btn btn-black hidden-xs"> Previous Question <i class="fa fa-angle-right"></i></span><span class="btn btn-black visible-xs"> Previous <i class="fa fa-angle-right"></i></span>'); // previous post ?>
                        </div>
                        <div class="clearfix"></div>
                        <!-- pagination functions ends here -->
                        <br />
                        <br />
                        <!-- comments template -->
                        <?php if ( is_singular() ) wp_enqueue_script("comment-reply"); ?>
                        <?php comments_template(); // include comments.php ?>
                    </div>
                    <div class="clearfix"></div>
                </div>
            </article>
            <!-- end post-format -->
        <?php endwhile; ?>
    <?php endif; ?>

如何确保 the_post() 仅 returns post 属于用户在 category.php 中搜索的类别?

我刚刚在这周完成了一个非常密集的 post link 函数来完成同样的事情。此功能不使用会话、cookie 或 HTTP 引荐来源网址进行分页。我也在 WPSE 上 post 编辑了这个,所以我将在这里重新 post post。

一些预注

  • 我不仅为类别编写了此函数,还为标签、分类法、作者和搜索查询编写了该函数。您可以删除不需要的内容

  • 默认情况下,在任何其他页面上,单击单个 post 时,下一个和上一个 post 将来自同一术语,您可以禁用此功能就像 post

  • 底部的用法部分一样
  • 这个post应该和this post on WPSE

  • 一起阅读

来自 WPSE

的 POST

这个问题的初衷是想知道一个post是从哪里被引用的,然后根据post引用者根据那个提供下一个和上一个post

我想完成的是例如:

post 从类别、分类法、标签、搜索或作者存档页面中单击。这些档案用作推荐人。现在,通常人们会像我的问题一样使用 wp_get_referer() 来获取该引荐来源网址并在进一步的查询中使用它。正如@G.M. in his accepted answer above所述,这种方法并不可靠,所以我去使用了他的替代方案

另一个问题是,您需要使用某种 cookie 或会话来存储此引荐来源网址,这样当您离开原始单一来源时,您仍然可以从原始引荐来源网址中获取 posts post 从特定存档中单击。由于 cookie 也由最终用户控制,因此不可靠,而且 Wordpress 默认不使用会话这一事实,我使用 @G.M 重构了下一个和上一个 post links . 替代解决方案 以可靠的方式检查和存储我的原始推荐人

这是我想出来的,希望不久的将来有人会发现它有用。请使用和滥用代码来满足您的需求,只需一个请求,留下 link 回到这个问题。 :-)

要遵循的代码注意事项

  • 这段代码比较长,内容也比较多,我就不细说了。代码评论很好

  • 此代码可以选择在同一术语内的 post 之间分页,就像 Wordpress 中默认的 next_post_link()previous_post_link() 函数一样。就像本机函数一样,您必须设置分类法。 in_same_term 的默认值为 true,分类法为 category

  • 最重要的是,这段代码需要PHP5.4+

代码

<?php
/**
 * @author Pieter Goosen
 * @license GPLv2 
 * @link http://www.gnu.org/licenses/gpl-2.0.html
 *
 * The functions on this page returns the next and previous post links
 * depending what is been set
 *
 * @return function single_post_navigation()
*/ 

/**
 * Register six new query variables aq, ,cq, tq, ttq, taq, and sq set by 
 * the term_referer_link function
 *
 * @see http://codex.wordpress.org/WordPress_Query_Vars
 *
*/ 
add_filter( 'query_vars', function ( $vars ) {

    $vars[] = 'cq'; // Will hold category ID
    $vars[] = 'tq'; // Will hold taxonomy name
    $vars[] = 'ttq'; // Will hold term slug
    $vars[] = 'sq'; // Will hold search query
    $vars[] = 'aq'; // Will hold author name
    $vars[] = 'taq'; // Will hold tag id


    return $vars;

}, 10, 3 );

/**
 * Conditional tag to check whether or not a query_var has been set
 *
 * @param string $query_var query_var to check
 * @return (bool) true if query_var exists, false on failure
 *
*/
function has_query_var( $query_var ) {

    $array = $GLOBALS['wp_query']->query_vars;

    return array_key_exists( $query_var, $array );

}

/**
 * For posts being clicked from a category page, the query_var, 'cq' is set. 
 * 'cq' holds the category ID
 *
 * Set two query_var, 'tq' and 'ttq' to single posts that was clicked on from 
 * taxonomy pages. 'tq' holds the taxonomy name while 'ttq' holds the term name
 *
 * For search queries, the query_var, 'sq' is set to single posts that was clicked on from 
 * the search page. 'sq' holds the search query value
 *
 * For posts being clicked from an author page, the query_var, 'aq' is set. 
 * 'aq' holds the author ID
 *
 * For posts being clicked from a tag page, the query_var, 'taq' is set. 
 * 'taq' holds the tag ID
 *
 * This function replaces the wp_get_referer() and $_SERVER['HTTP_REFERER']
 * functions that are not very reliable
 * @see php.net manual $_SERVER['HTTP_REFERER']
 * @link http://php.net/manual/en/reserved.variables.server.php
 *
 * @uses add_query_arg()
 * @uses post_link
 * @uses post_type_link
 *
*/
add_filter( 'post_type_link', 'term_referer_link', 10, 3 );
add_filter( 'post_link', 'term_referer_link', 10, 3 );

function term_referer_link( $permalink, $post ) {

    switch ( true ) {

        case ( is_category() ):

            $category = get_queried_object_id();

            $args = [
                'cq'    => $category, 
            ];

            break;
        case ( is_tax() ):

            $term = get_queried_object();

            $args = [
                'tq'    => $term->taxonomy, 
                'ttq'   => $term->slug
            ];

            break;

        case ( is_search() ):

            $search = get_search_query();

            $args = [
                'sq'    => $search, 
            ];

            break;

        case ( is_author() ):

            $author = get_queried_object_id();

            $args = [
                'aq'    => $author,
            ];

            break;

        case ( is_tag() ):

            $tag = get_queried_object_id();

            $args = [
                'taq'   => $tag,
            ];

            break;

    }

    if( isset( $args ) ) { 

        $permalink  = add_query_arg( $args, $permalink );

    }

    return $permalink;

}

/**
 * @access private
 * This function is marked private and should not be used in any other functions
 *
 * This is a helper function for the main navigation function 
 * 
 * This function checks if any of the query variables is set in the single
 * post page URL. If they exists, the values are retrieved that was set
 * by the query variables
 *
 * This query variables is converted into query arguments for the query that will
 * be used to determine the current post position and the posts adjacent to the
 * current post which will translate in the next and previous post. 
 * 
 * When no query variables are present, and empty array of argument is returned
 * 
 * @uses has_query_var()
 * @return (array) $add_query_args_to_args Query variable to determine the next/previous post links
 * @see http://codex.wordpress.org/Function_Reference/add_query_arg
 *
*/
function _query_vars_to_query_args() {

    switch ( true ) {

        case ( has_query_var( 'cq' ) ): // For category referrer

            $category = get_query_var( 'cq' );

            $add_query_args_to_args = [
                'cat' => $category,
            ];

            break;

        case ( has_query_var( 'tq' ) && has_query_var( 'ttq' ) ): // For taxonomy term referrer

            $taxonomy   = get_query_var( 'tq' );
            $term       = get_query_var( 'ttq' );

            $add_query_args_to_args = [
                'tax_query' => [
                    [
                        'taxonomy'          => $taxonomy,
                        'field'             => 'slug',
                        'terms'             => $term,
                        'include_children'  => false,
                    ],
                ],
            ];

            break;

        case ( has_query_var( 'sq' ) ): // For search referrer

            $search = get_query_var( 'sq' );

            $add_query_args_to_args = [
                's' => $search,
            ];

            break;

        case ( has_query_var( 'aq' ) ): // For author referrer

            $author = get_query_var( 'aq' );

            $add_query_args_to_args = [
                'author' => $author,
            ];

            break;

        case ( has_query_var( 'taq' ) ): // For tag referrer

            $tag = get_query_var( 'taq' );

            $add_query_args_to_args = [
                'tag_id' => $tag,
            ];

            break;

        default: // Default: returns empty array on any other archive or homepage

            $add_query_args_to_args = [];

            break;

    }

    return $add_query_args_to_args;

}
/**
 * @access private
 * This function is marked private and should not be used in any other functions
 *
 * This is a helper function for the main pagination function. This function 
 * checks if the defined query variables has been set in the URL of a single
 * post
 * 
 * If any of the query variables are found on any given single post page, then 
 * these query variables will be set to the next and previous post links according
 * to the single post's query variables
 * 
 * This way, next and previous posts will be shown from the same category, term, 
 * search query or author archive from which the original single post was referred 
 * from. 
 *
 * If a single post was referred from any other archive or main page, these query 
 * variables will not be set, and function will default to an empty array and no
 * query variables will be set to the next and previous post links
 *
 * @uses has_query_var()
 * @return (array) $qv Query variable to add to next/previous post links
 * @see http://codex.wordpress.org/Function_Reference/add_query_arg
 *
 * @todo Other archives can be added later
*/
function _add_query_vars_to_nav_links() {

    switch ( true ) {

        case ( has_query_var( 'cq' ) ): // For category referrer

            $category = get_query_var( 'cq' );

            $qv = [
                'cq'    => $category, 
            ];

            break;

        case ( has_query_var( 'tq' ) && has_query_var( 'ttq' ) ): // For taxonomy term referrer

            $taxonomy   = get_query_var( 'tq' );
            $term       = get_query_var( 'ttq' );

            $qv = [
                'tq'    => $term->taxonomy, 
                'ttq'   => $term->slug
            ];

            break;

        case ( has_query_var( 'sq' ) ): // For search referrer

            $search = get_query_var( 'sq' );

            $qv = [
                'sq'    => $search, 
            ];

            break;

        case ( has_query_var( 'aq' ) ): // For author referrer

            $author = get_query_var( 'aq' );

            $qv = [
                'aq'    => $author,
            ];

            break;

        case ( has_query_var( 'taq' ) ): // For tag referrer

            $tag = get_query_var( 'taq' );

            $qv = [
                'taq'   => $tag,
            ];

            break;


        default: // Default: returns empty array on any other archive or homepage

            $qv = [];

            break;

    }

    return $qv;

}

/**
 * This function returns navigation links to the next/previous single post
 * There are choices to which taxonomy to use, and whether adjacent posts should
 * be of the same term or not
 * 
 * When in_same_term is set to true, you have a choice to use the parent term or
 * child term if a post belongs to both. If the parent term is not available, the child term 
 * is automatically used
 *
 * @param array $defaults An array of key => value arguments. Defaults below 
 * - bool in_same_term      Whether or not next/previous post should be in the same term Default true
 * - bool parent_term       If in_same_term is true, should the parent or child terms be used Default true
 * - string/array taxonomy  The taxonomy from which terms to use Default category
 * - string previous_text   Text to display with previous post Default 'Previous post'
 * - string next_text       Text to display with next post Default 'Next post'
 *
 * @return string $links
*/ 
function get_single_post_navigation( $args = [] ) {

    // Sets the default arguments for default usage
    $defaults = [
        'in_same_term'      => true,
        'parent_term'       => true,
        'post_types'         => '',
        'taxonomy'          => 'category',
        'previous_text'     => __( 'Previous post' ),
        'next_text'         => __( 'Next post' ),
    ];

    // Merges the default arguments with user defined variables
    $args = wp_parse_args( $args, $defaults );

    /**
     * Get the currently displayed single post. For this use 
     * get_queried_object() as this is more safe than the global $post
     *
     * The $post global is very easily changed by any poorly written custom query
     * or function, and is there for not reliable
     *
     * @see Post below on WPSE for explanation
     * @link https://wordpress.stackexchange.com/q/167706/31545
    */ 
    $single_post = get_queried_object();

    /**
     * Use the post type of the current post or post types entered in args
     *
    */ 
    $post_type   = ( empty( $args['post_types'] ) ) ? $single_post->post_type : $args['post_types'];


    // Set the variable query variables according to condition
    if( !empty( _query_vars_to_query_args() ) ) {

        $query_args = _query_vars_to_query_args(); 

    }elseif( true === $args['in_same_term'] ) {

        $terms =  wp_get_post_terms( $single_post->ID, $args['taxonomy'] ); 

        if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){

            foreach ( $terms as $term ) {
                if( $term->parent === 0 ) {
                    $parent[] = $term;
                }else{
                    $child[] = $term;
                }
            }   

            $term_id = ( $args['parent_term'] === true && isset( $parent ) ) ? $parent[0]->term_id : $child[0]->term_id;

            $query_args = [ 
                'tax_query' => [
                    [
                        'taxonomy'          => $args['taxonomy'],
                        'field'             => 'term_id',
                        'terms'             => $term_id,
                        'include_children'  => false,
                    ],
                ],
            ];
        }

    }else{

        $query_args = [];

    }

    // Default arguments to use with all the conditional statements above
    $default_query_args = [ 
        'post_type'         => $post_type,
        'fields'            => 'ids',
        'posts_per_page'    => -1,
    ];

    // Merges the default arguments with the arguments from the conditional statement
    $combined_args = wp_parse_args( $query_args, $default_query_args );

    $q = new WP_Query( $combined_args );

    // Get the current post position. Will be used to determine adjacent posts
    $current_post_position = array_search( $single_post->ID, $q->posts );

    // Get the returned values from '_add_query_vars_to_nav_links()' to build links
    $get_qv = _add_query_vars_to_nav_links(); 

    // Get the next/older post ID
    if ( array_key_exists( $current_post_position + 1 , $q->posts ) ) {
        $next = $q->posts[$current_post_position + 1];
    }

    // Get post title link to the next post
    if( isset( $next ) ) {

        $next_post      = get_post( $next );
        $next_post_link = ( !empty( $get_qv ) ) ? add_query_arg( $get_qv, get_permalink( $next ) ) : get_permalink( $next );
        $next_title     = '<span class="meta-nav">' . $args['next_text'] . ': </span><a href="' . $next_post_link . '">' . $next_post->post_title . '</a></br>';

    }else{

        $next_title     = '';

    }

    // Get the previous/newer post ID
    if ( array_key_exists( $current_post_position - 1 , $q->posts ) ) {
        $previous = $q->posts[$current_post_position - 1];
    }

    // Get post title link to the previous post
    if( isset( $previous ) ) {

        $previous_post      = get_post( $previous );
        $previous_post_link = ( !empty( $get_qv ) ) ? add_query_arg( $get_qv, get_permalink( $previous ) ) : get_permalink( $previous );
        $previous_title     = '<span class="meta-nav">' . $args['previous_text'] . ': </span><a href="' . $previous_post_link . '">' . $previous_post->post_title . '</a></br>';

    }else{

        $previous_title     = '';

    }

    // Create the next/previous post links
    $links  = '<nav class="navigation post-navigation" role="navigation">';
    $links .= '<div class="nav-links">';
    $links .= $previous_title;
    $links .= $next_title;
    $links .= '</div><!-- .nav-links -->';
    $links .= '</nav><!-- .navigation -->';

    // Returns the post links with HTML mark-up
    return $links;

}

/** 
 * This function is simply just a wrapper for the main navigation
 * function and echo's the returned values from the main navigation
 * function
*/ 
function single_post_navigation( $args = [] ) {

    echo get_single_post_navigation( $args );

}

在单个模板中的使用

如果您不需要在同一术语中导航 post,也不需要使用您的 link 自定义下一个和上一个文本,您可以执行以下操作

$args = [
    'post_types'       => ['post', 'my_cpt'],
    'in_same_term'     => false,
    'previous_text'      => __( 'Vorige Pos' ),
    'next_text'      => __( 'Volgende Pos' ),
];

single_post_navigation( $args );