Nhận cấu trúc permalink mặc định từ URL đẹp


15

Khi một bài đăng được nhấp vào từ một trang chuyên mục hoặc cho vấn đề đó bất kỳ trang nào, bạn có thể lấy URL của người giới thiệu đó và phân tích nó để lấy chuỗi truy vấn. Nhưng điều này chỉ hoạt động với cấu trúc permalink mặc định

Ví dụ khi người giới thiệu là một trang chuyên mục:

A var_dump( parse_url( wp_get_referer() ) );đưa ra đầu ra sau với cấu trúc permalink mặc định

array(4) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(9) "localhost"
  ["path"]=>
  string(11) "/wordpress/"
  ["query"]=>
  string(5) "cat=7"
}

Tương tự var_dump()với permalinks được đặt thành /%postname%/, đây là những gì bạn nhận được

array(3) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(9) "localhost"
  ["path"]=>
  string(32) "/wordpress/category/uit-my-lewe/"
}

Tôi có thể sử dụng pathtừ khối mã thứ hai với get_category_by_path(), tôi có thể lấy các đối tượng thể loại

Vấn đề của tôi là, làm thế nào để tôi đi về điều này cho các thuật ngữ phân loại.

Tôi đã làm một bài kiểm tra. Tôi có một phân loại tùy chỉnh event_cat. Nếu tôi viết lại nó event-slug, tôi sẽ pathsử dụng /%postname%/cấu trúc permalink sau đây

/wordpress/event-slug/5-star/

event_cat=5-star

sử dụng cấu trúc mặc định

Tự động tên phân loại của tôi sẽ không có trong URL, chỉ là thuật ngữ của tôi. Vì vậy, đây sẽ không phải là một phương pháp an toàn rất thất bại trong việc lấy các đối tượng từ thuật ngữ này.

Câu hỏi của tôi là, làm thế nào để tôi có được cấu trúc permalink mặc định lấy chuỗi truy vấn hoặc chuỗi truy vấn hoặc tên phân loại và tên thuật ngữ từ /%postname%/cấu trúc permalink


Điều này nghe giống như thư viện Url To Query của một người nào đó mà bạn có thể bây giờ. ;)
Rarst

Tại sao anh làm điều này? (Vấn đề XY)
Tom J Nowell

Cảm ơn @Rarst Nên biết rằng ai đó sẽ có cái gì đó như thế này :-). Điều đó sẽ phù hợp với dự luật
Pieter Goosen

Tôi vẫn muốn xem câu trả lời từ GM giải thích cách thức hoạt động của nó.
Rarst

@TomJNowell Về cơ bản tôi cần biết liệu một bài đăng có được giới thiệu từ trang thuật ngữ phân loại hay không, nếu vậy, tôi cần biết thuật ngữ nào. Tôi cần tính toán bài đăng nào để phục vụ như bài tiếp theo / trước. Điều này sẽ chỉ cần thiết trong trường hợp nếu bài viết có nhiều điều khoản mặc dù. Các điều khoản duy nhất trên bảng rất dễ dàng
Pieter Goosen

Câu trả lời:


10

Trước hết tôi phải nói rằng wp_get_referer()nó không đáng tin cậy 100% vì nó phụ thuộc vào $_SERVER['HTTP_REFERER']điều đó không đáng tin cậy 100%, từ các tài liệu php.net :

Địa chỉ của trang (nếu có) đã giới thiệu tác nhân người dùng đến trang hiện tại. Điều này được thiết lập bởi tác nhân người dùng. Không phải tất cả các tác nhân người dùng sẽ thiết lập điều này và một số cung cấp khả năng sửa đổi HTTP_REFERER thành một tính năng. Nói tóm lại, nó không thể thực sự được tin tưởng.

Giải pháp thay thế

Nếu bạn có thể thêm vào url bài đăng một đối số truy vấn cho biết bài đăng đến từ đâu, nó sẽ đáng tin cậy hơn và bạn không cần phải phân tích một url để có được một đối tượng hạn.

Thí dụ:

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

Làm như vậy, đăng permalinks được nhấp từ một trang danh mục sẽ đưa bạn đến một url như

http://example.com/wordpress/post-name?catfrom=12

Và bạn có thể dễ dàng hiểu người dùng đến từ đâu mà không cần dựa vào $_SERVER['HTTP_REFERER']và không cần bất kỳ nỗ lực nào khác.

Trả lời câu hỏi của bạn

Nhận thông tin truy vấn bắt đầu từ một url là điều mà WordPress thực hiện bên trong WP::parse_request()phương thức.

Phương pháp đó được dự định chỉ được sử dụng một lần và chỉ cho url "chính" (url mà người dùng đang xem) chứ không phải cho các url tùy ý.

Vài tháng trước tôi đã viết plugin Url To Query với mục đích làm điều tương tự cho các url tùy ý.

