かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

WordPress サブテーマ テーマの絶対パスを取得したい。

WordPressでテーマのディレクトリの絶対パス取得をする方法のメモ
テーマ構成

/themes
   |- /main-theme
   |   |- functions.php
   |- /sub-theme
   |   |- functions.php

テーマディレクトリまでのパスの取得

get_template_directory

テーマのパスを取得するのに get_template_directory() を使っているのをよく見ますが、サブテーマでこの関数を使うと親テーマのディレクトリまでのパスが返されてしまいます。

親テーマ内で使用

<?php // /main-theme/functions.php
echo get_template_directory();
// 出力 => /home/www/wordpress/wp-content/themes/main-theme

子テーマ内で使用

<?php // /sub-theme/functions.php
echo get_template_directory();
// 出力 => /home/www/wordpress/wp-content/themes/main-theme

get_template_directory()は常に親テーマのディレクトリまでのパスが取得される。

get template directory
末尾にスラッシュを付けずに、現在のテーマのディレクトリへの絶対パスを取得します。
子テーマが使用されている場合には、親テーマのディレクトリへの絶対パスが返されます。 子テーマのディレクトリへの絶対パスを取得するには get_stylesheet_directory() をお使いください。
[出典] 関数リファレンス/get template directory - WordPress Codex 日本語版

get_stylesheet_directory

get stylesheet directory
現在のテーマまたは子テーマのスタイルシートディレクトリのパスを取得します。
注: 末尾にスラッシュを含みません。
[出典] 関数リファレンス/get stylesheet directory - WordPress Codex 日本語版

親テーマ内で使用

<?php // /main-theme/functions.php
echo get_stylesheet_directory();
// 出力 => /home/www/wordpress/wp-content/themes/main-theme

子テーマ内で使用

<?php // /sub-theme/functions.php
echo get_stylesheet_directory();
// 出力 => /home/www/wordpress/wp-content/themes/sub-theme

get_stylesheet_directory()を使えばそれぞれのテーマまでのパスが取得することができました!
 

get_stylesheet_directory 親テーマ内のfunctions.phpで実行されても今見ているサイトのテーマまでのパスが取得できるっぽい

WordPressの子テーマは親テーマのfunctions.phpも実行されます。
親テーマのfunctions.phpget_stylesheet_directory()がある時、子テーマから実行されると「現在のテーマ」である子テーマのパスが返されるようです。
これを利用すれば、親テーマに書いておくだけで、子テーマが複数あっても各テーマの設定ファイルを読み込んだりさせることができます。

テーマ構成

/themes
   |- /main-theme
   |   |- functions.php
   |   |- /inc
   |       |- config.php
   |- /sub-theme
   |   |- functions.php
   |   |- /inc
   |       |- config.php

親テーマ(/main-theme/functions.php)

<?php
define('__THEME_DIR__', get_stylesheet_directory());
require_once(__THEME_DIR__ . '/inc/config.php');
  1. 親テーマのサイトを見ている時
    /main-theme/inc/config.php が読み込まれる
  2. 子テーマのサイトを見ている時
    /sub-theme/inc/config.php が読み込まれる

 
WordPressで親テーマ・子テーマを作成する時は、常に親テーマまでの絶対パスを取得したい時はget_template_directory()、動的に現在のテーマまでの絶対パスを取得したい時はget_stylesheet_directory()を使えば良いとお覚えておけば良さそうです。


[参考]

WordPress マルチサイト ネットワーク管理画面のURLが変?

下記のような構成でWordPressでマルチサイトを設置しました。
サイト構成

/site-root <- サイトのルートのディレクトリ
  |- .htaccess
  |- index.php
  |- /wordpress  <- WordPress本体
        |- wp-config.php

メインサイトの管理画面のURLは example.com/wordpress/wp-admin/ です。
管理画面からマルチサイトをコントロールする「サイトネットワークの管理」にアクセスすると...
URLが example.com/wp-admin/network/ になりました。
WordPress本体が /wordpress にあるので、example.com/wordpress/wp-admin/network/ でないのがとても気持ち悪いです...

試しに example.com/wordpress/wp-admin/network/ でアクセスした所問題なくネットワークの管理画面が表示されており、 新規サイト作成のフォームのPOST先もこちらで問題なく動作しているようでした。 (見落としがあるかもしれません)

検索してみると同じような質問(Multisite network admin – URL / redirect error - WordPress Development Stack Exchange)が出ていましたが、解決方法は載っておらず...
WordPressのネットワーク管理画面のコアファイル(/wp-admin/network)でネットワーク管理画面関連のURLを出力している部分を調べてみた所、network_site_urlという関数を使ってネットワーク管理画面のURLを作成しているようでした。
このnetwork_site_url関数が定義されているコードを調べた所 network_site_url フィルターが使用できることが解りました。

network_site_url フィルターを使ってネットワーク管理画面のURLを置き換える

テーマにかかわらず常に実行してほしいのとWordPressのアップデート時に巻き戻ってしまっては困るので wp-config.php にフィルターを設置して、ネットワーク管理画面のURLを変更するようにします。

/wordpress/wp-config.php の最下部WordPressの設定を読み込んでいるrequire_once(ABSPATH . 'wp-settings.php');の下にフィルターを追記します。

<?php //wp-config.php
/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

