web-dev-qa-db-ja.com

URLからWP_Queryパラメータを決定する

与えられたページURLを使って only によってWP_Queryパラメータを決定することが可能かどうか私は思っています。これは、SPAテーマ(そして最終的にはJSONレスポンス)を開発していて、ページを再ロードせずにクエリを決定できる必要があるためです。

これはかなり厄介だと思いました。私は、単一の投稿クエリが何であるべきかを判断するために、投稿URLとパーマリンク構造を組み合わせることに成功しました。

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

上記の関数を使用して、私はajax呼び出しを実行するためにurlをパラメータとして渡すことができます、そしてそれはWP_Queryパラメータを見つけるためにそれを解析します。

したがって、http://example.com/blog/my-first-post/のようなURLはname => 'my-first-post'を抽出するために解析され、http://example.com/?p=124のようなURLはp => 124を抽出するために解析されます。これはWP_Queryなどに渡されます。 FTR、私は物事を安全に保つためにpost_statushas_passwordのようなブラックリストに載っているパラメータも削除します。

きれいなURL構造を解析するために、パスの構成要素を取ります。/2014/07/hello-world/の場合、 2014 07 、および hello-world のようになります。これらをset permalink構造体と比較します。この場合、それは/%year%/%monthnum%/%postname%/になります - そして、いくつかのpermalinkタグはWP_Queryでは動作しないので、私はいくらかの変換をします。たとえば、postnamenameになります。

とにかく ...私はページにたどり着くまで、良いスタートを切ったように感じました。上記のコードではhttp://example.com/about/のようなページURLと上記のパーマリンク構造で抽出されるパラメータはyear => 'about'になります。良くない。

私がこれにどのように取り組むべきかについてのガイダンスを誰かが持っているならば、それは ずっと になるでしょう。また、私がこれにすべて間違って近づいているかどうか私に知らせてください。ページをリロードせずにクエリを決定するだけです。

2
Jody Heavener

2014年7月7日6:28に編集


あなたのアプローチには多くの落とし穴があります。カスタム書き換えルールがある場合は機能しません。サーバーがIISであり、かなりパーマリンクがアクティブである場合は(おそらく)機能しません。カスタム投稿タイプでは機能せず、アーカイブでは機能しませんまたは検索URLなど。

手頃な方法でURLから歌のポスト/ページURLを取得するには、関数 url_to_postid があります。

$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
}

単一の投稿(CPTでも)またはページのURLのみに関心がある場合は、おそらく上記の数行が必要なものだけですが、WordPressのすべての種類のURLを解析する必要がある場合は、他の何か、そして本当に簡単なものではありません。

手頃な方法でURLからクエリ変数を取得する唯一の方法は、WordPressがURLの解析に使用する方法を再現することです。

これは、WPクラスのメソッド parse_request によってコアで行われます。

ただし、上記で説明した目的のためにこのメソッドを使用することは、以下の理由で困難/非推奨です。

  • $_SERVER$_POST、および$_GET変数に直接アクセスし、現在のHTTPリクエストに関連しない任意のURLの解析を困難にします
  • 現在のHTTPリクエストの解析に厳密に関連するいくつかのアクションフックをトリガーします。これは、任意のURLに対してトリガーする意味がありません
  • グローバル$wp変数のプロパティにアクセスして変更しますが、これらのプロパティはリクエストの解析後は変更しないでください。

できることは、そこのコードから開始し、不要な部分を削除し、現在のHTTPリクエストのURLではなく任意のURLを使用するようにすることです。

コアのparse_requestメソッドは214行(v。3.9.1)であり、その作業は非常に苦痛ですが、幸いにもsomeoneはすでに大変な作業を行っています。 こちら

5
gmazzap

良いメカニズムと奇妙なメカニズムを使った簡単な解決策があります。

良い部分

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

奇妙な部分

/* 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