从漂亮的URL获取默认固定链接结构

时间:2014-12-01 作者:Pieter Goosen

当从类别页面或任何页面单击单个帖子时,您可以获取该引用人的URL并对其进行解析以获取查询字符串。但这只适用于默认的permalink结构

当推荐人是类别页面时的示例:

A.var_dump( parse_url( wp_get_referer() ) ); 使用默认permalink结构提供以下输出

array(4) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(9) "localhost"
  ["path"]=>
  string(11) "/wordpress/"
  ["query"]=>
  string(5) "cat=7"
}
使用相同的var_dump() 永久链接设置为/%postname%/, 这就是你得到的

array(3) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(9) "localhost"
  ["path"]=>
  string(32) "/wordpress/category/uit-my-lewe/"
}
我可以使用path 从第二个代码块get_category_by_path(), 我可以得到类别对象

我的问题是,对于分类学术语,我该如何处理这个问题。

我做了个测试。我有一个自定义分类法event_cat. 如果我重写为event-slug, 我得到以下信息path 使用/%postname%/ as permalink结构

/wordpress/event-slug/5-star/
以及

event_cat=5-star
使用默认结构

自动地,我的分类名称不会出现在URL中,只是我的术语的slug。因此,这将不是一种从术语中获取对象的非常故障安全的方法。

我的问题是,如何正确获取默认的permalink结构从/%postname%/ permalink构造

2 个回复
最合适的回答,由SO网友:gmazzap 整理而成

首先我得说wp_get_referer() 不是百分之百可靠的,因为它依赖于$_SERVER[\'HTTP_REFERER\'] 这不是百分之百可靠的php.net 文档:

将用户代理引用到当前页面的页面(如果有)的地址。这是由用户代理设置的。并非所有的用户代理都会设置此功能,有些代理提供了将HTTP\\U REFERER作为功能进行修改的功能。简言之,它真的不可信。

替代解决方案

如果可以在帖子url中添加一个查询参数,说明帖子来自何处,那么它将更加可靠,并且不需要解析url来获取术语对象。

示例:

add_filter(\'post_link\', function($permalink) {
  if (is_category() && ($cat = get_queried_object())) {
    $permalink = esc_url(add_query_arg(array(\'catfrom\' => $cat->term_id), $permalink));
  }
  return $permalink;
});
这样,从类别页面单击的post permalinks会将您发送到如下url

http://example.com/wordpress/post-name?catfrom=12
您可以轻松了解用户的来源,而无需依赖$_SERVER[\'HTTP_REFERER\'] 没有任何其他的努力。

回答您的问题

从url获取查询信息是WordPress在WP::parse_request() 方法

该方法仅用于“主”url(用户正在查看的url),而不用于任意url。

几个月前,我写了Url To Query 插件的目的是为任意URL做同样的事情。

我所做的就是WP::parse_request(), 并将其重构为更合理的OOP代码,并使其可用于任意url(例如,要处理的url作为参数接收,而不是从$_SERVER var)。

使用我的插件,您可以

$args = url_to_query(\'/wordpress/event-slug/5-star/\');

var_dump($args); // array( \'event_slug\' => \'5-star\' );
因此,您可以获得查询参数(可以直接传递给new WP_Query) 从url开始,这正是WP::parse_request()

在您的情况下,您可能可以检查args数组,而无需实际运行查询。

这当然可以,但是我认为解析url所需的额外努力和$_SERVER[\'HTTP_REFERER\'] 使第一个解决方案更适合您的范围。

SO网友:Pieter Goosen

这个问题的初衷是要知道一个帖子是从哪里来的,然后根据这个帖子,根据帖子推荐人提供下一个和前一个帖子。

例如,我想完成的是:

从类别、分类法、标记、搜索或作者存档页面单击一篇文章。这些档案作为参考资料。现在,通常人们会使用,就像我的问题一样,wp_get_referer() 获得该推荐人并在进一步查询中使用。如所述@G.M. in his accepted answer above, 这种方法不可靠,所以我去用了他的Alternative Solution.

另一个问题是需要使用某种cookie或会话来存储此引用,这样,当您离开从特定存档中单击的原始单篇帖子时,您仍然可以从原始引用者中弹出帖子。由于Cookie也由最终用户控制,因此不可靠,而且WordPress默认不使用会话,因此我使用@G.M重构了下一个和上一个帖子链接。Alternative Solution 以可靠的方式检查和存储我的原始推荐人。

这就是我想到的,我希望在不久的将来有人会发现它有用。请使用和滥用代码以满足您的需要,只需一个请求:留下一个指向此问题的链接。:-)

关于要遵循的代码的注释这段代码很长而且很密集,所以我不打算详细介绍。代码已被很好地注释

与默认设置一样,此代码可以在同一期限内的帖子之间翻页next_post_link()previous_post_link() WordPress中的函数。就像本机函数一样,您必须设置分类法。的默认值in_same_termtrue 分类法是category

最重要的是,此代码需要PHP 5.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 on what has 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 exist, the values are retrieved that were set
 * by the query variables
 *
 * These query variables are 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, an empty array of arguments 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/array post_types Post types to get posts from. Uses current post\'s post type on empty string. Default empty string 
 * - 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,
        \'suppress_filters\'  => true,
    ];

    // 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 );

}
如果您不需要在同一期限内浏览帖子,从所有帖子类型中获取帖子,并使用链接自定义下一个和上一个文本,则可以执行以下操作:

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

single_post_navigation( $args );
应SO上帖子的请求,并作为@todo, 我现在引入了支持,不仅可以从当前帖子的帖子类型在帖子之间导航,还可以从用户使用post_types 函数中的参数。请查看更新的代码。

编辑2添加\'suppress_filters\' => true,WP_Query 参数中使用的任何筛选器都不会更改分页WP_Query

结束

相关推荐

Change Taxonomy Permalinks

我有自定义帖子,我创建了一个显示所有自定义帖子的页面。示例:www.example.com/archive-page我想知道是否可以更改与此自定义帖子相关的类别和标签的永久链接。现在我有:www.example.com/my-custom-post-type-cats/my-category-1www.example.com/my-custom-post-type-tags/my-tag-1</我想要这样的东西:www.example.com/archive-page?category=1www.e