誰にでもあることだし、全く恥ずかしいことではないと思います。見せびらかして友人を興醒めさせるのは一般的にはよくないことですが、互いに見せ合いっこするなら誰も傷つかないし、それは互いの個性を認めあう貴重な時間にもなります。
その一方でTKBが意図せず透けるのは大きな問題にもなりうることを我々は強く認識しており、透けるほどに育ったのならパッチを当てればいいじゃない、ということなのです。それが今回で言うところのパッチ的プラグイン「update-option Patch」であり、TKBに関してはパッチは2つ必要ですが、今回はTKBではないのでパッチは1つでOKです。話のわかるやつだ。
そんなTKBはひとまず横に置いといて、プラグインは以下からダウンロード。
チェックボックスをオフにできなくなってしまうのを解消し、通常通りオフにできるようにするプラグインです。
SQLite Integration update-option Patch ダウンロードページ
「1.8.1」というフォルダーの中にあるzipファイルをダウンロードしたら、展開して plugins ディレクトリに設置してください。そして管理画面から有効化。
なお、当プラグインは、2018年3月現在のSQLIte Integrationの最新バージョン・1.8.1専用です。もし今後バージョンアップなどで問題が解決したら、当プラグインはむしろ動作の妨げになる可能性があるので、削除してしまってください。
アクションフックupdate-option
で設定の変更を監視し、値がNULL
に変更されようとしている項目について、データベースファイルに直接接続して該当箇所を書き換えます。
なお wp_options テーブルの options_value は NULL が書き込めなくなっており、矛盾(?)が発生しているので、一通り検証した上でNULL
の代わりに空文字列
を書き込んでいます。
データベースに直に書き込むという、私的にかなりアバンギャルドなことをやっているプラグインなので、上記の仕様に至った経緯を解説してみます。
技術面は別にどうでもいいや、という人は読み飛ばしてOK。
動作の要はupdate-option
というアクションフックです。
フックとは何か? というのは細かくは説明しませんが、簡単に言うと「基本的な動作をしたタイミングで割り込み動作をさせる機能」です。新学期らしい例えをするならば、朝起きる
というのが基本的な動作だとしたら、枕元の採尿カップをトイレに持っていっておしっこを注ぎ、提出するアレで吸い上げてラベルを貼る
という動作がフックに該当します。いつもの動作の前や後に、別の動作を追加するわけです。(余談だけど私の場合、義務教育時代は四角いたれびんだったので、近代化された時に時代は変わったんだと思った)(どうでもいい)
でそのupdate-option
が何なのかというと、設定が保存される直前に、保存される前の情報と保存される情報を知らせてくれる、というフックなのです。
管理画面上で発生している状況を見るに、「あぁ、チェックボックスをオフにした時、その値が保存されてないんだろうなぁ」という予想はできます。
で、調べてみたところ実際そのようだったらしく、
NULL
となる。updated-option
も呼ばれない。つまり実際に保存処理が行われていない。という感じです。
どこに問題が起こっているのかは正直よくわかりませんが、通常使われる関数ではデータベースに正常に書き込まれなくなってしまっている、というのは確かなようです。
なるほど。それならWordPressを通さずにSQLiteに直接接続して、該当のチェックボックスのレコードにNULL
を書き込んじゃおう。
ちなみに私は普段SQLを直接いじるコードは書かないため、餅は餅屋ということで、一部コードをSQLite Integrationから拝借しました。
同プラグインはGPLライセンスなので、ああ、このプラグインもGPLになってしまったのだなあ……というプログラマにはわかってもらえるであろうある種の情動が起こりますが、それは横に置いといて。
完成したコードでいざNULL
を書き込もうとすると、以下のエラーが発生。
NOT NULL constraint failed: wp_options.option_value
これは「NOT NULL制約」といって、どうやら「option_valueにNULLは書き込めない」ようになっているようです。
WordPressはNULLを入れたいと言っている。しかしデータベースはNULLを入れるなと言っている。なるほどチェックボックスがオフにならなかったのはこれが原因か。
……ちょっと待って、じゃあフツーのWordPressは何で問題なく書き込めてるんだろうか? NULLを書き込もうとしたら、勝手に別の値を書き込んでくれるような親切機能があるとか?
そう思ってしばらく調べていると、こんな情報が。(下線は私が付けました)
明示的な DEFAULT 句のない NOT NULL カラムに対するデータエントリでは、(中略)UPDATE ステートメントがカラムを NULL に設定する場合、MySQL はその時点で有効な SQL モードに従ってカラムを処理します。
- 厳密モードが有効でない場合、MySQL はカラムデータ型の暗黙的なデフォルト値にカラムを設定します。
引用元:MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.6 データ型デフォルト値
https://dev.mysql.com/doc/refman/5.6/ja/data-type-defaults.html
「NULLが書き込めない場所にNULLを書き込もうとした場合は、暗黙的なデフォルト値で書き込まれる」という衝撃の事実。脳の皺が一本増えました。ためになったねー。
で、ここでいう「暗黙的なデフォルト値」とは何かというと、
暗黙的なデフォルトは次のように定義されます。
(中略)
ENUM ではない文字列型のデフォルト値は空の文字列です。ENUM のデフォルトは、最初の列挙値です。引用元:同上
だそうです。
つまりMySQLで運用されているWordPressの場合、wp_optioinsにNULLを書き込もうとすると、エラーにせずに、自動で空文字列を書き込んでくれていたのだ。
一方のSQLiteはそういうのがないので(?)、NULLを書き込むんじゃねえというエラーが出た、と。
どうやら「SQLiteの場合もNULLの場合は空文字列を書き込め」という結論になりそうですが、本当にそれでいいのかい、後悔はないのかい――と俺の中のSQLiteの妖精が囁いている……。
じゃあもう結局は実地検分しかねえな、ということで、「実際に運用されているデータベース」をこっそり覗いて、チェックボックスがオフの時、値が何になっているかを調べることにしました。「何も手を付けていないSQLiteのデータベース」と比較して様子を見てみようという作戦です。
すべてのチェックボックスを調べるのは疲れるので、チェックボックスがたくさんある「設定→ディスカッション」ページの分だけ、オン・オフがどのような値で保存されているのかを確認。
結果は以下の表の通り。
option_name | option_value | |
---|---|---|
未変更 (SQLite) | 一回以上保存 (MySQL) | |
require_name_email | 1 | 1 |
comments_notify | 1 | 1 |
default_pingback_flag | 1 | 空文字列 |
comment_moderation | 0 | 空文字列 |
moderation_notify | 1 | 1 |
comment_whitelist | 1 | 1 |
comment_registration | 0 | 1 |
show_avatars | 1 | 空文字列 |
close_comments_for_old_posts | 0 | 空文字列 |
thread_comments | 1 | 1 |
page_comments | 0 | 空文字列 |
1
、オフで0
が入っている1
、オフで空文字列が入っている同じオフなのに、デフォルトでは0
、変更後は0でなく空文字列
。
MySQLの親切機能のおかげなのか、スクリプトが裏でごにょごにょやってくれてるのかまではわかりませんが、少なくとも「チェックボックスがオフなら空文字列」というのは間違いなさそうだし、少なくとも今回扱う書き換えの範囲では、空文字列の一択で問題なさそう。
というわけで、「チェックボックスをオフにした場合は、NULLの代わりに空文字列で保存される」という仕様になった、ということです。
拙作プラグインについては以上です。
「手間を省いてくれる」とか「楽しい」とか、そういうプラグインはたくさんありますが、直接的に金銭的コストを削減してくれるプラグインなんてそうそうないわけで、そういう意味でとても貴重な同プラグイン。
その一方で、人(とブログの性質)を選ぶプラグインであることも確かです。負荷対策としてキャッシュプラグインを併用する必要があったり、使えないアドオンがあれば代替を探したり、ある日突然全てが吹っ飛ぶことを警戒して毎日データベースのバックアップをとったり……etc。
またこれから先、新しいバージョンのWordPressでも同プラグインが使えるという保証は全くないわけで、そういう意味ではある日突然終わりが来ても何とかできる人でないと難しいかなとも思います。
SQLite Integrationの最重要部分は、データベースとのやりとり部分をオーバーライドできる機構です。
インストールの際にdb.php
を wp-content/ にコピーすると思いますが、これは wp-includes/ の中にあるwp-db.php
をオーバーライドするためです。
ファイルを置くだけで仕事が完了するということは、セキュリティホールになりやすいとも考えられるはずで、この部分を利用した大規模な攻撃が起こったりすると、あんまり使われてないしこの機構は廃止するね、なんて風潮になりかねません。
そういう仕様変更は大抵は事前告知されますが、そもそもあんまり使われてない仕様の廃止が積極的にアナウンスされるとはあまり思えないので、「なんとなくバージョンアップしたら突然動かなくなった」となる可能性はぶっちゃけ低くはない気がします。
万一そうなったら、我々はどこに脱出すればいいのでしょう?
ここでは4つの派閥に分類してみます。
我々の先祖は、テキストエディターでウェブサイトを作っていました。
現在でも、一見ブログ風なのに、毎日HTMLを手入力して更新しているであろうサイトはわずかにあります。ろじっくぱらだいすとか。
必要なのは、サイトをシンプル仕様に変更する決断と、それをするだけのモチベーションです。WYSIWYGに慣れた身体では<br>や<p>をいちいち打つのはきついし、定期的に<pre>の誘惑と戦わなければならないのもつらいです。
私が個人的に好きなCMS、Movable Typeなら、SQLiteで動かせます。
バージョン5になった時点で公式には非対応ということになったのですが、なぜかバージョン6までこっそり対応されており、次期バージョンの7でもインストールウィザードに選択肢が出るので、使えるかもしれません。(もっともこないだベータ版をテストしようとしたらエラーが出てインストールできませんでしたが……)
それ以外にも、Movable Typeを使うメリットがたくさんあります。
しかしもしこれを真に受けて(嘘ではないですが)、WordPressユーザーがMovable Typeに移行してしまうと、
……という感じで、軽く地獄を見ることになります。
ただ、「WordPressはインストールしたままの素で使っていて、Movable Typeもデフォルトでできる範囲で何も問題なく、記事が移行できればOK」という人は、すんなり移行できるかもしれません。
再構築だって、基本は放っておけばいいだけなので。
身も蓋もない話、いろいろな制限に目をつぶることができ、あまり多くを望まない、ということであれば、無料ブログサービスという手もあります。
少なくともはてなブログについては、検索してみるとWordPressからの移行方法がいくらか紹介されているので、現実的な選択肢じゃないかなぁと思います。
そんな人はこのページをそもそも見てないだろう……とは思うのですが、一方で人間というのは刻々と変化するもので、ブログを開設した数年前には「広告は絶対にヤダ! レイアウトもこれじゃないとヤダ! 独自ドメインじゃないとヤダ! SEOがー!」……と言っていたのが、年を取ってくるといろいろと緩んで「ラクなのが一番じゃ」と思い始めたりすることもあるでしょう。
無料サービスなのにメンテナンスもやってくれるなんて最強じゃないですか。
我々がWordPressに費やしている時間と情熱は、QOL的に適正なものなのだろうか?
恥も外聞もかなぐり捨て、プランを一段階上げる方法もあります。
さくらのレンタルサーバを年払いで使っている場合、プランを「ライト」から「スタンダード」に上げるには、年当たり3,599円が必要です。
しかしいきなりドカンと3,600円を捻出しようとなると、えーと思うのが人情。
ところがどっこい、12ヶ月や365日で割り算してみると「月当たり299.9円、1日当たり9.9円」となります。これならなんとなく、どうにかできそうな気がしてきます。
例えばあからさまにTKBが透けているシャツをバイト先の店長の前で脱ぎ捨て、恍惚の表情を浮かべながら1日9.9円の賃上げを要求するのはどうでしょうか。こういうのはインパクト勝負で、速やかな賃上げが必要だという差し迫った何かを感じさせる必要があるので、リアクションが薄い場合は効果音と共に白目を剥き、底抜けAIR-LINEのテクノ体操の基本動作を繰り返しながらSHOP99のテーマを歌い続けるなどのディープインパクトを披露すれば、さらに確度が高まります。
より完璧を期すのであれば、決行の前日までに
「店長、PとRの間にあるアルファベットって何でしたっけ?」
「店長、日本の一番左にある島って何州でしたっけ?」
「10ひく1、10ひく1……あれー? 店長、何ですっけー?」
などと頻繁に問いかけを行い、「きゅう」というワードを脳に刷り込んでおけばもう盤石です。きっと「キュウ……キュウ……ふむ、よし!」となり、9.9円の賃上げが約束されます。
ただし失敗した場合はあだ名がTKBになります。
ライトプランとスタンダードプラン、その価格差は1日わずか9.9円(税込)――そんな事実をお伝えしたところで、本稿は終わりです。
ご静聴ありがとうございました。
当投稿のオリジナル版本文の芸術性が高すぎたためか、なかなか検索エンジンにインデックスされない状況を鑑み、一部をDAI語による表現に変更しました。ご了承ください。
WP_DEBUGをtrueにしていても(画面遷移のタイミングの問題なのか)エラー表示がページ上に出なかったので諦めていたのですが、WordPressのデバッグログはファイルに出力できることを今更知りました(WP_DEBUG_LOG)。これならエラー見放題。
実際に出力して確認したところ、以下のようなエラーが出ているらしい。
Error occurred at line 692 in Function execute_query.
Error message was: Error while executing query! Error message was: SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: wp_options.option_value
#0 PDOEngine->get_error_message() called at [/home/foobar/wordpress/wp-content/plugins/sqlite-integration/pdodb.class.php:254]
#1 PDODB->query(UPDATE `wp_options` SET `option_value` = NULL WHERE `option_name` = 'comment_registration') called at [/home/foobar/wordpress/wp-includes/wp-db.php:2166]
#2 wpdb->update(wp_options, Array ([option_value] => Array ([value] => ,[format] => %s,[charset] => ,[length] => )), Array ([option_name] => Array ([value] => comment_registration,[format] => %s,[charset] => ,[length] => ))) called at [/home/foobar/wordpress/wp-includes/option.php:369]
#3 update_option(comment_registration, ) called at [/home/foobar/wordpress/wp-admin/options.php:215] ] UPDATE `wp_options` SET `option_value` = NULL WHERE `option_name` = 'comment_registration'
そしてpdodb.class.php
を覗いてみたところ、値がNULLの時にそういうSQL文を組み立てているっぽい箇所がありました。2141行目。
foreach ( $data as $field => $value ) {
if ( is_null( $value['value'] ) ) {
$fields[] = "`$field` = NULL";
continue;
}
$fields[] = "`$field` = " . $value['format'];
$values[] = $value['value'];
}
ということは、ここを書き換えればNULLの代わりに空文字列を書き込む、という動作に変更できそうですが、実際は$field
がoption_valueの時だけ(カラムがNOT NULLの時だけ)にすべきなんだろうなぁと思います。
ただ、私はもうプラグインで暫定的に解決しておこうと思います。内部でエラーは起こってるわけですが、設定保存時だけですもんね……。