web-dev-qa-db-fra.com

Déterminer les paramètres WP_Query à partir d'une URL

Je me demande s'il est possible de déterminer les paramètres WP_Query avec seulement en utilisant l'URL de la page donnée. J'essaie de le faire parce que je développe un thème SPA (et finalement une réponse JSON) et que je devrais être en mesure de déterminer une requête sans recharger la page.

Bien que ce soit assez difficile, j'ai réussi à associer une URL de publication à la structure Permalink afin de déterminer ce que devrait être une requête de publication unique:

<?php

function api_query_url() {

  // Check that the URL is set and is in fact a string
  if ( ! isset( $_POST['url'] ) || gettype( $_POST['url'] ) !== 'string' ) {
    api_response( false, 400, "'url' is a required parameter!" );
  }

  // Parse the URL for parameters and path
  $query_url = parse_url( $_POST['url'] );

  // Pass query-based URL directly to Single API request
  if ( isset( $query_url['query'] ) ) {
    api_single( $query_url['query'] );
  }

  // Map Permalink structure tags to WP_Query parameters
  $structure_refs = array(
    'year'     => 'year',
    'monthnum' => 'monthnum',
    'day'      => 'day',
    'hour'     => 'hour',
    'minute'   => 'minute',
    'second'   => 'second',
    'post_id'  => 'p',
    'postname' => 'name',
    'category' => 'category_name',
    'author'   => 'author_name'
  );

  // Retreive the site's Permalink Structure and break it in to an array
  $structure = array_filter( explode( '/', get_option( 'permalink_structure' ) ) );

  // Break our query parameters in to an array
  $query_params = array_filter( explode( '/', $query_url['path'] ) );

  // Set up an empty query array
  $query = array();

  // For each query parameter received
  foreach ($query_params as $param) {

    // Using the parameter value's position, locate its corresponding structure key
    $key_position  = array_search( $param, $query_params );
    $structure_key = str_replace( '%', '', $structure[$key_position] );

    // If the structure key exists in the structure references, add to to the query
    if ( array_key_exists( $structure_key, $structure_refs) ) {
      $query[$structure_refs[$structure_key]] = $param;
    }
  }

  // Pass off to Query handler to create JSON response
  api_single( $query );

}
add_action( 'wp_ajax_nopriv_api_query_url', 'api_query_url' );

En utilisant la fonction ci-dessus, je peux passer url en tant que paramètre pour effectuer un appel ajax. Il sera ensuite analysé pour rechercher les paramètres WP_Query.

Ainsi, une URL telle que http://example.com/blog/my-first-post/ sera analysée pour extraire name => 'my-first-post' et une URL telle que http://example.com/?p=124 sera analysée pour extraire p => 124. Ceci est ensuite passé à un WP_Query et ainsi de suite. FTR, je supprime également tous les paramètres de la liste noire, tels que post_status ou has_password, dans le but de protéger les données.

Afin d'analyser une jolie structure d'URL, je prends les composants du chemin, donc pour /2014/07/hello-world/ nous obtenons 2014 , 07 , et hello-world , puis Je les compare à la structure permalink définie, qui dans ce cas serait /%year%/%monthnum%/%postname%/ - et comme certaines balises permalink ne fonctionnent pas avec WP_Query, je fais une conversion; Par exemple, postname serait name.

Quoi qu'il en soit ... j'avais l'impression d'avoir pris un bon départ, jusqu'à ce que je me précipite dans les pages. Avec mon code ci-dessus, une URL de page telle que http://example.com/about/ et la structure permalien ci-dessus, les paramètres extraits seraient year => 'about'. Pas bon.

Si quelqu'un a des indications sur la façon dont je devrais aborder cela, ce serait beaucoup apprécié. Aussi, s'il vous plaît laissez-moi savoir si j'aborde tout cela de travers. Je dois juste déterminer une requête sans recharger la page.

2
Jody Heavener

Édité le 07 juillet 2014 à 6:28


Votre approche comporte beaucoup de pièges. Cela ne fonctionnera pas s'il existe une règle de réécriture personnalisée, cela (probablement) ne fonctionnera pas si le serveur est IIS et si les permaliens sont actifs, cela ne fonctionnera pas pour les types de publication personnalisés, cela ne fonctionnera pas pour les archives ou rechercher des URL et ainsi de suite.

Pour obtenir une URL de publication/page à partir d'une URL de manière abordable, vous devez utiliser la fonction url_to_postid , par exemple.

$id = url_to_postid( $query_url['path'] );

if ( is_numeric( $id ) && (int) $id > 0 ) {
  // the required post id is: $id
} else {
  // the url is not for a single post, may be an archive url, a search url or even
  // a non-valid 404 url
}

Si vous êtes intéressé uniquement si vous avez un seul message (même CPT) ou des URL de page, alors les quelques lignes ci-dessus sont probablement la seule chose dont vous avez besoin, mais si vous devez analyser toutes sortes d’URL WordPress, vous avez besoin de quelque chose d’autre, mais ce n’est pas le cas. quelque chose de vraiment facile.

Le seul moyen d'obtenir des vars de requête à partir d'une URL de manière abordable consiste à reproduire la méthode utilisée par WordPress pour analyser une URL.

Cela se fait en core par la méthode parse_request de la classe WP.

Cependant, l’utilisation de cette méthode pour notre objectif expliqué ci-dessus est difficile/déconseillée pour les raisons suivantes:

  • il accède directement aux variables $_SERVER, $_POST et $_GET, ce qui rend difficile l'analyse des URL arbitraires non liées à la requête HTTP actuelle
  • il déclenche des points d'ancrage liés strictement à l'analyse actuelle des requêtes HTTP, ce qui n'a aucun sens de déclencher des URL arbitraires
  • il accède aux propriétés de la variable globale $wp et les modifie; celles-ci ne doivent pas être changées une fois la requête analysée ou très probablement, des choses se casseront.

Ce que nous pouvons faire, c'est partir du code là-bas, supprimer les parties dont nous n'avons pas besoin et faire en sorte que le code utilise une URL arbitraire au lieu de celle de la requête HTTP actuelle.

La méthode de base parse_request a une longueur de 214 lignes (v. 3.9.1) et faire ce travail peut être très pénible, mais heureusement, quelqu'un a déjà fait le travail, voir ici .

5
gmazzap

Il existe une solution simple utilisant un mécanisme bon et un mécanisme étrange.

La bonne partie

function api_query_url()
{
  // Check that the URL is set and is in fact a string
  if ( ! isset( $_POST['url'] ) || gettype( $_POST['url'] ) !== 'string' ) {
    api_response( false, 400, "'url' is a required parameter!" );
  }

  // Add an extra parameter to the url.
  $api_url = add_query_arg( 'json_vars', time(), $_POST['url'] );

  $request = wp_remote_request( $api_url );
  $content = wp_remote_retrieve_body( $request );

  if( is_wp_error($content) ){
    api_response( false, 400, "couldn't retrive the data" );
  }

  if( !empty($content) )
      $vars = json_decode( $content );
  else
      $vars = array();

  // pass the array to your function
  api_single( $vars );
}
add_action( 'wp_ajax_nopriv_api_query_url', 'api_query_url' );  

La partie étrange

/* Comparing the extra parameter (json_vars), we return the json of the vars & no html */
function api_parse_request( $q )
{
    /* home/front-page doesn't have any q-vars */
    /* so you might be setting some defaults for that */
    $vars = $q->query_vars;
    if( isset($_REQUEST['json_vars']) ){
        echo json_encode( $vars );
        die();
    }
}
add_action( 'parse_request', 'api_parse_request' );
1
Shazzad