Uzyskaj domyślną strukturę bezpośredniego łącza z ładnych adresów URL

15

Po kliknięciu pojedynczego wpisu na stronie kategorii lub w tym przypadku na dowolnej stronie, możesz uzyskać adres URL odnośnika i przeanalizować go, aby uzyskać ciąg zapytania. Ale działa to tylko z domyślną strukturą permalink

Przykład, gdy strona odsyłająca jest stroną kategorii:

A var_dump( parse_url( wp_get_referer() ) );daje następujące dane wyjściowe z domyślną strukturą bezpośredniego połączenia

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

Przy tym samym var_dump()ustawieniu permalinków na /%postname%/to, otrzymujesz

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

Mogę użyć pathz drugiego bloku kodu z get_category_by_path(), mogę uzyskać obiekty kategorii

Mój problem polega na tym, jak mam to zrobić dla warunków taksonomicznych.

Zrobiłem test. Mam niestandardową taksonomię event_cat. Jeśli przepiszę to event-slug, otrzymam następujące, pathużywając /%postname%/struktury permalink

/wordpress/event-slug/5-star/

i

event_cat=5-star

przy użyciu domyślnej struktury

Automatycznie moja nazwa taksonomii nie będzie w adresie URL, tylko ślimak mojego terminu. Tak więc nie będzie to bardzo bezpieczna metoda pobierania obiektów z tego terminu.

Moje pytanie brzmi: jak prawidłowo uzyskać domyślną strukturę permalink, uzyskać ciąg zapytania, ciąg zapytania lub nazwę systematyki i terminu ze /%postname%/struktury permalink

Pieter Goosen
źródło
To brzmi jak biblioteka Url To Query przez kogoś, kogo możesz teraz. ;)
Rarst
Dlaczego to robisz? (Problem XY)
Tom J Nowell
Dzięki @Rarst Powinienem wiedzieć, że ktoś miałby coś takiego :-). To by pasowało do rachunku
Pieter Goosen
Nadal chciałbym zobaczyć odpowiedź od GM wyjaśniającą, jak to działa.
Rarst
@TomJNowell Zasadniczo muszę wiedzieć, czy post został skierowany ze strony terminów taksonomicznych, jeśli tak, muszę wiedzieć, który termin. Muszę obliczyć, który post ma służyć jako następny / poprzedni post. Byłoby to konieczne tylko w przypadku, gdy posty zawierają wiele terminów. Pojedyncze terminy na całym forum są łatwe
Pieter Goosen,

Odpowiedzi:

10

Po pierwsze muszę powiedzieć, że wp_get_referer()nie jest w 100% wiarygodny, ponieważ polega na $_SERVER['HTTP_REFERER']tym, że nie jest w 100% wiarygodny, z dokumentacji php.net :

Adres strony (jeśli istnieje), który odsyłał agenta użytkownika do bieżącej strony. Ustawia to agent użytkownika. Nie wszystkie programy użytkownika to ustawią, a niektóre zapewniają możliwość modyfikacji HTTP_REFERER jako funkcji. Krótko mówiąc, nie można tak naprawdę ufać.

Alternatywne rozwiązanie

Jeśli możesz dodać do adresu URL argument zapytania, który mówi, skąd pochodzi post, będzie on bardziej niezawodny i nie będziesz musiał analizować adresu URL, aby uzyskać obiekt terminu.

Przykład:

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

W ten sposób bezpośrednie linki kliknięte na stronie kategorii wyślą cię do adresu URL podobnego do

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

Możesz łatwo zrozumieć, skąd pochodzi użytkownik, nie polegając na $_SERVER['HTTP_REFERER']żadnym innym wysiłku i bez niego.

Odpowiedz na pytanie

Pobieranie informacji o zapytaniach zaczynając od adresu URL jest czymś, co WordPress robi wewnątrz WP::parse_request()metody.

Ta metoda jest przeznaczona do użycia tylko raz i tylko dla „głównego” adresu URL (adresu URL, który przegląda użytkownik), a nie dla dowolnych adresów URL.

Kilka miesięcy temu napisałem wtyczkę Url To Query, aby zrobić to samo dla dowolnych adresów URL.

