Obtenez la structure de permalien par défaut à partir de jolies URL

15

Lorsqu'un seul article est cliqué sur une page de catégorie ou d'ailleurs n'importe quelle page, vous pouvez obtenir l'URL de ce référent et l'analyser pour obtenir la chaîne de requête. Mais cela ne fonctionne qu'avec la structure de permalien par défaut

Exemple lorsque le référent est une page de catégorie:

A var_dump( parse_url( wp_get_referer() ) );donne la sortie suivante avec la structure de permalien par défaut

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

Avec la même chose var_dump()avec des permaliens définis /%postname%/, c'est ce que vous obtenez

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

Je peux utiliser le à pathpartir du deuxième bloc de code avecget_category_by_path() , je peux obtenir les objets de catégorie

Mon problème est de savoir comment procéder pour les termes de taxonomie.

J'ai fait un test. J'ai une taxonomie personnalisée event_cat. Si je le réécris event-slug, j'obtiens ce qui suit en pathutilisant /%postname%/comme structure de permalien

/wordpress/event-slug/5-star/

et

event_cat=5-star

en utilisant la structure par défaut

Automatiquement, mon nom de taxonomie ne sera pas dans l'URL, juste le slug de mon terme. Donc, ce ne sera pas une méthode très sûre pour récupérer des objets du terme.

Ma question est, comment puis-je obtenir correctement la structure de permalien par défaut obtenir la chaîne de requête, ou la chaîne de requête ou la taxonomie et le nom du terme de la /%postname%/structure de permalien

Pieter Goosen
la source
Cela ressemble à la bibliothèque Url To Query par quelqu'un que vous pourriez maintenant. ;)
Rarst
Pourquoi fais-tu ça? (Problème XY)
Tom J Nowell
Merci @Rarst Aurait dû savoir que quelqu'un aurait quelque chose comme ça :-). Cela ferait l'affaire
Pieter Goosen
J'aimerais toujours voir la réponse de GM expliquer comment cela fonctionne.
Rarst
@TomJNowell Fondamentalement, j'ai besoin de savoir si un article a été référé à partir d'une page de termes de taxonomie, si c'est le cas, j'ai besoin de savoir quel terme. J'ai besoin de calculer le poste qui servira de poste suivant / précédent. Cependant, cela ne serait nécessaire que si les messages ont plusieurs termes. Les mandats simples à tous les niveaux sont faciles
Pieter Goosen

Réponses:

10

Tout d'abord, je dois dire que ce wp_get_referer()n'est pas fiable à 100% car il repose sur ce $_SERVER['HTTP_REFERER']qui n'est pas fiable à 100%, à partir de la documentation de php.net :

Adresse de la page (le cas échéant) qui a renvoyé l'agent utilisateur à la page actuelle. Ceci est défini par l'agent utilisateur. Tous les agents utilisateurs ne le définiront pas et certains offrent la possibilité de modifier HTTP_REFERER en tant que fonctionnalité. Bref, on ne peut pas vraiment lui faire confiance.

Solution alternative

Si vous pouvez ajouter à l'URL de publication un argument de requête qui indique d'où vient la publication, elle sera plus fiable et vous n'aurez pas besoin de analyser une URL pour obtenir un objet terme.

Exemple:

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

Ce faisant, publier des permaliens cliqués sur une page de catégorie vous enverra une URL comme

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

Et vous pouvez facilement comprendre d'où vient l'utilisateur sans compter sur $_SERVER['HTTP_REFERER'] et sans aucun autre effort.

Répondez à votre question

Obtenir des informations sur les requêtes à partir d'une URL est quelque chose que WordPress fait dans le WP::parse_request() méthode.

Cette méthode est destinée à être utilisée une seule fois et uniquement pour l'URL "principale" (l'URL qu'un utilisateur affiche) et non pour les URL arbitraires.

Il y a quelques mois, j'ai écrit le plugin Url To Query dans le but de faire la même chose pour les URL arbitraires.

