Dapatkan struktur tautan permanen default dari URL cantik

15

Ketika satu posting diklik dari halaman kategori atau dalam hal apapun halaman, Anda bisa mendapatkan URL dari pengarah itu dan menguraikannya untuk mendapatkan string kueri. Tetapi ini hanya berfungsi dengan struktur permalink default

Contoh ketika pengarah adalah halaman kategori:

A var_dump( parse_url( wp_get_referer() ) );memberikan output berikut dengan struktur permalink default

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

Dengan pengaturan var_dump()permalink yang sama /%postname%/, inilah yang Anda dapatkan

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

Saya dapat menggunakan pathdari blok kode kedua dengan get_category_by_path(), saya bisa mendapatkan objek kategori

Masalah saya adalah, bagaimana saya melakukan ini untuk istilah taksonomi.

Saya sudah melakukan tes. Saya memiliki taksonomi khusus event_cat. Jika saya menulis ulang event-slug, saya mendapatkan yang berikut pathmenggunakan /%postname%/struktur permalink

/wordpress/event-slug/5-star/

dan

event_cat=5-star

menggunakan struktur default

Secara otomatis nama taksonomi saya tidak akan ada di URL, hanya slug istilah saya. Jadi, ini bukan metode aman yang gagal untuk mendapatkan objek dari istilah tersebut.

Pertanyaan saya adalah, bagaimana cara mendapatkan struktur permalink default dengan benar mendapatkan string kueri, atau string kueri atau taksonomi dan nama istilah dari /%postname%/struktur permalink

Pieter Goosen
sumber
Ini terdengar seperti pustaka Url To Query oleh seseorang yang mungkin Anda miliki sekarang. ;)
Rarst
Mengapa kau melakukan ini? (Masalah XY)
Tom J Nowell
Terima kasih @Rarst Seharusnya tahu bahwa seseorang akan memiliki sesuatu seperti ini :-). Itu akan sesuai dengan tagihan
Pieter Goosen
Saya masih ingin melihat jawaban dari GM yang menjelaskan cara kerjanya.
Jarang,
@ TomJNowell Pada dasarnya saya perlu tahu jika posting dirujuk dari halaman istilah taksonomi, jika demikian, saya perlu tahu istilah mana. Saya perlu menghitung pos mana yang berfungsi sebagai pos berikutnya / sebelumnya. Ini hanya akan diperlukan dalam kasus jika posting memiliki beberapa istilah. Istilah tunggal di seluruh papan mudah
Pieter Goosen

Jawaban:

10

Pertama-tama saya harus mengatakan bahwa wp_get_referer()itu tidak 100% dapat diandalkan karena bergantung pada $_SERVER['HTTP_REFERER']yang tidak 100% dapat diandalkan, dari php.net docs:

Alamat halaman (jika ada) yang merujuk agen pengguna ke halaman saat ini. Ini diatur oleh agen pengguna. Tidak semua agen pengguna akan menyetel ini, dan beberapa menyediakan kemampuan untuk mengubah HTTP_REFERER sebagai fitur. Singkatnya, itu tidak bisa dipercaya.

Solusi alternatif

Jika Anda dapat menambahkan ke posting url argumen kueri yang mengatakan dari mana posting berasal, itu akan lebih dapat diandalkan dan Anda tidak perlu menguraikan url untuk mendapatkan objek istilah.

Contoh:

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

Dengan melakukan hal itu, memposting tautan permanen yang diklik dari halaman kategori akan mengirim Anda ke semacam URL

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

Dan Anda dapat dengan mudah memahami dari mana pengguna berasal tanpa mengandalkan $_SERVER['HTTP_REFERER']dan tanpa upaya lainnya.

Jawab pertanyaanmu

Dapatkan informasi permintaan mulai dari url adalah sesuatu yang dilakukan WordPress di dalam WP::parse_request()metode.

Metode itu dimaksudkan untuk digunakan hanya sekali dan hanya untuk url "utama" (url yang dilihat pengguna) dan bukan untuk url sewenang-wenang.

Beberapa bulan yang lalu saya menulis plugin Url To Query dengan tujuan untuk melakukan hal yang sama untuk url sewenang-wenang.

Apa yang saya lakukan adalah mengambil WP::parse_request(), dan mengubahnya menjadi kode OOP yang lebih waras dan membuatnya bekerja dengan url sewenang-wenang (mis. Url untuk diproses diterima sebagai argumen dan bukannya diambil dari $_SERVERvar).