Những gì tôi đã làm là lấy WP::parse_request()và tái cấu trúc nó thành mã OOP lành mạnh hơn và làm cho nó hoạt động với các url tùy ý (ví dụ: url để xử lý được nhận dưới dạng đối số thay vì được lấy từ $_SERVERvar).

Sử dụng plugin của tôi, bạn có thể

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

var_dump($args); // array( 'event_slug' => '5-star' );

Vì vậy, bạn có được các đối số truy vấn (thứ mà bạn có thể chuyển thẳng đến new WP_Query) bắt đầu từ một url, đó chính xác là những gì WP::parse_request().

Trong trường hợp của bạn, bạn có thể kiểm tra mảng args mà không cần thực sự chạy truy vấn.

Điều này chắc chắn có thể hoạt động, tuy nhiên tôi nghĩ rằng nỗ lực bổ sung cần thiết để phân tích url và không đáng tin cậy $_SERVER['HTTP_REFERER']làm cho giải pháp đầu tiên tốt hơn cho phạm vi của bạn.


Nếu tôi muốn lấy Id bài đăng hoặc sên từ người giới thiệu .. Làm thế nào tôi có thể nhận được điều đó..là đối tượng truy vấn không chứa thông tin đó ...
Parth Kumar

5

Mục đích ban đầu của câu hỏi này là để biết một bài đăng được giới thiệu từ đâu và sau đó theo đó, phục vụ các bài đăng tiếp theo và trước đó theo người giới thiệu bài đăng.

Những gì tôi muốn thực hiện là ví dụ:

Một bài đăng được nhấp vào từ một danh mục, phân loại, thẻ, tìm kiếm hoặc trang lưu trữ tác giả. Những tài liệu lưu trữ phục vụ như là người giới thiệu. Bây giờ, thông thường người ta sẽ sử dụng, như trong câu hỏi của tôi, wp_get_referer()để có được người giới thiệu đó và sử dụng nó trong các truy vấn tiếp theo. Theo mô tả của @GM trong câu trả lời được chấp nhận của anh ấy ở trên , phương pháp này không đáng tin cậy, vì vậy tôi đã đi và sử dụng Giải pháp thay thế của anh ấy .

Vấn đề khác là cần sử dụng một số loại cookie hoặc phiên để lưu trữ người giới thiệu này, để bạn vẫn xử lý các bài đăng từ người giới thiệu ban đầu khi bạn điều hướng khỏi bài đăng gốc được nhấp từ kho lưu trữ cụ thể. Vì cookie cũng được kiểm soát bởi người dùng cuối và do đó không đáng tin cậy và thực tế là WordPress không sử dụng phiên theo mặc định, tôi đã cấu trúc lại các liên kết bài đăng tiếp theo và trước đó bằng cách sử dụng @GM Alternative Solution để kiểm tra và lưu trữ bản gốc của tôi người giới thiệu.

Đây là những gì tôi nghĩ ra và tôi hy vọng ai đó sẽ thấy nó hữu ích trong tương lai gần. Xin vui lòng, sử dụng và lạm dụng mã để phù hợp với nhu cầu của bạn, chỉ cần một yêu cầu: để lại liên kết cho câu hỏi này. :-)

GHI CHÚ VỀ MÃ SỐ ĐỂ SAU

  • Mã này khá dài và chuyên sâu, vì vậy tôi sẽ không đi sâu vào chi tiết. Các mã đã được nhận xét tốt

  • Mã này có tùy chọn trang giữa các bài đăng trong cùng một thuật ngữ, giống như mặc định next_post_link()và các previous_post_link()chức năng trong WordPress. Giống như các hàm riêng, bạn phải thiết lập phân loại. Giá trị mặc định cho in_same_termtruevà phân loại làcategory

  • Quan trọng nhất, mã này yêu cầu PHP 5.4+

MẬT MÃ

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

}

SỬ DỤNG TRONG MẪU MẪU

Nếu bạn không cần điều hướng các bài đăng trong cùng một thuật ngữ, hãy nhận các bài đăng từ tất cả các loại bài đăng và tùy chỉnh văn bản tiếp theo và trước đó bằng liên kết của bạn, bạn có thể làm như sau:

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

single_post_navigation( $args );

CHỈNH SỬA 1

Theo yêu cầu từ một bài đăng trên SO và là một phần của a @todo, giờ đây tôi đã giới thiệu hỗ trợ không chỉ điều hướng giữa các bài đăng từ loại bài đăng hiện tại, mà từ một loạt các loại bài đăng được đặt bởi người dùng bằng cách sử dụngpost_types tham số trong hàm. Xin vui lòng xem mã cập nhật.

CHỈNH SỬA 2

Thêm 'suppress_filters' => true,vào các WP_Queryđối số để phân trang không bị thay đổi bởi bất kỳ bộ lọc nào được sử dụng trongWP_Query

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.