Ce que j'ai fait était de le prendre WP::parse_request(), de le refactoriser en un code OOP plus sain et de le faire fonctionner avec des URL arbitraires (par exemple, l'URL à traiter est reçue en tant qu'arguments au lieu d'être extraite de $_SERVERvar).

En utilisant mon plugin, vous pouvez

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

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

Ainsi, vous obtenez les arguments de requête (quelque chose que vous pouvez directement transmettre new WP_Query) à partir d'une URL, c'est exactement ce qui WP::parse_request()fait.

Dans votre cas, vous pouvez probablement vérifier le tableau args sans avoir besoin d'exécuter réellement une requête.

Cela peut certainement fonctionner, mais je pense que l'effort supplémentaire nécessaire pour analyser l'url et le manque de fiabilité de $_SERVER['HTTP_REFERER']rend la première solution meilleure pour vos étendues.

gmazzap
la source
Si je veux obtenir l'identifiant de publication ou le slug du référent .. Comment puis-je obtenir cela ... comme objet de requête ne contient pas ces informations ...
Parth Kumar
5

L'intention initiale de cette question était de savoir d'où un seul poste a été référé, puis d'après cela, de diffuser les messages suivants et précédents selon le référent.

Ce que je voulais accomplir était par exemple:

Un article est cliqué sur une page de catégorie, de taxonomie, de balise, de recherche ou d'archive d'auteur. Ces archives servent de référents. Maintenant, normalement, on utiliserait, comme dans ma question, wp_get_referer()pour obtenir ce référent et l'utiliser dans d'autres requêtes. Comme décrit par @GM dans sa réponse acceptée ci - dessus , cette méthode n'est pas fiable, alors je suis allé utiliser sa solution alternative .

L'autre problème était d'avoir besoin d'utiliser une sorte de cookie ou de session pour stocker ce référent, de sorte que vous restituiez les publications du référent d'origine lorsque vous vous éloignez de la publication unique d'origine sur laquelle vous avez cliqué à partir de l'archive spécifique. Comme les cookies sont également contrôlés par l'utilisateur final et donc non fiables, et le fait que WordPress n'utilise pas de sessions par défaut, j'ai refactorisé les liens de publication suivants et précédents en utilisant @GM Alternative Solution pour avoir un moyen fiable de vérifier et de stocker mon original référent.

C'est ce que j'ai trouvé et j'espère que quelqu'un le trouvera utile dans un avenir proche. S'il vous plaît, utilisez et abusez du code pour répondre à vos besoins, une seule demande: laissez un lien vers cette question. :-)

NOTES SUR LE CODE À SUIVRE

  • Ce code est assez long et intensif, donc je ne vais pas entrer dans les détails. Le code a été bien commenté

  • Ce code a la possibilité de paginer entre les publications dans le même terme, tout comme la valeur par défaut next_post_link()et previous_post_link()fonctionne dans WordPress. Tout comme les fonctions natives, vous devez définir la taxonomie. La valeur par défaut de in_same_termest trueet la taxonomie estcategory

  • Plus important encore, ce code nécessite PHP 5.4+

LE CODE

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

}

UTILISATION DANS DES MODÈLES UNIQUES

Si vous n'avez pas besoin de parcourir les articles dans le même terme, d'obtenir des articles de tous les types d'articles et de personnaliser le texte suivant et précédent avec votre lien, vous pouvez effectuer les opérations suivantes:

$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

À la demande d'un message sur SO, et dans le cadre d'un @todo, j'ai maintenant introduit la prise en charge non seulement pour naviguer entre les messages du type de message du message actuel, mais à partir d'un tableau de types de messages défini par l'utilisateur à l'aide de lapost_types paramètre de la fonction. Veuillez voir le code mis à jour.

EDIT 2

Ajoutez 'suppress_filters' => true,aux WP_Queryarguments afin que la pagination ne soit pas modifiée par les filtres utilisés dansWP_Query

Pieter Goosen
la source