Obter estrutura permalink padrão de URLs bonitas


15

Quando uma única postagem é clicada em uma página de categoria ou, em qualquer caso, em qualquer página, você pode obter o URL desse referenciador e analisá-lo para obter a string de consulta. Mas isso só funciona com a estrutura permalink padrão

Exemplo quando o referenciador é uma página de categoria:

A var_dump( parse_url( wp_get_referer() ) );fornece a seguinte saída com a estrutura de ligação permanente padrão

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

Com o mesmo var_dump()conjunto de links permanentes definido /%postname%/, é isso que você obtém

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

Eu posso usar o pathdo segundo bloco de código com get_category_by_path(), posso obter os objetos de categoria

Meu problema é: como faço para fazer isso em termos de taxonomia.

Eu fiz um teste. Eu tenho uma taxonomia personalizada event_cat. Se eu reescrevê-lo event-slug, recebo o seguinte pathusando /%postname%/como estrutura de link permanente

/wordpress/event-slug/5-star/

e

event_cat=5-star

usando a estrutura padrão

Automaticamente, meu nome de taxonomia não estará no URL, apenas a lesma do meu termo. Portanto, esse não será um método muito seguro de obter objetos do termo.

Minha pergunta é: como faço para obter corretamente a estrutura de link permanente padrão obter a string de consulta ou a string de consulta ou a taxonomia e o nome do termo da /%postname%/estrutura de link permanente


Parece a biblioteca Url para consulta de alguém que você possa agora. ;)
Primeiro

Por que você está fazendo isso? (Problema XY)
Tom J Nowell

Obrigado @Rarst Deveria saber que alguém teria algo assim :-). Que caberia a conta
Pieter Goosen

Eu ainda gostaria de ver a resposta da GM explicando como funciona.
Rarst

@ TomJNowell Basicamente, preciso saber se uma postagem foi referida a partir de uma página de termos de taxonomia; nesse caso, preciso saber qual termo. Preciso calcular qual post servir como próximo / post anterior. Isso só seria necessário se as postagens tiverem vários termos. Termos individuais através da placa é fácil
Pieter Goosen

Respostas:


10

Antes de tudo, devo dizer que wp_get_referer()não é 100% confiável, porque depende $_SERVER['HTTP_REFERER']disso não é 100% confiável, a partir do php.net docs:

O endereço da página (se houver) que encaminhou o agente do usuário à página atual. Isso é definido pelo agente do usuário. Nem todos os agentes do usuário definirão isso, e alguns oferecem a capacidade de modificar o HTTP_REFERER como um recurso. Em suma, não pode realmente ser confiável.

Solução alternativa

Se você pode adicionar ao URL da postagem um argumento de consulta que diga de onde vem a postagem, será mais confiável e você não precisará analisar uma URL para obter um objeto de termo.

Exemplo:

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

Com isso, os permalinks de postagem clicados em uma página de categoria o enviarão a um URL como

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

E você pode entender facilmente de onde o usuário vem sem confiar $_SERVER['HTTP_REFERER']e sem nenhum outro esforço.

Responda sua pergunta

Obter informações de consulta a partir de um URL é algo que o WordPress faz dentro do WP::parse_request()método.

Esse método deve ser usado apenas uma vez e apenas para o URL "principal" (o URL que um usuário está visualizando) e não para URLs arbitrários.

Alguns meses atrás, eu escrevi o plugin Url To Query com o objetivo de fazer a mesma coisa para URLs arbitrários.

O que fiz foi pegar WP::parse_request()e refatorá-lo para um código OOP mais sensato e fazê-lo funcionar com URLs arbitrários (por exemplo, o URL para processar é recebido como argumentos em vez de ser retirado de$_SERVER var).

Usando meu plugin, você pode

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

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

Então você obtém os argumentos da consulta (algo para o qual você pode passar diretamente new WP_Query) a partir de um URL, é exatamente issoWP::parse_request() isso faz.

No seu caso, você provavelmente pode verificar a matriz args sem precisar executar uma consulta.

Isso certamente pode funcionar, no entanto, acho que o esforço adicional necessário para analisar o URL e a falta de confiabilidade $_SERVER['HTTP_REFERER']tornam a primeira solução melhor para seus escopos.


Se eu quiser obter o cargo Id ou lesma do referer .. Como posso obter that..as objeto de consulta does not conter essa informação ...
Parth Kumar

5

A intenção original dessa pergunta era saber de onde uma única postagem foi referida e, de acordo com isso, servir as próximas e as anteriores de acordo com o referenciador da postagem.

O que eu queria realizar era, por exemplo:

Uma postagem é clicada em uma página de categoria, taxonomia, tag, pesquisa ou arquivo de autor. Esses arquivos servem como referenciadores. Agora, normalmente, seria usado, como na minha pergunta, wp_get_referer()para obter esse referenciador e usá-lo em consultas adicionais. Conforme descrito por @GM em sua resposta aceita acima , esse método não é confiável, então fui e usei sua Solução Alternativa .

O outro problema era a necessidade de usar algum tipo de cookie ou sessão para armazenar esse referenciador, para que você ainda divulgue as postagens do referenciador original quando sair da postagem única original que foi clicada no arquivo específico. Como os cookies também são controlados pelo usuário final e, portanto, não são confiáveis, e o fato de o WordPress não usar sessões por padrão, refatorei os links de postagem seguinte e anterior usando o @GM Alternative Solution para ter uma maneira confiável de verificar e armazenar meu original referenciador.

Foi isso que eu criei, e espero que alguém ache útil no futuro próximo. Por favor, use e abuse do código para atender às suas necessidades, apenas uma solicitação: deixe um link para esta pergunta. :-)

NOTAS SOBRE O CÓDIGO A SEGUIR

  • Esse código é bastante longo e intenso, então não vou entrar em detalhes. O código foi bem comentado

  • Este código tem a opção de paginar entre as postagens dentro do mesmo termo, assim como o padrão next_post_link()e as previous_post_link()funções no WordPress. Assim como as funções nativas, você deve definir a taxonomia. O valor padrão para in_same_termé truee a taxonomia écategory

  • Mais importante ainda, esse código requer PHP 5.4+

O CÓDIGO

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

}

USO EM MODELOS ÚNICOS

Se você não precisar navegar pelas postagens no mesmo termo, obter postagens de todos os tipos de post e personalizar o texto seguinte e anterior com o seu link, faça o seguinte:

$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

A pedido de uma postagem no SO e como parte de uma @todo, introduzi agora o suporte para não apenas navegar entre as postagens do tipo de postagem atual, mas também de uma variedade de tipos de postagem definidos pelo usuário usando o métodopost_types parâmetro na função Por favor, veja o código atualizado.

EDIT 2

Adicione 'suppress_filters' => true,aos WP_Queryargumentos para que a paginação não seja alterada por nenhum filtro usado dentroWP_Query

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.