// ▼ ネットワーク管理画面のURLを変更するフィルター ▼
// Wordpressのディレクトリ
define('__WORDPRESS_CORE_DIR__', '/wordpress');
// ネットワーク管理画面のURLを上書き
add_filter('network_admin_url', 'rewrite_my_network_admin_url', 10, 2);
function rewrite_my_network_admin_url($url, $path) {
  $networkPath = str_replace( '/wp-admin/', __WORDPRESS_CORE_DIR__ . '/wp-admin/', $url );
  return $networkPath;
}

これでネットワークの管理画面はexample.com/wordpress/wp-admin/network/になり、管理画面内からのリンクやフォームのPOST先のURLもwordpressディレクトリがある状態にすることができました!

WordPressの関数やフィルターを利用するコードを require_once(ABSPATH . 'wp-settings.php'); より上に書いてしまうとエラーになってしまうので、必ずwp-settings.phpの読み込みより下に記述しなければならないようです。

本当は.htaccessのRewriteRuleで書き換えたほうがスマートなのだと思うのですが、マルチサイトにした状態で上手くネットワーク管理画面関連だけのURLを書き換える技術力が今野私に無かったので、フィルターで出力自体を変更してしますというパワープレイに出ているので、とてもバッドノウハウな気がしてます。
現状確認できる範囲では問題なく動作しているようですが、何か不具合がある可能性は否めません。

そして、サブサイトを作成すると管理画面のURLは example.com/<sub-site>/wp-admin/ になってしまうので、WordPressのマルチサイトはそもそもサイト直下に直接WordPressのコアファイルを展開して使用する想定になってるっぽいなと思いました。

良い解決方法があればお待ちしています。

[参考]

<?php // /wp-includes/link-template.php#L3256
function network_site_url( $path = '', $scheme = null ) {
  if ( ! is_multisite() )
    return site_url($path, $scheme);

  $current_network = get_network();

  if ( 'relative' == $scheme )
    $url = $current_network->path;
  else
    $url = set_url_scheme( 'http://' . $current_network->domain . $current_network->path, $scheme );

  if ( $path && is_string( $path ) )
    $url .= ltrim( $path, '/' );

  /**
   * Filters the network site URL.
   *
   * @since 3.0.0
   *
   * @param string      $url    The complete network site URL including scheme and path.
   * @param string      $path   Path relative to the network site URL. Blank string if
   *                            no path is specified.
   * @param string|null $scheme Scheme to give the URL context. Accepts 'http', 'https',
   *                            'relative' or null.
   */
  return apply_filters( 'network_site_url', $url, $path, $scheme );
}

出典: https://core.trac.wordpress.org/browser/tags/4.8/src/wp-includes/link-template.php#L3256


人生にゆとりを生み出す 知の整理術

人生にゆとりを生み出す 知の整理術

WordPress さくらサーバーでマルチサイトにしたらリダイレクトループでサブサイトの管理画面にログインできなかった件

WordPressのマルチサイトを作成する案件があって、さくらのレンタルサーバーWordPressをインストールしてマルチサイトの設定を行いました。
メインサイトのトップを/にして、ディレクトリ型でマルチサイトをインストールしたまでは良かったのですが、サブサイトを作成してサブサイトの管理画面にアクセスしようとするとリダイレクトループが発生し管理画面にアクセスできない状況にハマってしまいました。(サブサイトそのものはリダイレクトループが発生すること無く表示されていました...

サイト構成

/site-root <- サイトのルートのディレクトリ
  |- .htaccess
  |- index.php
  |- /wordpress  <- WordPress本体
        |- wp-config.php

ネットワーク有効化の際に出力される .htpaccess に記入するコードに問題があった

さくらのレンタルサーバーでマルチサイトのネットワークを有効した時に表示されるRewriteRuleに不要なパスが出力されてしまっていてるのがリダイレクトループになってしまう原因のようでした。

ネットワークの有効化の際に表示される.htaccessの設定👇

2.次の内容を /home/user/www/ にある .htaccess ファイルへ追加して、他の WordPress ルールを置き換えてください:

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) site-root/wordpress/$2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ site-root/wordpress/$2 [L]
RewriteRule . index.php [L]

よく見ると、/www 直下の.htaccessに記入するようにと書かれています。
ドメイン/site-rootディレクトリに指定している場合はWordPress.htaccess/site-root直下にあるので、出力される設定ではパスが異なってしまうのが原因のようです!

RewriteRule のパスを修正する

下から2つ目と3つ目の設定

RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) site-root/wordpress/$2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ site-root/wordpress/$2 [L]

ここにあるパスを.htaccessのあるドメイン指定してある/site-rootからみてのWordPress本体があるパスに修正します。

このケースではWordPress本体は/site-rootからみるとwordpressディレクトリになるので次のように修正します。

RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) wordpress/$2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ wordpress/$2 [L]

 
仮に/site-rootに直接WordPressのコアファイルが置かれている場合は次のような感じです。

RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]

 

マルチサイトを作ったのは初めてで、注意書きを見をとしてしまっていたためにパスの違いに気づかずハマってしまいました。
サブサイトのそのものが閲覧できていたので余計に、ナゼ管理画面だけリダイレクトループになるんだ!? と盛大にハマりました。

今日のアイカツ格言
「注意書きはちゃんと読もう!」
f:id:kikiki-kiki:20180201075055p:plain


ローリーとふしぎな国の物語 ~プログラミングとアルゴリズムにふれる旅~

ローリーとふしぎな国の物語 ~プログラミングとアルゴリズムにふれる旅~