Obtenga la estructura de enlace permanente predeterminada de las URL bonitas

15

Cuando se hace clic en una sola publicación desde una página de categoría o en cualquier otra página, puede obtener la URL de ese referente y analizarla para obtener la cadena de consulta. Pero esto solo funciona con la estructura de enlace permanente predeterminada

Ejemplo cuando el referente es una página de categoría:

A var_dump( parse_url( wp_get_referer() ) );da el siguiente resultado con la estructura de enlace permanente predeterminada

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

Con lo mismo var_dump()con los enlaces permanentes establecidos /%postname%/, esto es lo que obtienes

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

Puedo usar pathdesde el segundo bloque de código con get_category_by_path(), puedo obtener los objetos de categoría

Mi problema es cómo hago esto para los términos de taxonomía.

He hecho una prueba. Tengo una taxonomía personalizada event_cat. Si lo reescribo event-slug, obtengo lo siguiente pathusando /%postname%/como estructura de enlace permanente

/wordpress/event-slug/5-star/

y

event_cat=5-star

usando la estructura predeterminada

Automáticamente mi nombre de taxonomía no estará en la URL, solo la babosa de mi término. Por lo tanto, este no será un método muy seguro para obtener objetos del término.

Mi pregunta es, ¿cómo obtengo correctamente la estructura de enlace permanente predeterminada para obtener la cadena de consulta, o la cadena de consulta o la taxonomía y el nombre del término de la /%postname%/estructura de enlace permanente

Pieter Goosen
fuente
Esto suena como la biblioteca Url To Query de alguien que tal vez ahora. ;)
Rarst
¿Por qué estás haciendo esto? (Problema XY)
Tom J Nowell
Gracias @Rarst Debería haber sabido que alguien tendría algo como esto :-). Eso encajaría bien
Pieter Goosen
Todavía me gustaría ver la respuesta de GM explicando cómo funciona.
Rarst
@TomJNowell Básicamente necesito saber si una publicación fue referida desde una página de términos de taxonomía, si es así, necesito saber qué término. Necesito calcular qué publicación sirve como la publicación siguiente / anterior. Sin embargo, esto solo sería necesario en el caso si las publicaciones tienen varios términos. Los términos individuales en todos los ámbitos son fáciles
Pieter Goosen el

Respuestas:

10

En primer lugar, tengo que decir que wp_get_referer()no es 100% confiable porque se basa en $_SERVER['HTTP_REFERER']que no es 100% confiable, de los documentos de php.net :

La dirección de la página (si la hay) que refirió al agente de usuario a la página actual. Esto lo establece el agente de usuario. No todos los agentes de usuario configurarán esto, y algunos brindan la posibilidad de modificar HTTP_REFERER como una característica. En resumen, realmente no se puede confiar.

Solución alternativa

Si puede agregar a la URL de publicación un argumento de consulta que indique de dónde proviene la publicación, será más confiable y no necesitará analizar una URL para obtener un objeto de término.

Ejemplo:

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

Al hacerlo, publicar enlaces permanentes en una página de categoría te enviará a una URL como

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

Y puede comprender fácilmente de dónde viene el usuario sin depender $_SERVER['HTTP_REFERER']y sin ningún otro esfuerzo.

Responde tu pregunta

Obtener información de consulta a partir de una URL es algo que WordPress hace dentro del WP::parse_request()método.

Ese método está destinado a ser utilizado solo una vez y solo para la url "principal" (la url que está viendo un usuario) y no para url arbitrarias.

Hace unos meses escribí el complemento Url To Query con el objetivo de hacer lo mismo para las URL arbitrarias.

Lo que hice fue tomar WP::parse_request()y refactorizarlo a un código OOP más sensato y hacerlo funcionar con URL arbitrarias (por ejemplo, la url para procesar se recibe como argumentos en lugar de tomarse de $_SERVERvar).

Usando mi plugin puedes

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

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

Entonces obtienes los argumentos de consulta (algo a lo que puedes pasar directamente new WP_Query) a partir de una URL, eso es exactamente lo que WP::parse_request()hace.

En su caso, probablemente podría verificar la matriz de args sin necesidad de ejecutar una consulta.

Sin duda, esto puede funcionar, sin embargo, creo que el esfuerzo adicional necesario para analizar la URL y la falta de fiabilidad $_SERVER['HTTP_REFERER']hacen que la primera solución sea mejor para sus alcances.

gmazzap
fuente
Si quiero obtener el ID del anuncio o babosa del árbitro .. ¿Cómo puedo obtener that..as objeto de consulta duerma contiene esa información ...
Parth Kumar
5

La intención original de esta pregunta era saber de dónde se refería una sola publicación y, de acuerdo con eso, servir las publicaciones siguientes y anteriores de acuerdo con el remitente de la publicación.

Lo que quería lograr era, por ejemplo:

Se hace clic en una publicación desde una categoría, taxonomía, etiqueta, búsqueda o página de archivo del autor. Estos archivos sirven como referentes. Ahora, normalmente se usaría, como en mi pregunta, wp_get_referer()para obtener ese referente y usarlo en consultas adicionales. Según lo descrito por @GM en su respuesta aceptada anteriormente , este método no es confiable, así que fui y usé su Solución alternativa .

El otro problema fue la necesidad de utilizar algún tipo de cookie o sesión para almacenar este referente, de modo que aún pueda publicar publicaciones del referente original cuando navega fuera de la publicación única original en la que se hizo clic desde el archivo específico. Como las cookies también son controladas por el usuario final y, por lo tanto, no son confiables, y el hecho de que WordPress no usa sesiones de forma predeterminada, refactoré los enlaces de publicaciones siguientes y anteriores utilizando @GM Alternative Solution para tener una forma confiable de verificar y almacenar mi original referente.

Esto es lo que se me ocurrió, y espero que alguien lo encuentre útil en el futuro cercano. Utilice y abuse del código para satisfacer sus necesidades, solo una solicitud: deje un enlace a esta pregunta. :-)

NOTAS SOBRE EL CÓDIGO A SEGUIR

  • Este código es bastante largo e intenso, por lo que no voy a entrar en detalles. El código ha sido bien comentado

  • Este código tiene la opción de paginar entre publicaciones dentro del mismo término, al igual que el predeterminado next_post_link()y previous_post_link()funciona en WordPress. Al igual que las funciones nativas, debe establecer la taxonomía. El valor predeterminado para in_same_termes truey la taxonomía escategory

  • Lo más importante, este código requiere PHP 5.4+

EL 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 EN PLANTILLAS INDIVIDUALES

Si no necesita navegar por las publicaciones dentro del mismo término, obtener publicaciones de todos los tipos de publicaciones y personalizar el texto siguiente y anterior con su enlace, puede hacer lo siguiente:

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

single_post_navigation( $args );

EDITAR 1

A pedido de una publicación en SO, y como parte de una @todo, ahora he introducido soporte para navegar no solo entre las publicaciones del tipo de publicación de la publicación actual, sino también desde una matriz de tipos de publicaciones establecidas por el usuario usando el post_typesparámetro en la función. Por favor vea el código actualizado.

EDITAR 2

Agregue 'suppress_filters' => true,a los WP_Queryargumentos para que la paginación no sea alterada por ningún filtro utilizado enWP_Query

Pieter Goosen
fuente