Ottieni la struttura di permalink predefinita da graziosi URL


15

Quando si fa clic su un singolo post da una pagina di categoria o comunque da qualsiasi pagina, è possibile ottenere l'URL di quel referrer e analizzarlo per ottenere la stringa di query. Ma questo funziona solo con la struttura permalink predefinita

Esempio quando il referrer è una pagina di categoria:

A var_dump( parse_url( wp_get_referer() ) );fornisce il seguente output con la struttura permalink predefinita

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

Con lo stesso var_dump()con permalink impostato su /%postname%/, questo è ciò che ottieni

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

Posso usare il pathdal secondo blocco di codice con get_category_by_path(), posso ottenere gli oggetti categoria

Il mio problema è, come posso fare questo per termini di tassonomia.

Ho fatto un test. Ho una tassonomia personalizzata event_cat. Se lo riscrivo event-slug, ottengo quanto segue pathusando /%postname%/come struttura permalink

/wordpress/event-slug/5-star/

e

event_cat=5-star

utilizzando la struttura predefinita

Automaticamente il mio nome di tassonomia non sarà nell'URL, ma solo nel mio termine. Quindi, questo non sarà un metodo sicuro per ottenere oggetti dal termine.

La mia domanda è: come posso ottenere correttamente la struttura di permalink predefinita ottenere la stringa di query o la stringa di query o la tassonomia e il nome del termine dalla /%postname%/struttura di permalink


Questo suona come la libreria Url To Query di qualcuno che potresti ora. ;)
Rarst

Perché stai facendo questo? (Problema XY)
Tom J Nowell

Grazie @Rarst Avrei dovuto sapere che qualcuno avrebbe avuto qualcosa del genere :-). Sarebbe perfetto
Pieter Goosen il

Mi piacerebbe ancora vedere la risposta di GM che spiega come funziona.
Rarst

@TomJNowell Fondamentalmente ho bisogno di sapere se un post è stato rinviato da una pagina dei termini della tassonomia, in tal caso, devo sapere quale termine. Devo calcolare quale post servire come post successivo / precedente. Ciò sarebbe necessario solo nel caso in cui i post abbiano più termini. Singoli termini su tutta la linea sono facili
Pieter Goosen,

Risposte:


10

Prima di tutto devo dire che wp_get_referer()non è affidabile al 100% perché si basa su $_SERVER['HTTP_REFERER']che non è affidabile al 100%, dai documenti php.net :

L'indirizzo della pagina (se presente) che rimanda l'agente utente alla pagina corrente. Questo è impostato dal programma utente. Non tutti i programmi utente lo imposteranno e alcuni offrono la possibilità di modificare HTTP_REFERER come funzionalità. In breve, non ci si può davvero fidare.

Soluzione alternativa

Se puoi aggiungere al post url un argomento di query che dice da dove proviene il post, sarà più affidabile e non dovrai analizzare un url per ottenere un oggetto termine.

Esempio:

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

In questo modo, post permalink cliccati da una pagina di categoria ti invierà a un URL come

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

E puoi facilmente capire da dove proviene l'utente senza fare affidamento $_SERVER['HTTP_REFERER']e senza alcuno sforzo.

Rispondi alla tua domanda

Ottenere informazioni sulle query a partire da un URL è qualcosa che WordPress fa all'interno del WP::parse_request()metodo.

Tale metodo deve essere utilizzato solo una volta e solo per l'URL "principale" (l'URL che un utente sta visualizzando) e non per gli URL arbitrari.

Pochi mesi fa ho scritto il plugin Url To Query con l'obiettivo di fare la stessa cosa per URL arbitrari.

Quello che ho fatto è stato prendere WP::parse_request()e riformattare in un codice OOP più sano e farlo funzionare con URL arbitrari (ad esempio, l'URL da elaborare viene ricevuto come argomento anziché essere preso da $_SERVERvar).

Usando il mio plugin puoi

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

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

Quindi ottieni gli argomenti della query (qualcosa a cui puoi passare direttamente new WP_Query) a partire da un url, questo è esattamente ciò che WP::parse_request()fa.

Nel tuo caso potresti probabilmente controllare l'array args senza la necessità di eseguire effettivamente una query.

Questo può sicuramente funzionare, tuttavia penso che lo sforzo aggiuntivo necessario per analizzare l'URL e l'inaffidabilità di $_SERVER['HTTP_REFERER']renda la prima soluzione migliore per i tuoi scopi.


Se voglio ottenere il post ID o la lumaca dal referente .. Come posso ottenerlo ... come oggetto query non contiene quell'informazione ...
Parth Kumar

5

L'intenzione originale di questa domanda era di sapere da dove veniva rinviato un singolo post e quindi, secondo quello, servire i post successivi e precedenti in base al referrer post.

Quello che volevo realizzare era ad esempio:

Si fa clic su un post da una pagina di categoria, tassonomia, tag, ricerca o archivio autore. Questi archivi servono come referrer. Ora, normalmente uno userebbe, come nella mia domanda, wp_get_referer()per ottenere quel referrer e usarlo in ulteriori query. Come descritto da @GM nella sua risposta accettata sopra , questo metodo non è affidabile, quindi sono andato e ho usato la sua soluzione alternativa .

L'altro problema era la necessità di utilizzare un qualche tipo di cookie o sessione per memorizzare questo referrer, in modo che continui a inviare post dal referrer originale quando esci dal singolo post originale su cui è stato fatto clic dall'archivio specifico. Poiché i cookie sono controllati anche dall'utente finale e quindi non sono affidabili e il fatto che WordPress non utilizzi le sessioni per impostazione predefinita, ho rifattorizzato i collegamenti post successivo e precedente utilizzando @GM Alternative Solution per avere un modo affidabile di controllare e archiviare il mio originale referrer.

Questo è quello che mi è venuto in mente e spero che qualcuno lo troverà utile in un prossimo futuro. Per favore, usa e abusa del codice per soddisfare le tue esigenze, una sola richiesta: lascia un link a questa domanda. :-)

NOTE SUL CODICE DA SEGUIRE

  • Questo codice è piuttosto lungo e intenso, quindi non entrerò nei dettagli. Il codice è stato ben commentato

  • Questo codice ha la possibilità di sfogliare tra i post nello stesso termine, proprio come l'impostazione predefinita next_post_link()e le previous_post_link()funzioni in WordPress. Proprio come le funzioni native, devi impostare la tassonomia. Il valore predefinito per in_same_termè truee la tassonomia ècategory

  • Ancora più importante, questo codice richiede PHP 5.4+

IL CODICE

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

}

UTILIZZO IN SINGOLI MODELLI

Se non è necessario navigare tra i post nello stesso termine, ottenere post da tutti i tipi di post e personalizzare il testo successivo e precedente con il collegamento, è possibile effettuare le seguenti operazioni:

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

single_post_navigation( $args );

MODIFICA 1

Su richiesta di un post su SO, e come parte di un @todo, ho ora introdotto il supporto non solo per navigare tra i post dal tipo di post corrente, ma da una serie di tipi di post impostati dall'utente usando il post_typesparametro nella funzione. Si prega di consultare il codice aggiornato.

MODIFICA 2

Aggiungi 'suppress_filters' => true,agli WP_Queryargomenti in modo che l'impaginazione non venga modificata da alcun filtro utilizzato all'internoWP_Query

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.