内向型人間の知恵ブログ内向型人間の知恵ブログ悩みのタネが、ネタになる。サイトを新しいテーマに変更しました。2019.06.27Tweetシェア新しいブログテーマを作るにあたり、「サイドバーに最新記事を出してぇなぁ」と考えていました。WordPressのデフォルトのウィジェットでも最新記事を表示することは可能ですが、こちらはアイキャッチがなくタイトルのみ。タイトルだけよりも、絵があったほうが見栄えがいい。「無ければ作ればいい」という精神で、アイキャッチ付きで表示できるウィジェットを作ったので、その解説をしていきます。プラグインを使わず、かつ仕組みを理解して自作したい方にどうぞ。期待する動作・完成イメージウィジェットとして登録、並び替え、設定ができる最新記事を指定したn件表示する最新記事のアイキャッチも同時に表示する言ってしまえば「デフォルトのウィジェットにアイキャッチが付いてる」だけなんですが。口で言うのが簡単でも、実装しなきゃ実現しないのがプログラミング。簡単な流れ完成までの流れをフローチャートに起こしました。コンストラクタで親クラスを継承する以外に、form関数・update関数・widget関数を定義していきます。実際に作るとなるとエラーの修正が多々あるため、VirtualBoxのような仮想環境での開発をおすすめします。(スナップショットなど)。それができない場合は、テーマ変更のページをブラウザのタブで保持しておくといいです。エラーで取り返しのつかないことになっても、保持したタブのページでテーマを切り替えれば戻せます。本番環境で開発をするのはおすすめしません。自作したウィジェットは、functions.phpに記述します。functions.phpは色んな用途のコードが入り混じって複雑になるため、別のファイルで管理することが好ましいと思います。私の場合、libディレクトリとwidets.phpというファイルを作成して、functions.php側から呼び出しています。'/lib/widgets.php';他にも、functions.phpはいくつかの機能に分けて管理しています。WordPressのテーマサポートを有効化したり、不要な出力を削除したり、以前の「すべてfunctions.phpにまとめる」書き方では煩雑でした。functions.phpを編集、修正、管理しやすくする書き方ウィジェットの登録ウィジェットを段階的に実装していきますが、その前に「ウィジェットとして登録する」必要があります。このコードがないと、ウィジェットが出来上がっていても管理画面には表示されません。widgets.php(またはfunctions.php)に忘れずに追記します。);register_widget関数は、追加したいプラグインのクラス名をパラメータとして渡します。段階的に実装するクラス関数の順番は、個人的にはHTML出力を行うwidget関数を最後にしています。ダッシュボード(管理画面)のウィジェットに表示できること。次に、ダッシュボードのウィジェットで設定を反映できること。最後に、登録したウィジェットをWebページで表示するためのコード。この順番で解説するのが好ましいと判断しました。STEP1.コンストラクタここでの目的は、ダッシュボードのページでウィジェットが表示されることです(Fig1)。それだけですが、追加するウィジェットに必要な設定の入力フォームの実装につながります。Fig1.管理画面に載った自作のウィジェットクラスを継承し、コンストラクタ内で初期化処理を記述します。他のform関数、update関数、widget関数は空っぽのままです。オプションのないウィジェットになる。保存ボタンは表示されるが、保存するものがない状態(Fig2)。「このウィジェットにオプションはありません」と表示される。保存ボタンは表示されない(Fig3)。Codexのサンプルでは、コンストラクタをまとめて記述しているコードがあります。最後の行でまとめてclassnameやdescriptionの配列を記述すると雑多になるため、配列名だけの記述で済むように先にパラメータを処理しています。親クラスであるWP_Widgetのコンストラクタを呼び出して、ここで記述した値を渡しています。}$widget_optionsclassnameはウィジェットに割り当てられるHTMLのクラス名です。descriptionは、文字通り「説明」ですが、ダッシュボード上では「ウィジェットの名前」とも言えます。customize_selective_refreshは、テーマカスタマイザーでの変更をリアルタイムに適用するもののようです。できた方が便利だと思うので”true”を指定しています。セルティスラボ$control_options$control_optionsは、ダッシュボード上で展開した際の幅や高さを指定することができます。高さも幅も、プリセットされたウィジェットの幅で充分だと思ったため、空の配列を指定しています。Resourcesさて、これでガワだけとはいえ、ダッシュボード上に表示され、他のウィジェットと同じようにドラッグアンドドロップできるものができました。次のステップで、ウィジェットのタイトルや、ウィジェット独自の設定を入力できるフォームを追加していきます。※この項目が一番長いですが、やっていることは難しくありません。form関数では、ウィジェットエリアで表示する名前のように、ユーザが設定を入力可能なフォームを実装します(Fig4)。(ウィジェットが持つ設定のことをオプションと呼びます)この「最新記事をアイキャッチ付きで表示するウィジェット」には、他のウィジェットと同じように任意の名前を付けられるフォームと、記事をいくつ表示するかを指定するフォームを持たせます。基本的にはダッシュボードで表示するためのHTML(とPHP)を書きますが、例えば表示件数が定義されていないとエラーの原因になるため、指定した初期値を読み込むようにします。Fig4.form関数を実装するフローチャート設定を入力するフォームの実装HTMLに慣れた人、またはWordPressの自作テーマで検索フォームを作ったことがある人なら、labelタグとinputタグを簡単に扱えるでしょう。他のウィジェットを見るとわかるように、基本的にラベル(見出し)とフォームがセットになっています。複雑な点といえば、PHPのコードを含むので「改行しないと読みづらい」ことでしょうか。「$this」は一つの塊として読んだほうがいい?この質問のようにアロー演算子で区切って理解しようとしていたのですが、「アロー演算子の右側も含めて変数を指している」と解釈するのが適切でしょう。PHPのthisと-_の意味がわかりません。|teratailフォームのIDや名前を動的に取得するform関数の引数$instanceからIDや名前を引っ張ってきています。labelタグのfor属性は、セットとなるフォームのIDを示します。echo出力されています。inputタグのname属性は「フォームの名前」、value属性は「フォームの初期値」を示し、それぞれをechoで出力しています。Resourcesinputタグとは|コーディングのプロが作るHTMLタグ辞典class=”widefat”とは「input」「textarea」タグに”widefat”というクラスが指定されていますが、これは要素を横幅一杯に表示するCSSプロパティが設定されています。WordPressで用意されているクラスです。各フォームはpタグで囲うと綺麗に整いますWordPressのウィジェット作成方法に関する情報のまとめ後から出てきますが、WordPressには数値のような小さい値を扱うフォームにはtiny-textというクラスが当てられています。表示件数には整数を扱うフォームを。他の解説を読んでこのウィジェットを試作したとき、フォームはテキストフォームで作っていました。この解説を書くために「デフォルトのウィジェットのコードを見ればいいじゃん」と気付き、デフォルトのウィジェットが「タイプ属性にnumberを指定している」ことを突き止めました。・・・(※3)(オープンソースというから、てっきりGithubからtar.gzを取ってこなきゃいけのかと思ってた。Webで閲覧できるとは。)「文字列を整数にキャストするの面倒くせーな」とか思ってたんですが、これなら全角の無効化や入力必須の仕様を実現できそうです。・・・(※4)(※キャストする=変数の型を変換する)ついでに、非現実的な数値は入れられないようにします。最大で15件くらいにしてみましょう。)(※3)デフォルトのウィジェットのソースコードは、WordPress.ORGのwidgets.phpと同じ階層にあるwidgetsディレクトリに入っています。Trac(※4)type=”number”は、HTML5で実装されました。index表示件数の入力フォームの実装は、次のように書くことが出来ます。/></p><?php}※tiny-textクラスにはwidth:45pxが指定されています。これにより、デフォルト(35px)より少し横幅が大きくなっています。利用したinputタグの属性は以下のものです。min...最小値max...最大値step...刻み幅と増減のUI(スピナー:▲▼ボタン)小数点の入力不可(初期値:1)required...入力必須スピナーで最小値は1、最大値は15でストップします。全角の数字は入力しても消えます。半角の少数は入力できますが、(update関数を実装すると)ボタンは「保存しました」に変わりません。空白の場合、入力必須の条件を満たしていないので、少数と同じように保存ボタンが効きません。エルビス演算子で無害化と初期値のセットを同時に行うWordPressデフォルトのウィジェットでは、無害化(サニタイズ)と初期値の宣言を同時に行っています。Tracタイトルの無害化にはesc_attr関数、表示件数の無害化にはabsint関数を使っています。「はてな記号による分岐(?:)」はエルビス演算子(あのエルビス・プレスリーが由来)と呼ぶらしい(PHP5.3で登場)。記号ってググるのが大変なので、読み方は載せるべき派。Qiita$instanceとは?$instanceは、form関数・update関数・widget関数の3つすべてで用いられる変数です。他所の解説を読んでいると当たり前のように$instance変数に手を加えています。Codexには、パラメータの説明に「データベースの保存値」と書かれており、実際に中身をデバッグしてみると、フォームに入力したオプション値が保存されていることがわかりました(Fig5)。Fig5.$instanceをvar_dump関数でデバッグしたもの以上を踏まえると、form関数は次のように書くことができます。現在のオプション値が渡される。}STEP3.クラス関数その2:update関数update関数は、ウィジェットの設定を変更するような入力があった際に、その値を無害化して保存する過程を担います。この関数が空だと、フォームに入力しても保存されません(定義した初期値が呼ばれます)。値を無害化するデータが二つということもあり、他の関数と比べて処理が少ないです(Fig6)。Fig6.update関数を実装するフローチャートCodexのサンプルで、基本的な形を見てみましょう。Documentコメントの方が長いという驚くかもしれない。日本語版$old_instanceの使いみちCodexサンプルコードでは、$old_instanceを使っていませんが、他所のコードを見てみると、関数の冒頭で$old_instanceを保存しています。$old_instance;おそらく、新しく入力した値が適切でない場合に、すでに保存されている値を保持するためだと思われます。空の配列を宣言しているのは、初回で保存されていない場合を想定しているのかもしれません。(具体的な理由を見つけられなかった。)ウィジェットタイトルの無害化Codexのウィジェットタイトルの無害化にはPHPのstrip_tags関数が使われています。デフォルトのウィジェットではWordPressのsanitize_text_field関数が使われています。関数と同じタグ除去アルゴリズムを使用します。Manualユーザーが入力、またはデータベースから取得した文字列を無害化します。日本語版うーん、sanitize_text_field関数の方が用途にあってるから採用しよう。表示件数の無害化form関数にて、type属性に数値しか扱えない”number”を指定しました。そのおかげで、数字(string)を数値(integer)に変換する処理は不要です。それでも、デフォルトのウィジェットでは、int型への型変換が行われています。データ検証を優先して処理をしているのでしょうか?(表示件数の初期値は数値として「5」を指定したため、文字列である心配は要らないでしょう。)update関数のコードはこれだけです。二つのオプション値を無害化するだけなので短いです。$instance;}STEP4.クラス関数その3:widget関数いよいよ、ウィジェットの個性が出る段階です。実際にWebページで表示する視覚的な要素は、PHPを織り混ぜたHTMLが担います(Fig7)。Fig7.widget関数を実装するフローチャートウィジェットを構成するHTMLタグたちwidget関数で主となるのは、Webページで表示される内容です。before_widgetとafter_widget、before_titleとafter_titleが登場し、ウィジェットを構成します。WordPressのテーマを作る上で、functions.phpにダイナミックサイバー(ウィジェットエリア)を記述したことがある人なら見たことがあると思います。これらの値は、$argsに格納されています。日本語版ウィジェットという一つの塊は、まずbefore_widgetでHTMLを吐き出すところから始まります。次にタイトルの前にbefore_title、ウィジェットのタイトルが来て、after_widgetで閉じます。すればウィジェット本体の出番。最後に、after_widgetを出力して終了です。掲載されているコードによっては、ここで渡された値が空かどうかを判定しています。無害化・サニタイズする処理は行われてきましたが、「カラかどうか」「カラなら値をセットする」という処理は、この段階でも行うようです。(初期値としてform関数で宣言した自分としては、違和感がありますが。)デフォルトのウィジェットのコードを読んでみると、バグを起こさないために、absint関数で絶対値かつ整数を取っています。次の行では、false(ゼロ)の場合に、それでは表示件数の意味がないので初期値「5」を代入しています(ゼロは整数)。form関数で最小値を1に指定し、少数の入力を不可にしているのですが、「データを取り出すときも検証する」のが大事ということでしょうか。Tracサブループで最新記事とアイキャッチを表示する最新記事の表示には、WP_Queryに条件を指定しています。以前書いた「関連記事を実装する」記事でも扱ったパラメータを使います。);表示件数は、’posts_per_page‘パラメータに$instance['limit']を検証した$limitを渡しています。新しい順に並べるには、’order’パラメータの初期値’DESC(降順)‘と、'orderby‘パラメータの初期値’post_date(日付)‘で実現できます。「先頭に固定した記事を除外する」’ignore_sticky_posts‘パラメータを有効にしていますが、記事の固定をしない人は記述を省いてもいいと思います。以上のパラメータをもとにサブループを作成すれば、最新記事を取り出すことができます。アイキャッチはループの中でthe_post_thumbnails関数を使って呼び出しています。呼び出すアイキャッチはCSSで縮小した同じ画像です。ダッシュボードの「メディア」では、「アイキャッチという名前」で小さい画像を生成できます(150*150pxとか)。このようにトリミング、あるいは縮小した画像を別途生成することには反対です。とっては重要かもしれません。小さいとはいえど記事(アイキャッチ)の数だけファイルが増えるのは、サーバを管理する側としては重荷です(削除する際、画像の数だけサーバに負担がかかります)。5G」を目前に控える現状に丸投げしてもいいと思います。オーム社、平成13年第1版第1刷発行、ISBN4-274-06406-9、P62widget関数のコードはHTMLを出力する部分が含まれていて長くなっています。register_sidebar()で設定したウィジェットの開始/終了タグ、タイトルの開始/終了タグなどが渡される。データベースの保存値。$args['after_widget'];}さいごに当初は他所様の解説でウィジェットを作ってたんですが、デフォルトウィジェットのコードの存在を知ったときに気づいてしまいました。「これ、アイキャッチを表示するところ以外は同じなんじゃね?」と。ウィジェットを作るハードルを下げるために解説を書こうとして、あれやこれやと調べてまわったのはかなり勉強になりました。それをほぼほぼ載せたものだから、長い記事になってしまったけど。タイムスタンプ投稿しました。18.04アップグレード失敗談【クリーンインストール編】プロフィールchromitz(くろみつ)「自分がつまづいたところは、他の誰かもつまづくだろう。困っている人を助けるために解決策を発信したい」というスタンスでブログを始めました。うつ経験者で、アダルトチルドレン。「動けない完璧主義」を抱えて生きてます。表示件数には整数を扱うフォームを。