WordPressのクエリにおける実体のパラメータをURIのリクエストや任意で取得する
仕事上の諸事情で、久しぶりにあーでもないこーでもないと唸った。
始まりは10月初頭の終わり。
いつもやり取りしている人から、(その時点では)とある要求(要望ではなく要求、大事なことなので復唱します。要望ではなく要求。)を受けてしまった。
それが表題のとおり、WordPressのクエリにおける実体のパラメータを取得するということ。
分かりやすいように言うと、
設定画面のパーマリンクで
「/%year%/%monthnum%/%day%/%postname%/」とか設定したものを、
テーマ側のメインループにおいては「?year=Y&monthnum=m&day=d&name=postname」という形に復号化して取得しろっていうこと。
これそのものが、機能の全部というわけではないが・・・まぁ、ある機能を実装するためにどうしても必要不可欠だった。
全く関係のない他のこともそこそこやっているせいか、かれこれ悩むこと結構なお時間で、さぁやるぞと悩み始めて本日で実に2週間くらいが過ぎた。
まぁその間全く何もしていなかったわけじゃない。
作業時間の合間でひたすら試行錯誤の右往左往。
ところで、URIからパラメータを変換するためのオプション値「rewrite_rules」、または、グローバル変数の$wp_rewriteから読み出せるメソッドのwp_rewrite_rules()というものがある。
まぁこの存在は一応は知っていたんだけど・・・。
まぁこれを頼りに、WordPressがURIのパラメータをどうやって変換してクエリに譲渡しているのか知るためにソースコードを読んだりとか、手がかりを探して必死こいて他サイトさんを血眼になって探していたりとかしていたが、四苦八苦。
やはり、件のオプション値といい、URIとしてはパーマリンク設定の形だが、実体として、内部ではよくある「?」から始まるパラメータを処理してWPのクエリを発行して動作させている。
とりあえずは既存の知識と合わせて、どういったメカニズムでパーマリンク設定からパラメータが割り出されるかなどはわかったが、肝心の方法は霞がかかったようにぼんやり。
というのも単純に一行二行程度の正規表現の参照と置換では、これらは復号化できないため、残念なことにうまいこといくロジックが思い浮かんでこない。
コピペ用のコードなんてあるわけもなく、自分で解決するしかない。
ヒントは十分に出ているのに、いざ書こうとすると筆・・・いや、キーボードが止まるのは実にもどかしいことだ。
・・・あれ?これって詰みじゃね??
実は、まぁ・・・その・・・いつもやり取りしている人に「自分の技量では難しい」ということはすでに伝えていたわけだけどね。
その辺りは理解を示してくれたようで、その点は非常に感謝。最悪のパターンの防衛線は築いてある。
でもこのまま放置しても、もやもやするんだよな・・・。
昨日寝る直前のうとうとしているときにコーディングの神様が俺の元に降り降りた。
神「おい、糞コーダー。何寝てるんだ?コンピュータがお前の友達じゃなかったのかぁ?」(CV:タブレット端末を孫の手にするあの赤いヤツ)
俺「うっせー!俺はこれから明日の労働者の権化というべき明日の仕事に備えて寝るんだ!コーディングやだ!きらいっ!」
神「ふはは!嫌よ嫌よも好きのうち!お前はもうコンピュータとは切っても切れぬ関係じゃねぇかぁ!」
俺「いいんだ!俺はアジア諸国に出荷されたスーパーカブのように・・・たとえ設計者が想定していなかった運用を求められても必死に働くんだ!!!」
神「本当にそれでいいのか!?そのお前のもやもやとしたものは・・・今まで取り残したままでそのまま過ごしてきたかぁ!?」
まぁそんな頭の中お花畑な茶番が本当にあったかどうかはともかく、夢うつつの状態で余計なことを考えない状態で筋道が立ったわけだけど・・・。
明鏡止水ってこういうことなのかな?
ともかく、頭の中にできたものを本日コードに写したので、散々と対して面白くもない前振りをした中で恐縮だけど掲載する。
// URIを実体のパラメータとして取得 function user_read_entity_param( $uri = '' ) { $entity = ''; $matches = array(); $request = ! empty( $uri ) ? $uri : $_SERVER['REQUEST_URI']; $rules = get_option( 'rewrite_rules' ); // 今回はオプションから参照。$wp_rewrite->wp_rewrite_rules()にするかは自由。 $home_dir = preg_replace( '~' . ( empty($_SERVER['HTTPS']) ? 'http://' : 'https://' ) . $_SERVER['HTTP_HOST'] . '~', '', get_home_url() ); $request = str_replace( $home_dir, '', preg_replace( '~/$~', '', $request ) ); foreach ( $rules as $key => $val ) { if ( preg_match( '~' . $key . '~', $request, $matches ) ) { $entity = $val; break; } } if ( ! empty( $matches ) ) { unset( $matches[0] ); foreach ( $matches as $key => $val ) { $entity = preg_replace( '~\$matches\[' . $key . '\]~', $val, $entity ); } $entity = preg_replace( '~&page=\$matches\[[0-9]{1,}\]~', '', $entity ); // 単一投稿系におけるゴミデータの削除 $entity = str_replace( '?index.php', '', $entity ); } return $entity; } // ?s=のリライトルールに対応するためにルールを追加 function user_flush_rules(){ global $wp_rewrite; $wp_rewrite->flush_rules(); } add_filter( 'init', 'user_flush_rules' ); function user_rewrite_rules_array( $rules ) { $add_rules = array( 'page/([0-9]{1,})/\?s=(.*)$' => 'index.php?paged=$matches[1]&s=$matches[2]', 'page/([0-9]{1,})/\?s$' => 'index.php?paged=$matches[1]&s=', '\?s=(.*)$' => 'index.php?s=$matches[1]', 'search/(.+)/page/?([0-9]{1,})/?$' => 'index.php?s=$matches[1]&paged=$matches[2]', 'search/(.+)/?$' => 'index.php?s=$matches[1]', '([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/page/?([0-9]{1,})/?$' => 'index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&paged=$matches[4]', '([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/?$' => 'index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]', '([0-9]{4})/([0-9]{1,2})/page/?([0-9]{1,})/?$' => 'index.php?year=$matches[1]&monthnum=$matches[2]&paged=$matches[3]', '([0-9]{4})/([0-9]{1,2})/?$' => 'index.php?year=$matches[1]&monthnum=$matches[2]', '([0-9]{4})/page/?([0-9]{1,})/?$' => 'index.php?year=$matches[1]&paged=$matches[2]', '([0-9]{4})/?$' => 'index.php?year=$matches[1]', ); $rules = array_merge( $add_rules, $rules ); return $rules; } add_filter( 'rewrite_rules_array', 'user_rewrite_rules_array' );
user_read_entity_param()を呼び出せば、多分実体のパラメータを取得できる。
関数の中身はいたって単純で、ループはrewrite_rulesをベースにして、preg_matchの第4引数とpreg_replaceを利用して順次置換。
最後にできあがったパラメータを返す。
オプション値にある置換後の値が$matchs[x]と至るところにあったが、なぜこれがこのようになっているのかという疑問は実際にこれらを利用して置換を行っていく中で自然と氷解した。
それなりにコード組んできたのに気づかない残念な頭の俺乙。
あとは検索などを行う際に、「?s」が付くことに備えたリライトルールを追加。
自分のようにざっくりとパーマリンクを設定するタイプには多分必要。
つーかいざ書いてみるとコードみじけぇ・・・。こんなもののために、俺は2週間以上もふいにしたのか。
まぁ・・・結果オーライかもしれんが・・・。
考えついたコードをそのまま写しただけなので、多分いろいろ穴はあるがそれなりに想定に近いものはできた感じ。
色んな意味でゴミゴミしたところは後で潰していくことにしよう。
で、こんなわざわざデバッグ用のプラグインを使えば「表示」できるのにあえて「取得」するようにした理由、機能の全部というわけではないと書いた理由について。
これについては、ちょっとしたクイズみたいな状態で置いておくことにする。
WebページのJavaScriptで手順を踏んでリクエストを処理して、query_posts()などの引数として突っ込めば・・・。
取得するデータの意図として、何をしようとしているかが恐らくわかると思う。
まぁ、実際にコードを使用するかどうか怪しいが、これを利用したものを作った際はまた適当に掲載しようと思う。