Contents
- 1 独自ドメインをはがしてログインできなくなったとき
- 2 ローカルに環境構築
- 3 基本、add_action/add_filterだけ使う
- 4 値を表示する関数と戻り値を返す関数
- 5 ローカルで動かすとき
- 6 データベース接続確立エラーになる場合
- 7 謎の の連続が出現する件
- 8 wordpressの編集画面でペーストするとスクロールバーがずれてうざい件
- 9 いまのところのざっくりとした理解
- 10 アクションフック・フィルタフック
- 11 wp_headとwp_footerの中身
- 12 フィルタフックにひっかけるときは必ずreturnする
- 13 いまのところのざっくりとした理解2
- 14 あきらかにバグないはずなのにエラーが出るとき
- 15 ローカル環境
- 16 テーマエディターで.phpファイルを更新できない場合
- 17 mixed content対策
- 18 WordPressコアとテーマ
- 19 お蔵入りのコード
独自ドメインをはがしてログインできなくなったとき
独自ドメイン(今回はサブドメイン)をはがしたらログインできなくなった。ブログのトップは表示できるのだが、各記事へのリンクがすべて独自ドメインになっていて記事にアクセスできない。
wp-config.phpなんかでサイトのURLを指定するところがないか調べたがそんな項目はない。ルートディレクトリから全ファイルをgrepで調べたが、独自ドメインは見つからなかった。WordPressはいったいどこから独自ドメインの情報を引っ張ってきてるんだ。
.htaccessのそれっぽいところを修正したが症状は治らず。
そういえばかすかな記憶のなかに、管理画面→設定からサイトアドレスを変更せずに独自ドメインにしてしまってログインできなくなったことを思いだす。「wordpress サイトアドレス 変更 ログインできない」というキーワードをひねり出してググるとそのものずばりの記事が見つかった(参考)。
サイトアドレスの情報はWordPress内のファイルではなく、データベースに保存されていたのだ。phpMyAdminからこれを修正すると無事復旧することができた。
ちなみにリンク先の「define(‘WP_SITEURL’, ‘http://●●●.●●’);」の部分をそのままコピペするとはまる。シングルクォーテーションが全角だ。これに気付くのに10分くらいかかった。。。
ローカルに環境構築
WordPressをインストール
ダウンロードして展開して配置するだけ。
MySQLをインストール
Visual Studioとかたくさんインストールさせられる。非常に多くのステップを踏む必要がある。解説ページをみつつ進めていく。
新しい(strong)方式のパスワードと旧式(legacy)のパスワードを選択するところで、旧式を選択。WordPressでは旧式しか使用できないため。デフォルトは新しい方式になっているので注意。
サービスの登録はインストーラーがやってくれるが、PATHの設定は自分でやらないといけない。
MySQLにデータベースを作成
MySQL80というサービスを起動。
1 |
mysql -u root -p |
でMySQLにログインしてから
1 |
create database local_wordpress; |
でデータベースをつくる。WordPressのwp-config.phpにデータベース名、ユーザー名、パスワード、ホスト(localhost)を記載する。認証用ユニークキーはローカルのテスト用ブログなので生成しなおさなくてもいいだろう。もちろん本番環境では生成しなおすべき。
今回はローカルのテスト用なのでrootでデータベースを作成したが、本番環境ではもちろん専用のユーザーをつくるべき。
Apacheの起動
Apacheのhttp.confのドキュメントルートをWordPressのフォルダに指定してから起動する。
WordPressをセットアップ
以上を踏まえてブラウザからhttp://localhost:8000(Apacheで8000番ポートを指定した場合)にアクセスするとWordPressのインストールが始まる。
インストールが終わるとlocal_wordpressに必要なテーブルが生成されている。
基本、add_action/add_filterだけ使う
我々ができることは、functions.phpでadd_action/add_filterを使ってWordpress開発者やテーマ開発者が各所に用意したフックに関数を登録すること。do_action/apply_filtersは開発者がフックを置くのに使うのであって、我々が使うことはない。
どうしても使っているテーマに手を入れたいときは、do_action/apply_filtersを使ってフックを置き、そのフックにfunctions.phpで関数を登録する。この場合、テーマをアップデートするたびに自分でフックを置きなおす必要がある。
テンプレートタグは、フックに登録する関数のなかでなにかしらブログの情報が必要なときにを使うもの。あるいは自分でテーマを作成するときやどうしてもテーマに手を入れたいときに使う。
値を表示する関数と戻り値を返す関数
wordpressの関数には2種類ある。値を表示する関数と戻り値を返す関数。たとえばthe_title関数は値を表示するので以下のように使う。echoする必要はない。
1 |
<?php the_title(); ?> |
echoする必要がないのは、the_title関数の定義のなかでechoしているから。wp-includes/post-template.phpをみると
1 |
echo $title; |
という箇所を確認できる。
一方、get_the_title関数は戻り値を返す関数。関数の定義をみるとechoしていない。表示するには戻り値をechoする必要がある。get_で始まる関数はたぶんぜんぶそう。
1 |
<?php echo get_the_title(); ?> |
また、the_title関数はデフォルトでは値を表示するが、オプションを指定($echo=TRUE)して戻り値として受け取ることもできる。
ローカルで動かすとき
-
- PHPのビルトインサーバーを起動
- php -S localhost:8000
- mysql80というサービスを起動
- 起動:net start mysql80
- 停止:net stop mysql80
- 状態確認:sc query mysql80
- コマンドプロンプトからmysqlに1回入る
- なぜかわからないが1回入らないと「データベース接続確立エラー」になる
- コマンドは「
mysql -u root -p
」
- PHPのビルトインサーバーを起動
データベース接続確立エラーになる場合
原因不明のデータベース接続確立エラーに悩まされていた。まずはwp-config.phpで
1 2 3 |
define('WP_DEBUG', false); // ↓に変更 define('WP_DEBUG', true); |
すると以下のようなメッセージが現れた。
1 |
The server requested authentication method unknown to the client |
ググってこのページにたどり着いた。
どうやらmysqlの現行バージョンではデフォルトの認証方式が新しくなり、PHP側がそれに対応していないのが問題らしい。対策としてはmysqlの認証方式を古いものに変更する。
1 |
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; |
こんなことが原因だったとは!安定してエラーが出ることはなくなった。
しかし解せないのは、いちどコマンドプロンプトから入るとエラーにならなかった点なんだよな。認証方式が違うのに接続に成功していた。謎だ…。
特定までに時間がかかった理由
最初からデータベースが怪しいという方針なら、わりとすぐに問題解決できたはず。しかしWebサーバーも怪しいと思ってしまったことで解決が遅れてしまった。
PHPのビルトインサーバーだと、記事を新規投稿するとサーバーが落ちてしまうのだ。これは面倒だということで、apacheを使うことにした。するとapacheでPHPを動かすにはモジュール(php7apache2_4.dll)が必要だったんだが、これが見当たらない。あとからわかったのが、PHPにはThread safeとNon Thread safeがあること。昔々俺がダウンロードしたのはいちばん上にあるNon~のほうだったのだが、くだんのモジュールはThread safeにしか入っていない。
ということでPHPを入れなおしてPATHも書き換えてと。あとapacheのドキュメントルートを変更したり、ポート番号も変更したり。
同時にいろいろやりすぎたせいで、怪しい対象が広くなりすぎてしまったorz
追記
「PHPのビルトインサーバーだと、記事を新規投稿するとサーバーが落ちてしまうのだ」と書いたが、現象を再現しようとapache→ビルトインサーバーに変えて新規投稿しても落ちない。原因はビルトインサーバーではなく認証方式が違ったからみたいだ。解せないのは認証方式が違うのに投稿できて、そのあとビルトインサーバーが落ちていたことだ。闇が深い…。
「投稿できて、そのあとビルトインサーバーが落ちる」を再現しようと認証方式を新しいものに戻して投稿してみた。やはり投稿できて(データベースにインサートできて)、しかしこんどはビルトインサーバーは落ちず、データベース接続確立エラーになった。
ようわからんが、たしかなことは認証方式が違っていても投稿できてしまうということ。認証方式自体をお勉強すればこの現象を理解できそうだが、今回はこれ以上深追いしないことにする。
謎の の連続が出現する件
「wordpress 」でググって見つけたこちらのページによると、2連スペースが に変換されてしまうらしい。
たしかに該当箇所にはスペースの連続があった。しかし が現れないほかの場所にもいたるところにスペースの連続がある。たぶんこれが原因じゃないよなぁ、と思いつつ の連続が出現する箇所のスペースをTABに置き換えてみた。 消えた。一件落着。だけど、ほかにも2連スペースがいたるところにあるけど 出てないよ?なんだこれ。
とはいえWordpressで謎の の連続が現れたら、とりあえず当該箇所のスペースをTABに置き換えてみると解決するかもしれない。
wordpressの編集画面でペーストするとスクロールバーがずれてうざい件
コピペするたび視点がずれて不便極まりない。検索しても思うような記事がヒットせず。いまだ解決できず。
→思案のち、コピペといえば「Image Elevator」怪しいなということで停止してみた。ずれなくなった。Image Elevator超便利なんだけどね。。。なんか設定すれば回避できるかもしれない。
いまのところのざっくりとした理解
wordpressは3つの部分からなっているっぽい。
- wordpressコア
- bloginfo()やthe_title()などのテンプレートタグを提供する
- ブログ情報などを保持してる
- テーマ
- wp_head()やwp_footer()などのフックを実際にかけたのはテーマ製作者
- ユーザーが手を加えた部分
- テーマ製作者がおいたフックを子テーマのfunctions.phpから使う(テーマ製作者自身も親テーマのfunctions.phpから使う)
正直複雑すぎて全部は把握できそうにない。しかし結局最後はHTMLを吐くということを念頭にコードを追いかければ、完璧には理解できなくてもトライアンドエラーでやりたいことは基本できるのかな、という感じではある。
アクションフック・フィルタフック
- add_action():アクションフック:追記するときなど
- add_filter():フィルタフック:変数を書き換える:書き換え後の変数を必ずreturnする
- do_action():フックされた関数を実行する
- apply_filters():フックされた関数を実行する:引数は基本Codexで調べるが、載ってなかったらソースを探すとわかる
以下はwp-login.php内でapply_filters関数を呼んでいる部分の一例。
1 |
$classes = apply_filters( 'login_body_class', $classes, $action ); |
login_body_classにフックすることで$classesを成形することができるんだと思う。$actionは成形できないのかな?渡しているのが参照ならできるのかも。
do_action関数とかapply_filters関数を自分で呼べば、自分でつくったフックを設置できる。実際できた(勉強のために実験する以外で設置することはないだろうけど)。
wp_head()とかwp_footer()とかがテーマから呼ばれているが、それ自体がフックなわけではない。wordpressコアの中で定義されているwp_head()/wp_footer()のなかでdo_action関数が呼ばれているはず(ちょろっと探したがソースファイルがみつからない)。
wp_headとwp_footerを定義しているファイルを見つけました。wp-includes/general-template.phpにあります。定義部分を抜粋します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function wp_head() { /** * Prints scripts or data in the head tag on the front end. * * @since 1.5.0 */ do_action( 'wp_head' ); } function wp_footer() { /** * Prints scripts or data before the closing body tag on the front end. * * @since 1.5.1 */ do_action( 'wp_footer' ); } |
予想どおりdo_action関数を呼んでいました。というか、呼んでるのみかいw つまり、wp_head/wp_footerはフックを置くことのみが目的の関数だった。じつにシンプル。
ちなみにソースファイルの場所はCodexに書いてあった。すべての関数にソースファイルの項目が用意されているっぽい。親切。
フィルタフックにひっかけるときは必ずreturnする
wordpressコアのソースでは基本この形で書かれているみたい。
1 |
$value = apply_filters("フィルタフック", $value); |
なので、functions.phpでフィルタフックにひっかける際、returnを返さないとフィルタ処理が反映されない。return必須(アクションフックにひっかけるときは必要なし)。
1 2 3 4 |
add_filter("フィルタフック", function($value) { //フィルタ処理 return $value; }); |
いまのところのざっくりとした理解2
functions.php
functions.phpに書く処理は、かならず関数で囲みフックにひっかける(登録する)必要がある。
フックにひっかけないとすると、どこにどのタイミングで実行するか決めないことになる。そのような処理はない。functions.phpに処理を書く目的はPHPが吐くHTMLのどこかをいじることなのだ。
ゆえにかならずadd_action/add_filterでフックにひっかける必要がある。
フックの種類
フックには主に2種類ある。Wordpressコア内に置かれたフックと、テーマ製作者が置いたフック。
さらにテーマ製作者が置いたフックのなかでも、Wordpressに置くことを要求されているフックがある。wp_headやwp_footerなどだ。これらはフックを置くための関数がWordpressコア内に用意されている。wp_head()関数やwp_footer()関数など。上述したように中身はフックを置くだけ(add_action関数を呼ぶだけ)になっている。
テーマ利用者の俺は、基本的にfunctions.php内に処理を書くのみ。テーマにはできるだけ手は入れない。どうしてもテーマに手を入れたい場合、親テーマのファイルを子テーマにコピーしてきていじることになる。
また、Wordpressコアに手を入れることは絶対にないだろう。テーマ製作者ですらWordpressコアには手を入れることはないのだから。なぜならテーマ利用者はテーマとWordpressをべつべつにインストールするわけだから。
あきらかにバグないはずなのにエラーが出るとき
周辺のスペースが悪さしてるパターンけっこうある。タブに置き換えるとエラーがとれるパターンありがち。
ローカル環境
PHPのビルトインサーバーでローカルのWordpressにアクセスする場合、ポート番号8000番でないとなぜかアクセスできない。
8080番とかで起動して8080番にアクセスするとなぜか8000番にリダイレクトされてエラーになる。たまにアクセスできるけどなぜかCSSがあたっていない。なんだろうこれは。
たぶんWordpressのなかのファイルのどれかで8000番を指定してるんじゃないかと思う。8000でfindstrしてみたらclass-wp-http-cookie.phpにて以下のコメントが見つかった。
1 2 3 4 |
// Port - supports "port-lists" in the format: "80,8000,8080". if ( ! empty( $port ) && ! in_array( $url['port'], explode( ',', $port ) ) ) { return false; } |
80、8000、8080しかサポートしていないのか?しかしサーバーを8080で起動してもだめじゃん。なぞだ。8000で起動すれば問題ないので、とりあえずいまは放置。
テーマエディターで.phpファイルを更新できない場合
ローカルのWordPressでfunctions.phpを更新しようとしたら数十秒間くるくる回ったあげく、
致命的なエラーをチェックするためにサイトと通信できないため、PHP の変更は取り消されました。SFTP を使うなど、他の手段で PHP ファイルの変更をアップロードする必要があります。
というエラーメッセージが出て更新できずに困った。ググって出てきた解決策をいくつか試してみたが解決せず。
サーバーにはPHPのビルトインサーバーを使っていたのだが、なんとなくApacheなどのちゃんとしたサーバーを使ってみたら解決した。いったいなんだったんだろうなぁ。ビルトインサーバーには備わっていない機能を使っているのかな。あくまで簡易サーバーだからねぇ。
mixed content対策
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// mixed content対策(アイキャッチ) add_filter('wp_get_attachment_image_src', function($image) { $image[0] = preg_replace('~^http:~', 'https:', $image[0]); return $image; }); // mixed content対策(サムネイル) add_filter('post_thumbnail_html', function($html) { $doc = new DOMDocument(); $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'utf-8')); $img = $doc->getElementsByTagName('img')[0]; foreach ($img->attributes as $attr) { if ($attr->name === 'src' && preg_match('~^http:~', $attr->value)) { // $img->parentNode->removeChild($img); $attr->value = preg_replace('~^http:~', 'https:', $attr->value); } } return mb_convert_encoding($doc->saveHTML(), 'utf-8', 'HTML-ENTITIES'); }); // mixed content対策(本文) add_filter('the_content', function($content) { $doc = new DOMDocument(); $doc->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'utf-8')); $imgs = $doc->getElementsByTagName('img'); foreach ($imgs as $img) { foreach ($img->attributes as $attr) { if ($attr->name === 'src' && preg_match('~^http:~', $attr->value)) { // $img->parentNode->removeChild($img); $attr->value = preg_replace('~^http:~', 'https:', $attr->value); } } } return mb_convert_encoding($doc->saveHTML(), 'utf-8', 'HTML-ENTITIES'); }); |
wp-includes\post-thumbnail-template.phpのget_the_post_thumbnail関数内の末尾にpost_thumbnail_htmlというフックが用意されている。これに処理を登録することでサムネイルのimgタグを編集することができる。
ちなみにthe_post_thumbnail関数はget_the_post_thumbnail関数を呼んで得た結果をechoしているだけだったりする。
wp-includes\media.phpのwp_get_attachment_image_src関数内の末尾にwp_get_attachment_image_srcというフックが用意されている。これに処理を登録することで画像のURL、幅、高さなどを編集することができる。
mb_convert_encodingしてからloadHTMLに投入し、結果をmb_convert_encodingしなおしているのは文字化けを避けるため。
今回は使わなかったが、add_filter関数の第3引数で優先順位($priority)を指定することができる。
まずはドキュメントを読むんだけどそれをふまえつつソースコードも読むのが最短距離だと思う。
WordPressコアとテーマ
テーマがWordPressコアを使って画面をつくっている。
画面のこの部分をいじりたいと思ったら、まずはテーマのソースコードをあたってみて、どういうWordPressコアの機能を使っているのか把握する。そしてその機能にフックが用意されているかどうかを調べていく。
お蔵入りのコード
HTMLタグや<?phpをエスケープする
preタグのなかのHTMLタグや<?php がCrayon Syntax Highlighterでエスケープされないので、Crayonで置換されるまえにエスケープしてしまう処理を書いていたのだが、設定が悪かっただけでデフォルト設定に戻したらエスケープしてくれるようになった。お蔵入りのコードを以下に残しておく。
1 2 3 4 5 6 7 8 |
add_filter('the_content', function($content) { preg_match_all('/<pre>(.*?)<\/pre>/s', $content, $matches); foreach($matches[1] as $match) { // 閉じタグの/と混じってしまうためデリミタを~にしている $content = preg_replace('~' . preg_quote($match) . '~s', htmlspecialchars($match, ENT_QUOTES, 'UTF-8'), $content); } return $content; }); |
これをCrayonを停止した状態でfunctions.phpに書くとエスケープされるのだが、Crayonを有効にするとエスケープされない。たぶんCrayonの置換処理が、the_contentフックよりも先に実行されるフックにひっかけてあるんだと思う。add_filterの$priorityを-1,0,1にしてみてもだめだった。