Menggunakan plugin saya, Anda bisa

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

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

Jadi, Anda memperoleh argumen kueri (sesuatu yang bisa langsung Anda sampaikan new WP_Query) mulai dari url, itulah tepatnya WP::parse_request().

Dalam kasus Anda, Anda mungkin dapat memeriksa array args tanpa harus benar-benar menjalankan kueri.

Ini pasti dapat bekerja, namun saya pikir upaya tambahan yang diperlukan untuk mengurai url dan ketidakpercayaan $_SERVER['HTTP_REFERER']membuat solusi pertama yang lebih baik untuk lingkup Anda.

gmazzap
sumber
Jika saya ingin mendapatkan id posting atau siput dari pengarah .. Bagaimana saya bisa mendapatkan itu..sebagai objek permintaan tidak mengandung info itu ...
Parth Kumar
5

Tujuan asli dari pertanyaan ini adalah untuk mengetahui dari mana satu posting dirujuk dari dan kemudian sesuai dengan itu, melayani posting berikutnya dan sebelumnya sesuai dengan pengarah posting.

Apa yang ingin saya capai adalah misalnya:

Sebuah posting diklik dari kategori, taksonomi, tag, pencarian, atau halaman arsip penulis. Arsip-arsip ini berfungsi sebagai rujukan. Sekarang, biasanya orang akan menggunakan, seperti dalam pertanyaan saya, wp_get_referer()untuk mendapatkan pengarah itu dan menggunakannya dalam permintaan lebih lanjut. Seperti dijelaskan oleh @GM dalam jawaban yang diterima di atas , metode ini tidak dapat diandalkan, jadi saya pergi dan menggunakan Solusi Alternatifnya .

Masalah lain adalah perlu menggunakan beberapa jenis cookie atau sesi untuk menyimpan pengarah ini, sehingga Anda masih menayangkan posting dari pengarah asli ketika Anda menavigasi jauh dari posting tunggal asli yang diklik dari arsip tertentu. Karena cookie juga dikendalikan oleh pengguna akhir dan karenanya tidak dapat diandalkan, dan fakta bahwa WordPress tidak menggunakan sesi secara default, saya refactored tautan posting berikutnya dan sebelumnya menggunakan @GM Alternatif Solusi untuk memiliki cara yang dapat diandalkan untuk memeriksa dan menyimpan yang asli saya pengarah.

Inilah yang saya buat, dan saya harap seseorang akan menemukannya berguna dalam waktu dekat. Silakan, gunakan dan penyalahgunaan kode yang sesuai dengan kebutuhan Anda, hanya satu permintaan: tinggalkan tautan kembali ke pertanyaan ini. :-)

CATATAN KODE UNTUK MENGIKUTI

  • Kode ini cukup panjang dan intensif, jadi saya tidak akan merinci. Kode telah dikomentari dengan baik

  • Kode ini memiliki opsi untuk halaman antara posting dalam istilah yang sama, sama seperti default next_post_link()dan previous_post_link()fungsi di WordPress. Sama seperti fungsi asli, Anda harus mengatur taksonomi. Nilai default untuk in_same_termis truedan taxonomy adalahcategory

  • Yang paling penting, kode ini membutuhkan PHP 5.4+

KODE

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

}

PENGGUNAAN DALAM TEMPLAT TUNGGAL

Jika Anda tidak perlu menavigasi posting dalam istilah yang sama, mendapatkan posting dari semua jenis posting, dan menyesuaikan teks berikutnya dan sebelumnya dengan tautan Anda, Anda dapat melakukan hal berikut:

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

single_post_navigation( $args );

EDIT 1

Atas permintaan dari pos di SO, dan sebagai bagian dari @todo, saya sekarang telah memperkenalkan dukungan untuk tidak hanya menavigasi antara posting dari jenis posting saat ini, tetapi dari berbagai jenis posting yang ditetapkan oleh pengguna menggunakan post_typesparameter dalam fungsi. Silakan lihat kode yang diperbarui.

EDIT 2

Tambahkan 'suppress_filters' => true,ke WP_Queryargumen agar pagination tidak diubah oleh filter apa pun yang digunakan di dalamnyaWP_Query

Pieter Goosen
sumber