To, co zrobiłem, to wziąć i przekształcić go WP::parse_request()w bardziej rozsądny kod OOP i sprawić, by działał z dowolnymi adresami URL (np. Adres URL do przetworzenia jest odbierany jako argument zamiast zamiast z $_SERVERvar).

Za pomocą mojej wtyczki możesz

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

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

Otrzymujesz więc argumenty zapytania (coś, co możesz bezpośrednio przekazać new WP_Query), zaczynając od adresu URL, czyli dokładnie to, co WP::parse_request()robi.

W twoim przypadku prawdopodobnie możesz sprawdzić tablicę args bez potrzeby uruchamiania zapytania.

To z pewnością może działać, jednak uważam, że dodatkowy wysiłek potrzebny do przeanalizowania adresu URL i niewiarygodności $_SERVER['HTTP_REFERER'] sprawia, że ​​pierwsze rozwiązanie jest lepsze dla twoich zakresów.

gmazzap
źródło
Jeśli chcę dostać identyfikator posta lub ślimaka od osoby polecającej .. Jak mogę to uzyskać ... obiekt zapytania nie zawiera tych informacji ...
Parth Kumar 30.04.16
5

Pierwotnym zamiarem tego pytania było wiedzieć, skąd skierowano pojedynczy post, a następnie zgodnie z tym, obsłużyć kolejne i poprzednie posty zgodnie z polecającym post.

Chciałem na przykład:

Kliknięcie posta następuje na stronie kategorii, taksonomii, tagu, wyszukiwania lub archiwum autora. Te archiwa służą jako strony odsyłające. Teraz normalnie można by użyć, tak jak w moim pytaniu, wp_get_referer()aby uzyskać odnośnika i użyć go w dalszych zapytaniach. Jak opisano przez @GM w jego zaakceptowanej odpowiedzi powyżej , ta metoda nie jest niezawodna, więc skorzystałem z jego alternatywnego rozwiązania .

Innym problemem było użycie jakiegoś pliku cookie lub sesji do przechowywania tego odsyłacza, aby nadal wyświetlać posty od oryginalnego odsyłacza, gdy odsuwasz się od oryginalnego pojedynczego wpisu, który został kliknięty w określonym archiwum. Ponieważ pliki cookie są również kontrolowane przez użytkownika końcowego, a zatem nie są wiarygodne, a fakt, że WordPress domyślnie nie używa sesji, zmieniłem linki do następnego i poprzedniego postu za pomocą @GM Alternative Solution, aby mieć niezawodny sposób sprawdzania i przechowywania mojej oryginalnej polecający.

Właśnie to wymyśliłem i mam nadzieję, że ktoś okaże się przydatny w najbliższej przyszłości. Używaj i nadużywaj kodu, aby dopasować go do swoich potrzeb, tylko jedna prośba: zostaw link z powrotem do tego pytania. :-)

UWAGI DOTYCZĄCE KODU OBSERWUJĄCEGO

  • Ten kod jest dość długi i intensywny, więc nie będę wchodził w szczegóły. Kod został dobrze skomentowany

  • Ten kod ma opcję stronicowania między postami w tym samym terminie, podobnie jak domyślny next_post_link()i previous_post_link()działa w WordPress. Podobnie jak funkcje natywne, musisz ustawić taksonomię. Domyślna wartość in_same_termto, truea taksonomia tocategory

  • Co najważniejsze, ten kod wymaga PHP 5.4+

KOD

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

}

WYKORZYSTANIE W JEDNYM SZABLONIE

Jeśli nie musisz poruszać się po postach w tym samym terminie, uzyskiwać posty ze wszystkich typów postów i dostosowywać następny i poprzedni tekst za pomocą linku, możesz wykonać następujące czynności:

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

single_post_navigation( $args );

EDYCJA 1

Na żądanie od posta na SO oraz w ramach a @todo, wprowadziłem obsługę nie tylko nawigacji między postami z bieżącego typu posta, ale z tablicy typów postów ustawionych przez użytkownika za pomocąpost_types parametru w funkcji. Zobacz zaktualizowany kod.

EDYCJA 2

Dodaj 'suppress_filters' => true,do WP_Queryargumentów, aby podział na strony nie był zmieniany przez żadne filtry użyte w ciąguWP_Query

Pieter Goosen
źródło