WordPressのテーマを作る羽目になったWebエンジニアへ
はじめに
Webエンジニアの皆さん、日々の業務お疲れ様です。皆さんは、さぞや楽しいエンジニアライフを送っていることでしょう。最近は技術の進歩も落ち着いてきましたので、Rustなんかに手を出して、先行者利益を目論んだりしているのではないでしょうか。
さて、そんな楽しい中、たまにやってくる何とも言い難い案件というのが「WordPressのテーマ作成」です。普段、大規模開発や自社サービスに携わっている方は、WordPressに関わることはないかもしれませんが、請負業務やフリーランスの方には、ふと湧いてくる案件でもあります。そして、何かと言い訳を付け、できる限りWordPress関連の案件は避けているのではないでしょうか。
なぜ、エンジニアはWordPressを嫌うのか
エンジニアというのはWordPressを嫌う傾向にありますが、それは何故でしょうか。
-
プライドがゆるさない
WordPress界隈は、初心者が非常に多いです。初心者というか、プログラミングができない人も沢山います。一方、エンジニアと呼ばれる人は、膨大な(本当に膨大な)時間を技術習得に費やして今があると思います。WordPressがよかろうが悪かろうが、初心者と同じような仕事をするというのは、やはりプライドが邪魔をするのではないでしょうか。 -
やることがつまらない
WordPressのテーマ作成は、予めWordPressが用意している関数を設置していく作業が中心となります。エンジニアにとって、これはプログラミングと言えないのかもしれません。 -
セキュリティ的に不安
WordPressは、度たび脆弱性の問題が発生します。クライアントに納品する限り、そのようなシステムはできる限り使いたくはありません。 -
PHPが嫌い
PHPも初心者が非常に多いプログラム言語です。PHPの仕様自体が嫌いな人も多いかもしれませんが、これもプライドが邪魔をすることがあるのではないでしょうか。
他にも色々あると思いますが、要はWordPressとPHPに悪い印象を持っているということです。
WordPressとPHPに対しての誤解
僕がPHPを書いていてよく思うのが、節操のない言語だなということです。思想などは感じられず、流行っていたり便利なものは取り入れるスタンスです。この考え方は、何故かPHPで作られたシステムにも受け継がれ、Laravel(← Rails)やcomposer(← npm)、そしてWordPress(← Movable Type)なども、やはり節操のない感じがします。同じく僕が節操のないフレームワークと感じるVue(← React)がLaravelに標準搭載されていたのも、そのような相性がいいからではないでしょうか。
ですがこれは、悪い事ではありません。「いいものは取り入れる」、これ自体が素晴らしい思想になっています。技術者特有の思想やこだわり、またはプライドは、時には業務やシェア争いの妨げとなります。最初にいいものを作って後で追いこされる、どこかの国のビジネスのようですね。そもそも、何のためにシステム化をしているかというと、効率化です。したがって、とことんまで効率化を考えることは、とてもいいことです。
※ 効率化だけでいいとは言っていません。思想やこだわりは大事です。
つまり、WordPressで済むならWordPressでいいということです。わざわざシステムを組んだり、フロントエンドに分けたりする必要はありません。そして、WordPressとPHPを毛嫌いしているエンジニアの皆さんは、恐らく一昔前のWordPressとPHPを見ています。両者とも、現在ではセキュリティも改善され、機能的にも使いやすく、洗練されてきています。
人生は長いようで短いです。余計なことに時間をかけず、最短ルートで突っ走り、本当にやらなければいけないことに時間をかけましょう!
WordPressのテーマを作る羽目になったWebエンジニアへ
しかし、だからといって、今からWordPressのお作法や関数の仕様を学んでいくのも気が引けると思います。そこで今回は、テーマ作成の一連の流れを通じて、これさえ知っておけば何とかなる箇所を説明しています。そして、順番通りに進めて行けばテーマが完成するような構成になっています。 多少、荒削りではありますが、これを通じてWordPressのテーマ構築を体験してください。
今回は膨大な量となりましたが、記事として無料で公開しました。そして、JavaScriptのBookを有料で公開しております(DOM編は無料)ので、もしよければ、気持ち程度でJavaScriptのBookを読んでやってくださいませ。WordPressでもJavaScriptを使用するシーンが出てきますので。
WordPressのインストール
Local
まずは、ローカル環境でWordPressを操作する際、仮想環境でWordPressの環境を整える、ローカルPC内に直接環境を構築するなどの方法があります。どれも面倒くさそうですが、Flywheelという会社が提供しているLocalというソフトウェアを使用すると、とても簡単にWordPressの環境を準備でき、複数のページを簡単に追加、削除できます。
Localは以下からダウンロードして、インストールを行ってください。
Localを起動したら、中央にCREATE A NEW SITE
というボタンが表示されていますのでクリックします。次に、制作するウェブサイトの名前を入力してCONTINUE
をクリックします。すると、環境の内容を設定する画面に移りますので、特に問題がなければPreferred
を選択してCONTINUE
をクリックしてください。最後に管理者のユーザー名、パスワード、メールアドレスを入力してADD SITE
をクリックすると、次の場所に各環境ごとのディレクトリが構築されます。
PC | パス |
---|---|
Mac | /ユーザー/ユーザー名/Local Sites |
Win | C:\Users\ユーザー名\Local Sites |
構築が完了したら、右上のADMIN
ボタンで管理ページ、OPEN SITE
ボタンでウェブサイトが立ち上がります。その後は、左下の+
ボタンで環境を追加することが可能です。
さて、このLocalですが、各ディレクトリごとに開発環境を作るとはどういう事でしょうか。Webエンジニアなら大体想像がつくと思いますが、一応説明しておきます。
まず、このLocalを提供しているFlywheelですが、WordPress専用のホスティングサービスを提供しています。これは、開発サーバーで編集作業などを行い、完成したら簡単に本番サーバーに移行できるというものです。この仕組みをローカルで実現しているのがLocalとなります。
Localは各ディレクトリごとにVirtualBoxで仮想環境を構築しています。したがって、、Localをインストールすると、一緒にVirtualboxもインストールされます。そして、この仮想環境はDockerで構築されます。この仕組みにより、各ディレクトリごとにApache、Nginxなど別環境を構築することができます。また、Localは仮想環境を構築すると、PC内のhosts
ファイルを書き換えます。これにより、sample.local
などのURLでアクセス可能となります。
サーバー
本番化の際に、サーバーにインストールする方法も説明しておきます。サーバーにnginxかapache、PHPとMySQLがインストールされていることを前提として、説明します。また、ここでは割愛しますが、WordPressで使用するデータベースとユーザーをMySQLで作っておいてください。
まずは、WordPressを公式サイトからダウンロードしましょう。
$ wget https://ja.wordpress.org/latest-ja.tar.gz
ダウンロードした圧縮ファイルを解凍します。
$ tar zxvf latest-ja.tar.gz
圧縮ファイルを解凍するとwordpress
というディレクトリが作成されるので、公開するディレクトリに移動します。
$ mv wordpress/ /var/www/html/wordpress/
圧縮ファイルは必要ないので削除します。
$ rm latest-ja.tar.gz
wordpress
ディレクトリの所有者とグループをnginx(もしくはapache)に変更し、nginxユーザーに対して、wordpress
ディレクトリの読み書き権限を与えます。
$ chown nginx:nginx /var/www/html/wordpress -R &&\
$ chmod -R u=rwX,g=rX,o=rX /var/www/html/wordpress
そのディレクトリに移動します。
$ cd /var/www/html/wordpress
wp-config-sample.php
をwp-config.php
に変更します。
$ mv wp-config-sample.php wp-config.php
wp-config.php
を編集します。
$ vi wp-config.php
# [追加]pluginインストールなどをFTP不要にする
define('FS_METHOD', 'direct');
# データベース名
define('DB_NAME', 'データベース名');
# データベースユーザー名
define('DB_USER', 'ユーザー名');
# データベースパスワード
define('DB_PASSWORD', 'パスワード');
# セキュリティ設定。以下で生成されるシークレットキーに置き換え
# https://api.wordpress.org/secret-key/1.1/salt/
define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');
# データベース内のテーブルプレフィックス(接頭辞)
$table_prefix = 'wp_';
http(s)://ドメイン名/wp-admin/install.php
にアクセスをして、インストールを行ってください。
テンプレート階層
WordPressでは、そのページごとに表示されるテンプレートファイルが決まっています。そして、そのページに紐づくテンプレートファイルは1つではなく、複数のテンプレートファイルが優先順位の下で紐づくようになっています。つまり、優先順位の高いテンプレートが存在しなければ、次のテンプレートが指定されます。これは、ページに対してテンプレートが階層になっていることから、テンプレート階層と呼ばれ、WordPressのテーマ開発には非常に重要な仕組みとなります。
例えば、トップページではfont-page.php
優先順位が最も高くなり、次はWordPressの設定 > 表示設定
で設定した値によってテンプレートファイル名が異なります。そして次にhome.php
が映され、最後にindex.php
が反映されます。
なお、どのページも最終的にはindex.php
が反映されます。つまり、WordPressは極端に言うとindex.php
さえあれば、全てのページを表示させることができます。
個別ページ
WordPressで内容が表示されるページを個別ページといい、個別投稿ページと固定ページに分かれます。ブログの記事のようなページが個別投稿ページで、会社概要などの固定されたページが固定ページとなり、標準では以下のような違いがあります。
個別投稿ページ | 固定ページ | |
---|---|---|
一覧ページ | 作られる | 作れない |
カテゴリーやタグ | 使える | 使えない |
ページの親子関係 | 作れない | 作れる |
個別投稿ページは、ブログ記事や新着情報などのように、次々とページを追加していく傾向があり、固定ページは、会社概要やお問い合わせページなどのように、ページを固定して使い続けるという傾向があります。
テーマ作成の準備
テストデータのインポート
テーマの表示を確認するためには、ある程度の数の投稿が必要になるのですが、これはマユニットテストデータを使用すると便利です。まずは、以下のGithubからデータをダウンロードしましょう。下が日本語のデータとなります。
wordpress-theme-test-data-ja.xml
がダウンロードされますので、ツール > インポート > WordPress
から今すぐインストール
をクリックしてインポーターをインストールしてください。インストール後、インポーターの実行
をクリックして、wordpress-theme-test-data-ja.xml
をインストールしてください。すると、投稿者の割り当て設定の画面が出てきますので、とりあえずはそのまま実行をクリックしてください。テストデータがインポートされるのですが、メディアのインポートに失敗しました
と多く表示されます。これは画像のインポートができていないという意味ですので、特に問題はありません。投稿を確認すると、数多くの投稿がインポートされているのが確認できます。これらの投稿は、タイトルの文字数が極端に長いものなど、表示ミスに繋がりやすい投稿となっております。
テーマの配置
管理画面の外観 > テーマ
を見てみると、既にいくつかのテーマがインストールされています。そして、これらのテーマはLocalを使用している場合、標準では以下のディレクトリ内に格納されています。
PC | パス |
---|---|
Mac | /ユーザー/ユーザー名/Local Sites/作成したWebサイト名/app/public/wp-content/themes |
Win | C:\Users\ユーザー名\Local Sites\作成したWebサイト名\app\public\wp-content\themes |
ようは、wp-content/themes
に格納されているということです。themes
ディレクトリ内を確認すると、インストールされているテーマらしいディレクトリが確認できます。では、themes
ディレクトリ内に例えばsample
などと適当なディレクトリを設置してみましょう。そして、管理画面の外観 > テーマ
を見てみると、左下に壊れているテーマ
と表示されています。つまり、WordPressは themesディレクトリにディレクトリを設置するだけでテーマとして認識します。 ただし、壊れているテーマ
となっています。そして、その下にはスタイルシートが見つかりません。
という忠告が表示されています。
では、忠告通りに先ほど作成したsample
ディレクトリに、style.css
を追加しましょう。すると忠告が次のように変更されています。
テンプレートが不足しています。独立したテーマには index.php テンプレートファイルが必要です。
子テーマでは style.css スタイルシートにテンプレートヘッダーが必要です。
index.php
テンプレートファイルが必要だとのことですので、同じくsample
ディレクトリに、index.php
を追加しましょう。すると、インストールされているテーマの一覧に、ディレクトリ名のテーマとして同じように表示されています。そして、有効化ボタンも設置されていますので、クリックしてみましょう。有効化されるのですが、index.php
にはなにも記述していませんので、ブラウザー上では何も表示されません。
つまり、WordPressはthemesディレクトリにディレクトリを設置し、その中にindex.phpとstyle.cssが存在すればテーマとして成り立つということです。
index.php
index.php
はテンプレート階層の最下層のテンプレートとなり、PHPですのでここに記載したHTMLはそのまま表示されます。つまり、通常のPHPとして作成するのですが、WordPress独自の関数が使用できるという特徴があります。例えば、次のように記述すると最新記事のタイトルが取得され表示されます。
<h1><?php the_title(); ?></h1>
style.css
style.css
には、もちろんCSSを設定してテンプレートから読み込むことができます。ただし、CSSの設定は特にstyle.css
でなければいけないという決まりはなく、別のCSSファイルで設定しても問題はありません。では、なぜstyle.css
が必要かといいますと、style.css
はテーマの設定も担っているからです。例えば、次のようにコメントとしてTheme Name
を設定してください。
/*
Theme Name: Sample Theme
*/
管理画面でテーマの名前が変更されます。このように、style.css
はテーマの各設定を行うことが可能です。設定できる項目は以下となります。全て設定する必要はなく、必要なものだけ設定すればいいです。ただし、配布する場合は日本語を使用できませんので、英語で設定してください。
Theme Name | テーマの名前 |
---|---|
Theme URI | テーマの配布元 |
Author | 作成者 |
Author URI | 作成者のURL |
Description | 説明 |
Version | バージョン |
License | ライセンス |
License URI | ライセンスのURI |
Tags | タグ |
Text Domain | テーマのドメイン名。 |
screenshot.png
カレントディレクトリにscreenshot.png
という画像ファイルを設置すると、テーマ一覧に画像が表示されます。なお、スクリーンショットの推奨サイズは、幅1200px・高さ900pxとなっております。
子テーマ
今回は使用しませんが、子テーマとは親テーマから設定を引き継ぐテーマです。子テーマは、style.css
にTemplate
を設定します。
/*
Theme Name: Sample Theme
Author: ANTEZ
Version: 1.0.0
Template: twentytwenty
*/
Template
は、親テーマとなるテーマのディレクトリ名を設定します。これにより、それが親テーマとして設定されます。そのため、index.php
が存在しなくてもエラーにはなりません。そして、テーマを開くと「これはxxxxxxの子テーマです。」とのメッセージが表示されています。
子テーマを有効化すると、親テーマを引き継いでいますので、その内容が表示されます。ただし、スタイルシートは引き継がれませんので、何らかの方法で引き継ぐ必要があります。例えば、親テーマのstyle.css
の冒頭の設定コメント以外を子テーマのstyle.css
にコピペします。また、子テーマは親テーマを上書きしたいテーマを新規作成することにより、カスタマイズします。
テンプレートの準備
さて、テーマの準備が整いましたので、ここからindex.php
を作成し、必要ならば他のファイルも作成していくのですが、今回はHTMLとCSSの説明はできるだけ省きたいです。そこで、WordPressのテーマ作成によく使用される、Clean Blogというテンプレートをベースに構築していきたいと思います。これは、Start BootstrapというBootstrapのテンプレートを扱うサイトからダウンロードできます。
ダウンロードをしたら、現在のsample
ディレクトリは削除して、Clean Blogのディレクトリ名をsample
に変更して、themes
ディレクトリ内に設置してください。
style.css
を、例えば以下のように記述して設置します。
/*
Theme Name: Sample Theme
Author: TEST
Description: This is a my theme.
Version: 1.0
*/
index.html
をindex.php
に変更すると、テーマとして認識されるようになりますので、有効化しましょう。ただし、相対パスの指定が合っていないため、スタイルが効いていません。とりあえずは次のように絶対パスで指定してください。後ほど、適切な設定に変更します。
<link href="//mysite.local/wp-content/themes/sample/css/styles.css" rel="stylesheet" />
なお、https://fonts.googleapis.com/
などとURL指定している箇所は、https
が変更される可能性があります。このような場合、//
から指定するとその時のプロトコルで読み込まれます。
<link href='//fonts.googleapis.com/css?...' rel='stylesheet' type='text/css'>
スターターテーマ
先ほどダウンロードをしたテンプレートは、あくまでもBootstrapのテンプレートですので、WordPressとは関係のないものです。したがって、テーマ作成的には、ゼロベースから構築するのと変わりません。ただし、毎回ゼロベースから構築するのは大変です。そこで、今回は使用しませんが、スターターテーマという基本的な構造が予め用意されたテーマをもとに作成すると便利です。これは、時間の短縮になるのは勿論ですが、テーマの構成の学習にも繋がります。
スターターテーマは沢山存在しますが、s(UNDERSCORES)
というWordPress開発元であるAutomatticによるスターターテーマがお勧めです。シンプルなスターターテーマとなっており、Twenty NineteenやBusinessPressもこれをもとに作成されています。
公式サイトにアクセスして、Theme Nameに作成したいテーマ名を入力しGENERATEをクリックすると、テーマをZIPファイルをダウンロードできます。ダウンロードが完了したら、テーマ > 新規追加
からテーマのアップロード
ボタンをクリックして、ダウンロードしたZIPファイルを選択してください。すると、スターターテーマがインストールされますので、有効化をしてください。
テンプレートパーツ
index.php
を、更にテンプレートパーツとして分けて行きましょう。head
要素の内容のみをheader.php
、footer
要素の内容のみをfooter.php
に切り分けてください。
<meta charset="utf-8" />
……
<!-- Core theme CSS (includes Bootstrap)-->
<link href="//sample.local/wp-content/themes/sample/css/styles.css" rel="stylesheet" />
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
……
</div>
</div>
この、header.php
とfooter.php
は特別なファイルで、これを呼び出す関数が、予めWordPressでは用意されています。
なお、テンプレートパーツとしてどの様に分けるかは、様々な考え方があります。この場合、</header>
から上をheader.php
とする人も多いのではないでしょうか。今回は、head
要素の内容のみをテンプレートとしていますが、これはページによってはhead
要素内に別の要素を追加する可能性を想定しています。その場合、テンプレート内で条件分岐させることもできますが、冗長的になる恐れもあるため、このようにしています。また、タグを跨がないようにテンプレート作成し、HTMLの関連性が分かりにくくなるのを防いでいます。
関数とテンプレートタグ
WordPressには、専用の関数が多数用意されています。その中でも、テンプレートの中で使用する物をテンプレートタグといいます。関数とテンプレートタグは数多く存在し、次のウェブサイトから調べることができます。
では、この関数とテンプレートタグを使用して、header.php
とfooter.php
を仕上げて行きましょう。
get_header()、get_footer()
get_header() はheader.php
を、get_footer() はfooter.php
を読み込むことがでる関数です。パラメーターを指定するとheader-パラメーター.php
、footer-パラメーター.php
を読み込みます。例えば、次はheader-foo.php
、footer-bar.php
を読み込んでいます。
get_header("foo");
get_footer("bar");
では、index.php
を次のように更新してください。
<head>
<?php get_header(); ?>
</head>
……
<footer class="border-top">
<?php get_footer(); ?>
</footer>
get_template_part()
get_template_part() はヘッダー、サイドバー、フッターを除いたテンプレートパーツを読み込む関数です。テンプレートパーツは自由に作成することが可能で、第1パラメータにはテンプレートパーツへのパスを指定します。なお、各拡張子は省略可能です。では、nav
要素をincludes/nav.php
に、header
要素をincludes/header-main.php
に切り分けて下さい。
<nav class="navbar navbar-expand-lg navbar-light" id="mainNav">
……
</nav>
<header class="masthead" style="background-image: url('assets/img/home-bg.jpg')">
……
</header>
では、includes/nav.php
を次のように読み込んでください。
<!-- Navigation-->
<?php get_template_part("includes/nav"); ?>
次にincludes/header-main.php
を読み込みます。第2パラメータに指定した文字列は、第1パラメータのパスに-
で繋げられ、それがパスとなります。
<!-- Page Header-->
<?php get_template_part("includes/header", "main"); ?>
wp_head()、wp_footer()
wp_head() は、wp_headアクションというものをスタートさせる関数で、</head>
タグの直前で使用します。
<?php wp_head(); ?>
</head>
wp_footer() もwp_headアクションをスタートさせる関数で、</footer>
タグの直前で使用します。
<?php wp_footer(); ?>
</footer>
この2つのタグを設置することにより、プラグインなどを適用することが可能となります。したがって、この2つのタグの設置はほぼ必須となります。
また、ログインをしている状態だと、ページ上部にアドミンバーが表示されます。ただし、このアドミンバーは確認する際に邪魔になる場合もあります。その場合、管理画面のユーザーからユーザー名をクリックして、サイトを見るときにツールバーを表示する
のチェックを外してください。その他にも、WordPressやウェブブラウザのプラグインで非表示などにすることができます。
get_template_directory_uri()
get_template_directory_uri() は、有効化しているテーマのディレクトリのURIを取得する関数です。末尾にスラッシュは付きません。
例えば、CSSの読み込みを絶対パスで指定しましたが、URLは変更される可能性があります。そのような個所はget_template_directory_uri()
で指定したほうがいいでしょう。
<link href="<?php echo get_template_directory_uri(); ?>/css/clean-blog.min.css" rel="stylesheet">
home_url()
home_url() は、利用中のWordPressのホームURLを返すテンプレートタグです。第1パラメータにパスを設定すると、ホームURLからなる絶対パスを返します。なお、ホームURLとは一般設定のサイトアドレスで設定しているURLです。ちなみに、同じ一般設定にあるWordPressアドレスとは、WordPressをインストールした場所です。
<a class="navbar-brand" href="<?php echo home_url('/'); ?>">Start Bootstrap</a>
esc_url()
esc_url() は属性をエスケープ処理する関数です。セキュリティの面からデータベースなどから取得した内容を直接出力するのは、好ましくありません。そこで、エスケープ処理を行ってから出力するようにします。この他にも、HTMLをエスケープ処理するesc_html()
や属性をエスケープ処理するesc_attr()
など、いくつかのエスケープ処理を行う関数が存在しますので、次のページから確認してください。
例えば、先ほどのURLは次のように出力します。
<?php echo esc_url(home_url('/')); ?>">
bloginfo()
bloginfo() は、利用中のWordPressの情報を表示するテンプレートタグです。表示させたい項目をパラメータに設定し、例えばname
はタイトル、description
はキャッチフレーズとなります。
以下は、左上のサイト名と、TOPページのタイトルと説明をbloginfo()
で表示しています。
<a class="navbar-brand" href="<?php esc_url(home_url('/')); ?>"><?php bloginfo('name'); ?></a>
<h1><?php bloginfo('name'); ?></h1>
<span class="subheading"><?php bloginfo('description'); ?></span>
functions.php
functions.phpはテーマの中の全てのファイルが参照してるファイルです。したがって、テーマのPHP関数をまとめて管理することができます。
また、WordPressにはさまざまな段階で発火するイベントトリガーである、アクションフックとフィルターフックという2種類のフックと呼ばれるものが用意されており、functions.php
で設定することが可能です。両方とも第1パラメータに発火のタイミング、第2パラメータに処理をする関数を設定します。
では、カレントディレクトリにfunctions.php
を作成してください。
add_action()
アクションフックは、特定のポイントやイベント発生時に起動され、何らかのアクションを起こします。
次は、Codexで公開されているアクションフックの一覧ですが、ほぼ実行順に並んでいます。ini
があり、次のように設定します。関数を別で定義してもいいですが、大抵は無名関数として設定します。
add_action('init', function() {
echo '<!-- This is a comment. -->';
});
他にも、ヘッダーテンプレートファイルがロードされる前に実行されるget_header
などがあります。
add_filter()
フィルターフックは、何らかのタイミングで値を受け取り、更新して返します。the_title
を設定します。以下は、そのタイミングでタイトルの文字列の前に★
を追加しています。
add_filter('the_title', function($title) {
return '★' . $title;
});
このように、フィルターを通すと値が加工されて返ってくることになります。
次は、全てのユーザーでアドミンバー(ページ確認時に上部に表示されるバー)を非表示にします。
add_filter('show_admin_bar', '__return_false');
TOPページ
では、TOPページを完成させて行きましょう。今回は、index.php
をTOPページのテンプレートとします。まずは、Post preview
とDivider
の箇所を1つ分だけ残して、後は消去しておいてください。
<!-- Post preview-->
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">Man must explore, and this is exploration at its greatest</h2>
<h3 class="post-subtitle">Problems look mighty small from 150 miles up</h3>
</a>
<p class="post-meta">
Posted by
<a href="#!">Start Bootstrap</a>
on September 24, 2022
</p>
</div>
<!-- Divider-->
<hr class="my-4" />
language_attributes()
language_attributes() は、WordPressの設定をもとに言語属性を表示する関数です。
<html <?php language_attributes() ?>>
body_class()
body_class() は、その状態によってbody
要素にクラスを付与してくれる関数です。例えば、管理画面にログインをしている状態ですとlogged-in
というクラスが追加され、記事ページですとpostid-123
などと追加されます。これにより、その状態によってスタイルシートを設定することが可能となります。どのようなクラスが追加されるかは、次を確認してください。
では、以下のようにbody
タグの中に設置してください。
<body <?php body_class() ?>>
wp_body_open()
wp_body_open() は、body
タグ直下に設定をして、そこにスクリプトなどを表示することができる関数です。出力する内容を後述するfunctions.php
などに記述すると、wp_body_open()
にフックすることができます。
<body <?php body_class() ?>>
<?php wp_body_open() ?>
add_action('wp_body_open', function() {
echo '<!--wp_body_open action hook-->';
});
the_title()
the_title() は、現在の投稿のタイトルを表示するテンプレートタグであり、ループ内で使用します。単体で使用すると、最新の投稿のタイトルを表示しますが、ブログのトップに固定に設定している投稿があると、そのタイトルが表示されます。
なお、表示ではなく取得するにはget_the_title()
を使用します。
<h2 class="post-title"><?php the_title(); ?></h2>
また、第1パラメータ、第2パラメータで前後の表示を設定でき、第3パラメータをfalse
にすることで値を返すことができます。例えば、次のようにすることも可能です。
<?php $title = the_title('<h2 class="post-title">', '</h2>', false); ?>
<?php echo $title; ?>
文字数の制限
このままでは、設定したタイトルの文字数全てが表示されてしまいます。この場合、タイトルを表示ではなく取得するget_the_title()
を使用し、PHPのmb_substr()
で出力文字の制限を行いましょう。
<h2 class="post-title"><?php echo mb_substr(get_the_title(), 0, 25) . '...'; ?></h2>
これで、先頭から25文字までの文字列が摘出され、末尾に...
が付与されます。ただし、これでは25文字以内の文字列でも...
が付与されてしまいます。しががって、以下のように文字数で条件分岐を行いましょう。
<h2 class="post-title">
<?php
if (mb_strlen( $title = get_the_title() ) > 25) {
$title = mb_substr($title, 0, 25);
echo $title . '...';
} else {
echo $title;
}
?>
</h2>
the_excerpt()
the_excerpt() は、投稿の抜粋を表示するテンプレートタグであり、ループ内で使用します。単体で使用すると、最新の投稿の抜粋を表示します。抜粋が入力されていなければ、本文が最初の55文字(英数字)に省略されて表示されます。その場合、HTMLタグは取り除かれます。なお、表示ではなく取得するにはget_the_excerpt()
を使用します。
<h3 class="post-subtitle"><?php the_excerpt(); ?></h3>
the_author()
the_author() は、投稿者を表示するテンプレートタグであり、ループ内で使用します。なお、表示ではなく取得するにはget_the_author()
を使用します。
単体での使用はできませんので、以下の設定は今のところ表示されません。
<a href="#!"><?php the_author(); ?></a>
get_the_author_meta()
get_the_author_meta() は、ユーザーのメタデーターを返えす関数です。第1パラメータに、取得したいデーター項目を設定します。また、ループ内で使用すると、現在の投稿者のデーターを返しますが、ループ外では使用する場合、第2パラメータにユーザーIDを指定する必要があります。
以下は、ループ内で投稿者のIDを取得しています。
get_the_author_meta( 'ID' )
get_author_posts_url()
get_author_posts_url() は、指定した作成者のアーカイブページのURLを取得します。第1パラメータは、取得する作成者のIDを設定します。第1パラメータは、取得する作成者のスラッグとなり、省略可能です。
以下は、get_the_author_meta()でIDを指定しています。
<a href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>"><?php the_author(); ?></a>
the_permalink()
the_permalink() は、投稿のパーマリンクを表示するテンプレートタグであり、ループ内で使用します。単体で使用すると、最新の投稿のパーマリンクを表示します。なお、表示ではなく取得するにはget_permalink()
を使用します。
<div class="post-preview">
<a href="<?php the_permalink(); ?>">
このURI はWordPressのパーマリンクの設定によって、取得する形式が決まります。投稿名で設定している場合、日本語のパーマリンクは好ましくありません。その場合、投稿画面のパーマリンクで適切なURLスラッグを設定してください。どちらにせよ、投稿名での設定は固定ページと被る恐れがあるので、別の設定がいいでしょう。なお、URLスラッグは公開、または下書き保存しないと設定できません。ちなみに、固定ページはページ属性で親ページを設定すると、URLスラッグを階層にできます。
パーマリンクの設定を行うと、Apacheの場合.htaccess
が更新されます。この.htaccess
を手動で間違った更新をしたり、削除したりするとアクセスができなります。その場合は、再度パーマリンクの設定を行うと、.htaccess
が更新されます。
the_date()
the_date() は、記事の投稿・更新日を表示し、同じ日に複数の投稿がある場合は最初の投稿にのみ表示するテンプレートタグであり、ループ内で使用します。
単体での使用はできませんので、次の設定は今のところ表示されません。
on <?php the_date(); ?>
表示書式はWordPressの設定で決まるのですが、第1引数で指定することも可能です。また、第2引数と第3引数は前後の表示、第4引数はfalse
で値を返します。なお、get_the_date()
でも時刻を返すことができ、かつ全ての投稿で返します。例えば、次のようにすることも可能です。
<?php $date= the_date('Y-m-d', '<h2>', '</h2>', false); ?>
<?php echo $date; ?>
the_time()
the_time() は、投稿の公開時刻を表示するテンプレートタグであり、ループ内で使用します。単体で使用すると、最新の投稿の公開時刻を表示します。また、the_date()
と違い全ての投稿に表示されます。かつ、引数で書式指定ができ、年月日も出力先可能ですので、the_date()
の代わりとしても使用できます。なお、時刻を返すにはget_the_time()
を使用します。
on <?php the_time('Y年n月j日 g:i a'); ?>
get_option()
get_option() は、一般設定を取得する関数です。例えば、次は日付のフォーマットを取得しています。
on <?php the_time(get_option('date_format')); ?>
その他にも、様々なパラメーターが存在しますので、以下で確認してください。
the_post()
the_post() は、次の投稿を取得する関数です。例えば、the_post()
で投稿を取得した後でthe_title()
を使用すると、その投稿のタイトルを取得することができます。そして、再びthe_post()
を使用すると、2つ目の投稿を取得します。
次は、最新の投稿から2つ目の投稿までのタイトルを、取得しています。
<?php
the_post();
the_title();
the_post();
the_title();
?>
このように使用すると投稿を表示していくことができるのですが、投稿の数だけ記述するのは現実的ではありません。そこで、次に紹介するhave_posts()
と併用して、投稿を表示させます。
have_posts()
have_posts() は、投稿記事があればtrue
を、なければfalse
を返す関数です。
次は、記事がある場合はタイトルを表示、ない場合はメッセージを表示しています。
<?php if(have_posts()): ?>
<!-- Post preview-->
<div class="post-preview">
……
<hr class="my-4" />
<?php else: ?>
<p>Article not found.</p>
<?php endif; ?>
また、have_posts()
は次のようにwhile
でループで使用することが可能です。
<?php if(have_posts()): ?>
<?php while (have_posts()): ?>
<?php the_post(); ?>
<!-- Post preview-->
<div class="post-preview">
……
<hr class="my-4" />
<?php endwhile; ?>
<?php else: ?>
<p>Article not found.</p>
<?php endif; ?>
投稿記事があればtrue
を返し、the_post()
が使用されると残りの記事に関して判定を行います。つまり、the_post()
で全ての記事を取得するとfalse
となりループは終了します。したがって、the_post()
で記事を取得しないと無限ループとなりますので注意してください。
get_the_ID()
get_the_ID() は、現在の投稿のIDを取得する関数です。ここでは使用しませんが、よく使う関数ですので覚えておきましょう。
get_the_ID();
個別投稿ページ
では、個別投稿ページを作成しましょう。テンプレート階層を確認すると、固定ページは個別投稿ページと固定ページの共通のテンプレートはsingular.php
となっており、個別投稿ページ類の共通のテンプレートはsingle.php
となっています。したがって、今回はsingle.php
を作成します。既にあるpost.html
をsingle.php
にリネームして、Post Content以外をindex.php
に合わせてください。
add_theme_support()
add_theme_support() は、テーマやプラグインに特定の機能を使用可能とする関数です。functions.php
内で設定します。
個別ページではアイキャッチ画像を使用しますので、add_theme_support()
でアイキャッチ画像が使用できるようにしましょう。
add_action('init', function() {
add_theme_support('post-thumbnails');
});
init
で初期化のタイミングを指定しています。add_theme_support()
の引数にpost-thumbnails
と設定していますが、これがアイキャッチ画像を指定しています。他の値は以下を確認してください。
これで、管理画面にアイキャッチ画像の項目が追加されます。
また、引数にtitle-tag
を渡すことで、title
タグを表示します。TOPページならタイトル名-サブタイトル
、その他のページなら、ページタイトル-タイトル
となります。
add_action('after_setup_theme', function() {
add_theme_support( 'title-tag' );
});
add_action
のafter_setup_theme
は、テーマが読み込まれた後にフックする、一番タイミングの早いフックとなります。なお、title-tag
でtitle
タグを表示しますので、
ループ
WordPressのループとは、投稿の情報を取得している間という意味なので、投稿を1つだけ取得する場合にもループは使用することになります。今回の場合だと、<header>
タグから</article>
タグの終わりまでをループさせます。
<?php if (have_posts()): ?>
<?php while (have_posts()): the_post(); ?>
<!-- Page Header-->
<?php get_template_part("includes/header"); ?>
<!-- Post Content-->
<article class="mb-4">
……
</article>
<?php endwhile; ?>
<?php endif; ?>
<!-- Footer-->
なお、single.php
は記事が存在しないということはあまりなく、なかった場合は404
を返す仕様となっております。ただし、念のためif (have_posts()):
内に記述していった方がいいでしょう。その場合、仕様上else
の設置は必要ありません。
the_content()
athe_content() は、投稿の本文を出力するテンプレートタグです。ループ内で使用します。
<div class="col-md-10 col-lg-8 col-xl-7">
<?php the_content(); ?>
</div>
the_post_thumbnail()
the_post_thumbnail() は、アイキャッチ画像を表示するテンプレートタグです。ループ内で使用し、サイズと属性を設定することが可能です。
第1引数はサイズの設定で、thumbnail
、medium
、large
、full
を指定でき、これらは管理画面の設定 > メディア
で設定できます。またはarray( 横, 縦 )
で指定できます。
第2引数は属性の設定となり、array('属性名'=>'値')
で複数設定可能です。
the_post_thumbnail(array(800, 300), array('alt'=>'アイキャッチ画像'));
wp_get_attachment_image_src()
wp_get_attachment_image_src() は、第1引数でID指定した画像のurl
、width
、height
属性とリサイズされているかどうかを配列として返す関数です。配列は次のようになります。
- [0] => url
- [1] => width
- [2] => height
- [3] => 真偽値
また、第2引数にthumbnail
、medium
、large
、full
とサイズを指定でき、初期値はthumbnail
です。またはarray( 横, 縦 )
でも指定できます。
次は、画像のURLを表示しています。
$img = wp_get_attachment_image_src(15, "large");
echo $img[0];
なお、画像IDとは管理画面のメディア > ライブラリ
で画面を選択した際に表示されるURLのitem
パラメーターで確認できます。
get_post_thumbnail_id()
get_post_thumbnail_id() は、設定されているアイキャッチ画像のIDを返すテンプレートタグです。次は、取得したIDをwp_get_attachment_image_src()
で使用して、アイキャッチ画像の情報を取得しています。
$id = get_post_thumbnail_id();
$img = wp_get_attachment_image_src($id);
echo $img[0]; // URLを出力
has_post_thumbnail()
has_post_thumbnail() は、その投稿にアイキャッチ画像が設定されているかのチェックを行い、設定されていればtrue
を返す関数です。
次は、アイキャッチ画像が設定されていなければ、指定の画像を表示するようにしています。
<?php
if (has_post_thumbnail()) {
$id = get_post_thumbnail_id();
$img = wp_get_attachment_image_src($id, "large");
} else {
$img = array(get_template_directory_uri() . '/assets/img/about-bg.jpg');
}
?>
<header class="masthead" style="background-image: url('<?php echo $img[0]; ?>')">
なお、このような他のテンプレートでも使用するような処理は、functions.php
で関数としてまとめた方がいいでしょう。
function getEyecatchUrl() {
if (has_post_thumbnail()) {
$id = get_post_thumbnail_id();
$img = wp_get_attachment_image_src($id, "large");
} else {
$img = array(get_template_directory_uri() . '/assets/img/about-bg.jpg');
}
return $img[0];
}
header-single.php
を作成して、投稿詳細が表示されるようにし、functions.php
で定義した関数で背景画像を表示しましょう。
<header class="masthead" style="background-image: url('<?php echo getEyecatchUrl(); ?>')">
……
<h1><?php the_title(); ?></h1>
<p class="subheading">
Posted by
<a href="#!"><?php the_author(); ?></a>
on <?php the_time('Y年n月j日 g:i a'); ?>
</p>
……
</header>
コメント
コメントのテンプレートは、comments.php
となりますので作成してください。
<div class="my-5">
<p>コメントフォーム</p>
</div>
comments_template()
comments_template()
は、コメントテンプレートを読み込みます。第1パラメータはロードするファイルの指定で、デフォルト値はcomments.php
となります。第2パラメータはtrue
でコメントとトラックバックを分け、デフォルト値はfalse
となります。
<div class="col-md-10 col-lg-8 col-xl-7">
<?php the_content(); ?>
<?php comments_template(); ?>
</div>
comments_open()
comments_open()
は、現在のページにコメントが許可されていればtrue
を返す関数です。コメントの許可は、管理画面の投稿ページのディスカッションにあるコメントを許可
で行えます。
<?php
if (comments_open()) {
comments_template();
}
?>
get_comments_number()
get_comments_number()
は、現在のページのコメント、トラックバック、ピンバックの合計数を取得する関数です。パラメータには投稿のID、または投稿オブジェクトを指定することもでき、デフォルト値は現在の投稿である0となります。
次は、現在のページにコメントが許可されいる、または、何らかのコメントがある場合にコメントのテンプレートを取得しています。
<?php
if (comments_open() || get_comments_number()) {
comments_template();
}
?>
have_comments()
have_comments()
は、次のコメントデータが存在するかを判定する関数です。存在するればtrue
を、存在しなければfalse
を返します。
<div class="my-5">
<?php if( have_comments() ): ?>
<p>コメント</p>
<?php endif; ?>
</div>
wp_list_comments()
wp_list_comments()
は、コメントを表示するテンプレートタグです。第1パラメータには、各設定を配列で設定し、それらには初期値が設定されています。内容に関しては次を確認してください。
<?php if( have_comments() ): ?>
<ol>
<?php
wp_list_comments(array(
'style' => 'ol',
'reply_text' => '返信!',
));
?>
</ol>
<?php endif; ?>
comment_form()
comment_form()
は、コメントフォームを出力する関数です。第1パラメータには、各設定を配列で設定し、それらには初期値が設定されています。内容に関しては次を確認してください。
<div class="my-5">
<?php if( have_comments() ): ?>
……
<?php endif; ?>
<?php
comment_form(array(
'title_reply' => 'コメントを書く',
'label_submit' => 'コメントを送信!',
));
?>
</div>
固定ページ
固定ページは基本的にpage.php
が呼び出されますので、今回はsingle.php
をコピーしてpage.php
を作成します。そして、header-single.php
をコピーしてheader-page.php
を作成し、投稿詳細を削除します。
<div class="site-heading">
<h1><?php the_title(); ?></h1>
</div>
<?php get_template_part("includes/header", "page"); ?>
カスタムページテンプレート
固定ページでは、page.php
よりも優先度が高いpage-テンプレートID.php
があり、更に優先度が高いpage-スラッグ.php
があります。これらを使用して、それぞれの固定ページごとにテンプレートを作成してもいいのですが、同じテンプレートを使用する場合でもテンプレート作成するため冗長的になります。その場合、管理画面から固定ページに設定できるカスタムページテンプレートを使用します。
カスタムページテンプレートとは、固定ページの中で一番優先度の高いテンプレートとなります。ファイル名は何でもいいのですが、必ず次のコメントをファイル内に設置する必要があります。
/*
Template Name: テンプレート名
*/
例えば、page-custom-sample.php
というファイルを作成して、次のコメントを設置してください。
/*
Template Name: サンプルテンプレート
*/
すると、固定ページの編集ページにテンプレートという項目が追加され、作成したテンプレートを選択できるようになっています。
TOPページへの反映と投稿ページ一覧
標準では、TOPページには投稿ページの一覧が最新の投稿順位表示される設定になっています。これを個別ページに変えるには、管理ページの設定 > 表示設定 > ホームページの表示
で固定ページを選択して、ホームページを表示したい固定ページにしてください。
また、固定ページに投稿ページの一覧を表示させることもできます。同じく、ホームページの表示
で固定ページを選択して、投稿ページでどの固定ページ反映させるかを選択してください。
カテゴリーとタグ
カテゴリーは、管理画面のカテゴリ-から作成することが可能で、タグと違い親カテゴリーを設定することができます。また、投稿でカテゴリーを設定しないと、標準ではUncategorized
というカテゴリーが設定されます。この初期設定は、設定 > 投稿設定 > 投稿用カテゴリーの初期設定
から設定できます。何も設定しない場合は、一度投稿してから設定を外す必要があります。一方タグの場合は、最初から何も設定しないことが可能です。
投稿には、何らかのカテゴリーが設定されていることが望ましいです。したがって、Uncategorized
を一番頻繁に設定するカテゴリーに変えておけばいいでしょう。タグは、カテゴリーでは分類しにくい細分化として使用することが多いです。つまり、明確なルールはありませんが、カテゴリーを大分類とし、そこからさらにタグで分けるイメージとなります。カテゴリーは必要最低限の数にして、あとはタグを設定すればいいでしょう。
なお、固定ページはカテゴリーとタグを設定することができませんが、WordPressには別で紹介するカスタム分類(custom taxonomy) という機能があり、それで分類することが可能です。なお、カスタム分類は投稿でも使用可能です。
カテゴリーページは/category/カテゴリーのスラッグ/
でアクセスができます。この/category/
の箇所は、設定 > パーマリンク設定 > オプション > カテゴリーベース
で設定できます。
カテゴリーとタグは、それぞれ個別のテンプレートが用意されていますが、今回は共通のテンプレートであるarchive.php
を使用します。投稿の一覧表示をするためindex.php
をベースとして作成しますので、index.php
をコピーしてarchive.php
にしてください。そして、header-main.php
をコピーしてheader-archive.php
を作成し、読み込んでください。
<!-- Page Header-->
<?php get_template_part("includes/header", "archive"); ?>
wp_title()
wp_title() は、現在のページのタイトルを表示または取得するテンプレートタグです。第1パラメータは、タイトルの区切り文字の設定となり、デフォルトでは»
となっています。区切り文字が必要ないのなら、''
と設定してください。第2パラメータはtrue
で表示(デフォルト)、false
で取得となります。第3パラメータは、区切り文字の位置指定となり、right
ならタイトルの右端、それ以外で左端(デフォルト)に表示します。
<h1>Category</h1>
<span class="subheading"><?php wp_title(''); ?></span>
is_category()
is_category() は、カテゴリーアーカイブが表示されていればtrueを返します。このように、is_*** 形式のテンプレートタグは条件分岐タグと呼ばれており、他にも沢山の条件分岐タグが存在します。Category
を表示しています。また、同じ条件分岐タグであるis_date()
を使用して、DateアーカイブならDate
を、is_author()
を使用してAuthorアーカイブならAuthor
を表示します。そして、どれにも当てはまらないのならTag
を表示しています。
<div class="site-heading">
<?php if(is_category()): ?>
<h1>Category</h1>
<?php elseif(is_date()): ?>
<h1>Date</h1>
<?php elseif(is_author()): ?>
<h1>Author</h1>
<?php else: ?>
<h1>Tag</h1>
<?php endif; ?>
<span class="subheading"><?php wp_title(''); ?></span>
</div>
メニュー
register_nav_menu()
register_nav_menu() は、ナビゲーションメニューを登録します。この設定を行うと、カスタムメニューエディタが使用できるようになります。functions.php
に次のように設定をして下さい。
add_action('init', function() {
register_nav_menus([
'globalNav' => 'グローバルナビゲーション',
'footerNav' => 'フッターナビゲーション',
]);
});
管理画面の外観にメニュー
が追加されています。
メニューを編集
タブからメニューを作成できますので、メニュー構造のメニュー名を入力してください。例えば、グローバルナビゲーション
などと入力して、メニューを作成
ボタンをクリックします。
メニュー項目を追加
から、メニューを追加できます。例えば、よくあるホームを追加する場合、カスタムリンクのURLを/
、リンク文字列をホーム
にしてメニューに追加ボタン
をクリックします。すると、メニュー構造
にメニューが追加されますので、いくつか追加してください。
メニュー構造
にメニューはマウス操作で移動でき、右にずらすと、ロールオーバーで表示する階層構造にすることができます。また、メニューの位置
には設定したナビゲーションが表示されていますので、どこに表示するかを選択してください。今回はグロナビしか使用しません。すべて設定できたら、メニューを保存
をクリックして登録してください。
メニューの編集
が完了したら、位置を管理
タブでテーマの位置に指定されたメニューが設定されているのを確認してください。
wp_nav_menu()
wp_nav_menu() は、ナビゲーションメニューをリスト表示するテンプレートタグです。パラメータなしで使用すると、ulタブ構成でクラスが付与されたHTMLが出力されますので、これに合わせてスタイルシートを設定してもいいです。また、パラメータに配列を設定でき、各項目を設定することが可能です。
次は、出力されたHTMLです。<ul id="menu-%e3%82%b0%e3%83%ad%e3%83%bc%e3%83%90%e3%83%ab%e3%83%8a%e3%83%93%e3%82%b2%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3" class="menu">
<li id="menu-item-2118" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-2118"><a href="/" aria-current="page">ホーム</a></li>
<li id="menu-item-2119" class="menu-item menu-item-type-post_type menu-item-object-post menu-item-2119"><a href="http://test.local/hello-world/">Hello world!</a></li>
<li id="menu-item-2120" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-2120"><a href="http://test.local/sample-page/">Sample Page</a></li>
</ul>
get_nav_menu_locations()
get_nav_menu_locations() は、登録されているすべてのナビゲーションメニューと、それらに割り当てられているメニューIDを取得する関数です。
var_dump(get_nav_menu_locations());
/*
array (size=2)
'globalNav' => int 155
'footerNav' => int 0
*/
この場合、globalNav
とfooterNav
という2つのナビゲーションメニューが存在し、globalNav
にはID155
のメニューが割り当てられています。
wp_get_nav_menu_object()
wp_get_nav_menu_object() は、指定したメニューIDのデーターを配列で返し、見つからなかった場合はfalse
を返す関数です。配列の要素は、次の内容となっています。
プロパティ名 | データ型 | 内容 |
---|---|---|
term_id | int | ID |
name | string | ナビゲーション名 |
slug | string | スラッグ |
term_group | int | グループID |
term_taxonomy_id | int | タクソノミーID |
taxonomy | string | タクソノミー名。カテゴリーの場合はcategoryとなる |
description | string | 説明 |
parent | int | 親カテゴリーID。なければ0となる |
count | int | メニュー項目数 |
$menuName = "globalNav";
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object($locations[$menuName]);
var_dump($menu);
/*
object(WP_Term)[4862]
public 'term_id' => int 155
public 'name' => string 'グローバルナビゲーション' (length=36)
……
*/
wp_get_nav_menu_items()
wp_get_nav_menu_items() は、指定したメニューIDの各アイテムの情報を配列で返す関数です。次は、wp_get_nav_menu_object()
でメニューIDを取得し、それを元に情報を取得しています。
$menuName = "globalNav";
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object($locations[$menuName]);
$menuItems = wp_get_nav_menu_items($menu->term_id);
var_dump($menuItems);
/*
array (size=2)
0 =>
object(WP_Post)[4865]
public 'ID' => int 2112
public 'post_author' => string '1' (length=1)
……
1 =>
object(WP_Post)[4905]
public 'ID' => int 2113
……
*/
つまり、各メニューを配列で取得できましたので、これをforeach
などで要素を取得していき、HTMLを付与することで、ナビゲーションメニューを作成することができます。なお、各要素を表示する際、エスケープ処理を忘れないようにしましょう。
<?php
$menuName = "globalNav";
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object($locations[$menuName]);
$menuItems = wp_get_nav_menu_items($menu->term_id);
?>
……
<?php foreach($menuItems as $menuItem): ?>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="<?php echo esc_attr($menuItem->url); ?>"><?php echo esc_html($menuItem->title); ?></a></li>
<?php endforeach; ?>
ページネーション
1ページにおける投稿の表示数は、設定 > 表示設定 > 1ページに表示する最大投稿数
で設定します。これを超える投稿はページネーションにより管理されることになります。
next_posts_link()
next_posts_link() は、次の投稿の一覧へのリンクを表示するテンプレートタグです。パラメータを設定せずに使用すると、次ページへ »
というリンクが表示され、この表示テキストは第1パラメータで変更が可能です。第2パラメータで表示するページ数の上限が設定でき、初期値は上限なしとなっています。
<!-- Pager-->
<div class="d-flex justify-content-end mb-4">
<?php next_posts_link('古い投稿へ →'); ?>
</div>
get_next_posts_link()
get_next_posts_link() は、次の投稿の一覧へのリンク要素を取得する関数です。パラメータはnext_posts_link()
と同じです。
$linkElm = get_next_posts_link('古い投稿へ →');
$linkElm = str_replace('<a', '<a class="btn btn-primary float-right"', $linkElm);
echo $linkElm;
get_previous_posts_link()
get_previous_posts_link() は、前の投稿の一覧へのリンク要素を取得する関数です。パラメータや使い方は、get_next_posts_link()
と同じです。なお、表示はprevious_posts_link()
となります。
クラスなども修正して、以下のようにしてください。
<!-- Pager-->
<?php
$linkElm = get_previous_posts_link('← 新しい投稿へ');
if ($linkElm) {
$linkElm = str_replace('<a', '<a class="btn btn-primary float-left"', $linkElm);
echo '<div class="d-flex justify-content-between mb-4">';
echo $linkElm;
} else {
echo '<div class="d-flex justify-content-end mb-4">';
}
$linkElm = get_next_posts_link('古い投稿へ →');
if ($linkElm) {
$linkElm = str_replace('<a', '<a class="btn btn-primary float-right"', $linkElm);
echo $linkElm;
}
echo "</div>";
?>
条件分岐をしているのは、古い投稿がない場合に処理を行わないためです。
サイト内検索
WordPressは検索機能も兼ね備えていますので、それを実装するだけでサイト内検索を行うことが可能です。
get_search_form()
get_search_form() は、検索フォームを表示する関数です。searchform.php
を表示し、なければ標準で用意されている検索フォームを表示します。第1パラメータをfalse
にするとフォームを文字列として返し、デフォルト値はtrue
です。
では、ナビゲーションの箇所に設置してみましょう。
……
</ul>
<?php get_search_form(); ?>
これだけで検索フォームを表示されますが、searchform.php
を作成して、それを表示させましょう。
<form method="get" id="searchform" action="<?php bloginfo('url'); ?>">
<input type="text" name="s" id="s" placeholder="SEARCH" />
<button type="submit">検索する</button>
</form>
検索結果のページはsearch.php
となります。archive.php
をコピーしてsearch.php
を作成してください。
WP_Query
WP_QueryはWordPressでwp-includes/class-wp-query.php
に定義されているクラスで、ブログの投稿やページのリクエストを取り扱います。クラスですのでインスタンス化を行い使用するのですが、WP_Queryのオブジェクトであるグローバル変数の$wp_query
を使用することも可能です。
では、検索結果数を表示してみましょう。
<?php if(have_posts()): ?>
<?php
if (isset($_GET['s']) && empty($_GET['s'])) {
echo '検索キーワードが確認できません。';
} else {
echo '「' . $_GET['s'] . '」の検索結果: ' . $wp_query->found_posts . '件';
}
?>
<?php while (have_posts()): ?>
……
<?php endwhile; ?>
<?php else: ?>
<p>キーワードに一致しませんでした。</p>
<?php endif; ?>
カスタム投稿タイプ
WordPressには個別投稿ページと固定ページがありますが、これは投稿タイプと呼ばれ、個別投稿ページと固定ページはWordPressが標準で用意している投稿タイプとなります。この、投稿タイプは自作することが可能で、それをカスタム投稿タイプといいます。
register_post_type()
register_post_type() は、投稿タイプを作成または変更する関数です。init
アクション内から呼び出してください。第1パラメータは投稿タイプを設定します。これは、URLにも関わってくる投稿タイプを識別するキーワードで、最大20文字、大文字や空白は禁止となります。第2パラメータは、配列で様々な設定を行うことができます。例えば、次のような設定値があります。
-
label
カスタム投稿タイプの表示名で、初期値は「投稿」となります。 -
public
true
で投稿タイプがパブリックになり、デフォルト値はfalse
となります。false
だと管理画面から消えますが、使用できないわけではありません。 -
menu_position
管理画面での表示位置を設定します。 -
menu_icon
管理画面で表示する際のアイコンを指定でき、Dashiconsから選択することもできます。 -
supports
投稿の際に入力などができる項目を設定できます。標準ではタイトルと本文が設定されていますが、追加する場合はタイトルと本文を含めて設定する必要があります。 -
has_archive
true
でアーカイブを有効にします。つまり、投稿の一覧が表示されます。デフォルト値はfalse
です。 -
hierarchical
true
で親を指定で切るようになり、デフォルト値はfalse
です。 -
show_in_rest
true
でREST APIを有効にし、編集画面で新しいエディターが使用可能となります。
その他の項目や設定値に関しては、公式ドキュメントを確認してください。music
という投稿タイプを定義しています。音楽と表示され、投稿画面ではタイトル、本文、アイキャッチ画像が登録できるように設定しています。
add_action( 'init', function() {
register_post_type('music', [
'label' => '音楽',
'supports' => ['title', 'editor', 'thumbnail'],
'public' => true,
]);
});
なお、次の投稿タイプはWordPressが使用しているため、予約済みとなっております。
- post - 投稿
- page - 固定ページ
- attachment - 添付ファイル
- revision - リビジョン
- nav_menu_item - ナビゲーションメニュー
次の投稿タイプは、WordPressの関数と動作を妨害するため、使用してはいけません。
- action
- order
- theme
管理画面に音楽が追加されていますので、適当に新規追加をしてください。
テンプレート
カスタム投稿タイプのページが表示される一番優先度の高いテンプレートは、single-$posttype.php
です。この$posttype
は投稿タイプ、つまりregister_post_type()
の第1パラメータで設定した値となります。
では、single.php
をコピーしてsingle-music.php
を作成してください。投稿したページを表示すると、投稿内容が反映されています。
get_post_type()
get_post_type() は、投稿タイプを取得します。パラメータにIDまたは投稿オブジェクトを指定することで、その投稿の投稿タイプが取得できます。デフォルト値はnull
となり、現在の投稿の投稿タイプを取得します。
var_dump(get_post_type());
// string 'music' (length=5)
get_template_part()の第2パラメータにget_post_type()
を指定することで、例えば以下のようにincludes/header-music.php
のテンプレートを読み込むことができます
<!-- Page Header-->
<?php get_template_part( 'includes/header', get_post_type() ); ?>
では、includes/header-page.php
をコピーして、includes/header-music.php
を作成してください。
アーカイブ
カスタム投稿は、デフォルトでは固定ページと同じで一覧表示はされません。これを一覧表示させるためには、register_post_type()
でhas_archive
を設定してアーカイブを有効にしてください。
add_action( 'init', function() {
register_post_type('music', [
……
'has_archive' => true,
]);
});
http://xxx/投稿タイプ/
にアクセスすると、archive.php
をもとにタイトルが投稿分だけ表示されます。カスタム投稿専用のテンプレートとして、archive-music.php
などと作成すればそれが優先されますが、今回はarchive.php
を使用し、includes/header-archive.php
を編集していきます。
is_post_type_archive()
is_post_type_archive() は、指定された投稿タイプのアーカイブならtrue
を返す関数です。引数には投稿タイプを指定することもできます。これは、is_category()で紹介した、条件分岐タグの一種となります。
次のように、条件分岐を付け加えてください。
<?php elseif(is_post_type_archive()): ?>
<?php $custumFlg = 1; ?>
<h1>カスタム投稿</h1>
<?php else: ?>
<h1>Tab</h1>
<?php endif; ?>
<?php if($custumFlg != 1): ?>
<span class="subheading"><?php wp_title(''); ?></span>
<?php endif; ?>
今回は該当すれば$custumFlg
を定義するようにしています。これは、下部でwp_title('')
の出しわけをするためです。
なお、次のように配列で複数指定することも可能です。
is_post_type_archive(array('music', 'AAA', 'BBB');
get_post_type_object()
get_post_type_object() は、投稿タイプに設定されているオブジェクトを返す関数です。これはカスタム投稿タイプだけでなくpost
(投稿)やpage
(固定)なども対象とします。
次は、投稿タイプのラベルを取得して表示しています。なお、今回は説明のためにget_post_type_object()
を使用しましたが、wp_title('')
で取得してもかまいません。
<h1><?php echo get_post_type_object(get_post_type())->label; ?></h1>
階層構造
個別投稿ページは時系列に並べられ親子関係を持ちませんが、固定ページは並べるような一覧がなく、親子関係の階層構造が作れます。カスタム投稿タイプは標準では個別投稿ページと同じで、時系列に並べられ親子関係を持ちません。これを、親子関係の階層構造が作れるようにするには、register_post_type()
で、hierarchical
を設定します。また、supports
エレメントにpage-attributes
を追加します。
add_action( 'init', function() {
register_post_type('music', [
……
'supports' => ['title', 'editor', 'thumbnail', 'page-attributes'],
'hierarchical' => true,
]);
});
これで、固定ページの編集画面にページ属性の設定が追加されます。
カスタムタクソノミー(カスタム分類)
カテゴリーやタグなどのように、分類を行うものをタクソノミー(taxonomy) といいます。そして、固定ページやカスタム投稿にはタクソノミーが存在しませんので、標準ではタクソノミーを設定できません。この、固定ページやカスタム投稿にタクソノミーを追加することをカスタムタクソノミー(カスタム分類) いいます。
register_taxonomy()
register_taxonomy() は、カスタムタクソノミーとしてタクソノミーを追加したり上書きをする関数です。init
アクション内から呼び出してください。第1パラメータにはタクソノミーの名前を設定します。第2パラメータには対象を設定します。第3パラメータには配列で各オプションを設定します。各設定値などは、以下のページでご確認ください。
register_taxonomy('genre', 'music', [
'label' => '音楽ジャンル',
'hierarchical' => true,
'show_in_rest' => true,
]);
hierarchical
をtrue
にすることで階層を設定でき、設定ではカテゴリのように選択できます。false
だと階層を設定できず、設定ではタグのように設定します。つまり、カテゴリとタグはhierarchical
の値で分類されます。また、register_post_type()でshow_in_rest
をtrue
にして新しいエディターを使用している場合、こちらもshow_in_rest
をtrue
にしなければ、追加したタクソノミーが選択できません。
これで、管理画面の音楽に音楽ジャンルというタクソノミーが追加されます。では、カスタムタクソノミーの一覧ページを作成しましょう。archive.php
をコピーしてtaxonomy-genre.php
を作成してもいいですし、より優先順位が高いtaxonomy-タクソノミー名-スラッグ.php
でもいいです。今回は、archive.php
を使用します。
何らかのジャンルを作成して、カスタム投稿に設定しておいてください。
is_tax()
is_tax() は、カスタムタクソノミーならtrue
を返す関数で、条件分岐タグの一種となります。第1パラメータにはタクソノミー名を指定し、配列で複数指定することも可能です。第2パラメータにはタームのID、名前、スラッグ、またはそれらの配列を指定できます。
includes\header-archive.php
に条件分岐を追加してください。
<?php elseif(is_tax()): ?>
<h1><?php wp_title(''); ?></h1>
wp_title('')
でタイトルを取得していますが、このままでは「カスタムタクソノミー ターム」と表示されます。
get_queried_object()
get_queried_object() は、現在リクエストされているクエリのオブジェクトを取得する関数です。投稿ページやアーカイブページなどによって、取得できるオブジェクトが代わり、もちろん、カスタムタクソノミーでも取得可能です。
var_dump(get_queried_object());
/*
object(WP_Term)[4505]
public 'term_id' => int 8
public 'name' => string 'EDM' (length=3)
public 'slug' => string 'edm' (length=3)
public 'term_group' => int 0
public 'term_taxonomy_id' => int 8
public 'taxonomy' => string 'genre' (length=5)
public 'description' => string '' (length=0)
public 'parent' => int 0
public 'count' => int 0
public 'filter' => string 'raw' (length=3)]
*/
get_taxonomy()
get_taxonomy() は、指定したタクソノミーのオブジェクトを取得します。パラメータにはタクソノミー名を設定します。
次は、get_queried_object()
で取得したタクソノミー名を設定してオブジェクトを取得し、label
プロパティを表示しています。
<?php elseif(is_tax()): ?>
<?php
$query_object = get_queried_object();
$taxonomy = get_taxonomy($query_object->taxonomy);
?>
<h1><?php echo $taxonomy->label; ?></h1>
これで、タクソノミーのラベルだけを表示できます。
the_archive_title()
the_archive_title() は、アーカイブタイトルを表示する関数です。
<span class="subheading"><?php the_archive_title(); ?></span>
ただし、「カスタムタクソノミー: ターム」と表示されます。
single_term_title()
single_term_title() は、現在のページのタームタイトルを表示または取得する関数です。したがって、通常はタクソノミーで使用します。第1パラメータは、タイトルの前に出力するテキストを設定します。第2パラメータをfalse
にすると、値を返します。
<span class="subheading"><?php single_term_title(); ?></span>
single_***_title() は、ターム以外も準備されていますので、その他の箇所も変更して、以下のように更新しましょう。各条件ごとに、サブタイトルを決定しています。
<div class="site-heading">
<?php
$query_object = get_queried_object();
$taxonomy = get_taxonomy($query_object->taxonomy);
?>
<?php if(is_category()): ?>
<?php $sub_title = single_cat_title(``, false); ?>
<h1><?php echo $taxonomy->label; ?></h1>
<?php elseif(is_tag()): ?>
<?php $sub_title = single_tag_title(``, false); ?>
<h1><?php echo $taxonomy->label; ?></h1>
<?php elseif(is_author()): ?>
<?php $sub_title = get_the_author(); ?>
<h1>Author</h1>
<?php elseif(is_tax()): ?>
<?php $sub_title = single_term_title(``, false); ?>
<h1><?php echo $taxonomy->label; ?></h1>
<?php elseif(is_post_type_archive()): ?>
<?php $custumFlg = 1; ?>
<h1><?php wp_title(''); ?></h1>
<?php elseif(is_search()): ?>
<?php $sub_title = esc_html(get_search_query(false)); ?>
<h1>検索結果</h1>
<?php elseif(is_404()): ?>
<?php $sub_title = 'ページが見つかりません'; ?>
<h1>404</h1>
<?php else: ?>
<?php endif; ?>
<?php if($custumFlg != 1): ?>
<span class="subheading"><?php echo $sub_title; ?></span>
<?php endif; ?>
</div>
the_taxonomies()
the_taxonomies() は、投稿に割り当てられているタクソノミーの各タームを表示する関数です。
では、header-music.php
を以下のように更新して、カスタム投稿のページを確認して下さい。
<h1><?php the_title(); ?></h1>
<p class="post-meta"><?php the_taxonomies(); ?></p>
タクソノミー名: <a href="http://***/***/">ターム名。</a>
という形式で表示され、ターム名は設定した分だけ、
で区切られて表示されます。また、配列でオプションを渡すことで、前後の表示をカスタマイズすることができます。
<h1><?php the_title(); ?></h1>
<?php the_taxonomies(array('before' => '<p class="post-meta">', 'after' => '</p>')); ?>
get_the_terms()
get_the_terms() は、投稿に割り当てられているタクソノミーの各タームを取得する関数です。第1パラメータに投稿のIDを、第2パラメータにタクソノミー名を指定します。各タームが配列として取得され、各タームごとに配列としていくつかの値が設定されています。
<h1><?php the_title(); ?></h1>
<?php $terms = get_the_terms(get_the_ID(),'genre'); ?>
<?php if ($terms): ?>
<ul class="list-inline text-center">
<?php foreach ($terms as $term): ?>
<li class="list-inline-item"><?php echo esc_html($term->name); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
カスタムタクソノミーは選択されていない場合もありますので、if ($terms)
で判定しています。
get_term_link()
get_term_link() は、指定したタームのアーカイブページへのパーマリンクを返す関数です。第1パラメータにタームのオブジェクト、ID 、スラッグのどれかを指定します。第2パラメータは第1パラメータにオブジェクトを指定した際にタクソノミーのスラッグを指定します。
<li class="list-inline-item"><a href="<?php echo get_term_link($term); ?>"><?php echo esc_html($term->name); ?></a></li>
get_terms()
get_terms() は、指定したタクソノミーに含まれるタームを取得する関数です。第1パラメータにタクソノミー名を指定します。各タームが配列として取得され、各タームごとに配列としていくつかの値が設定されています。
header-archive.php
に、カスタムタクソノミーの場合は各タームが表示されるようにしましょう。
<?php if($custumFlg === 1): ?>
<?php $terms = get_terms('genre'); ?>
<ul class="list-inline text-center">
<?php foreach ($terms as $term): ?>
<li class="list-inline-item"><a href="<?php echo get_term_link($term); ?>"><?php echo esc_html($term->name); ?></a></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<span class="subheading"><?php echo $sub_title; ?></span>
<?php endif; ?>
WP_Query
WP_Queryはwp-includes/class-wp-query.php
に定義されているクラスで、ブログの投稿やページの情報を扱います。
これまでは、リクエストされたURLによって投稿を表示してきました。これをメインクエリといい、テンプレートを読み込む前にデーターを取得しています。そして、メインクエリをループ処理することをメインループといいます。メインクエリ以外で取得するデーターをサブクエリといい、サブクエリをループ処理することをサブループといいます。WP_Query
は、このサブクエリを扱うクラスとなります。
サブループはメインループとは別にループ処理を行えます。したがって、1ページ内に各種記事のループを表示させるなどが可能になります。
Wp_Query
は、インスタンス化を行い利用するのですが、その際に引数を利用することにより特定のインスタンスを作成できます。
$args = array(
'post_type' => 'music',
'posts_per_page' => 5,
);
$wp_query = new WP_Query($args);
if ( $wp_query->have_posts() ) {
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
the_post();
}
} else {
print "no no!";
}
wp_reset_postdata();
WP_Query
の引数に配列を設定して、インスタンス化をしています。この場合、musicカスタム投稿タイプから、1ページの最大取得数を5ページで取得しており、これが投稿ページだと、postと設定します。生成したインスタンスの使い方は、通常のメインクエリと同じようにループで使用します。
主に、以下のような要素を設定できます。
-
post_type
投稿タイプを選択します。post
で投稿ページ、page
で固定ページとなり、カスタム投稿タイプなどを指定できます。 -
posts_per_page
1ページあたりの表示件数を指定します。デフォルト値は10件となり、全件表示するには-1
を指定します。 -
order
昇順か降順かを指定します。デフォルト値は降順DESC
で、昇順はASC
となります。 -
orderby
ソートの項目を選択します。ID
、author
、title
、date
などを設定でます。
それ以外の設定に関しては、以下を確認してください。
WP_Query
は、様々な値の組み合わせにより細かな設定が可能ですので、積極的に使用しましょう。
カスタムフィールド
カスタムフィールドとは、登録ページに標準で入力できる項目以外の入力項目のことです。例えば、投稿の登録ページの右上のオプションから設定を選択し、パネルのカスタムフィールドをONにして有効化してリロード
ボタンをクリックします。すると、登録ページの下部にカスタムフィールドの項目が表示され、名前(キー)と値をのセットで複数登録することができ、一度作成すると次からは名前(キー)の選択エリアからそれらを選択できるようになります。また、同じ名前のものを複数登録することもできます。
カスタム投稿タイプでカスタムフィールドを使用するには、functions.php
のregister_post_type()
のsupports
にcustom-fields
を追加する必要があります。
add_action( 'init', function() {
register_post_type('music', [
……
'supports' => ['title', 'editor', 'thumbnail', 'page-attributes', 'custom-fields'],
]);
……
});
これで、カスタム投稿タイプの登録ページにカスタムフィールドが表示されますので、以下のように設定してください。
- 価格: 10000
- レーベル: EMI
- アーティスト: The WP
- アーティスト: PHPer
get_post_meta()
get_post_meta() は、カスタムフィールドの値を取得する関数です。第1パラメータに投稿のID、第2パラメータに取得したい値のキー、第2パラメータはtrue
だと文字列を返し、初期値のfalse
だとカスタムフィールドの配列を返します。
では、single-music.php
を次のように更新しましょう。
<?php
$price = get_post_meta(get_the_ID(), '価格', true);
$label = get_post_meta(get_the_ID(), 'レーベル', true);
$artists = get_post_meta(get_the_ID(), 'アーティスト', false);
?>
<!DOCTYPE html>
……
<div class="col-md-10 col-lg-8 col-xl-7">
<dl>
<?php if ($price !== ''): ?>
<dt>価格</dt>
<dd><?php echo esc_html(number_format($price)); ?>円</dd>
<?php endif; ?>
<?php if ($label !== ''): ?>
<dt>レーベル</dt>
<dd><?php echo esc_html($label); ?></dd>
<?php endif; ?>
<?php if ($artists): ?>
<dt>アーティスト</dt>
<?php foreach ($artists as $artist): ?>
<dd><?php echo esc_html($artist); ?></dd>
<?php endforeach; ?>
<?php endif; ?>
</dl>
<?php the_content(); ?>
……
価格とレーベルは文字列で、複数設定しているアーティストは配列で取得しています。
ショートコード
WordPressはセキュリティ上、投稿画面の本文の中にPHPのコードを埋め込むことはできません。その場合、予めショートコードというコードを作成しておき、それを使用することになります。
add_shortcode()
add_shortcode() は、ショートコードタグ用のフックを追加する関数ですfunctions.php
内で定義し、第1パラメータにショートコード名、第2パラメータに実行する関数を定義します。その際、必ずreturn
で値を返さないと「更新に失敗しました。 返答が正しい JSON レスポンスではありません。」とエラーとなります。また、処理のタイミング上、echo
などで表示すると表示がずれてしまします。したがって、例えばthe_title()
関数などではなく、get_the_title()
関数などで取得して処理をしてください。
add_shortcode('date', function() {
return date('Y年 n月 j日');
});
投稿ページの本文で+
ボタンをクリックし、ショートコードを選択して使用してもいいですし、そのまま本文に記載することもできます。その際、必ずブラケットで囲む必要があります。
[date]
また、第2パラメータの関数にはパラメータを設定することができ、パラメータは連想配列で受け取ることができます。
add_shortcode('date', function($atts) {
return $atts['before'] . date('Y年 n月 j日') . $atts['after'];
});
[date before="今日は" after="です。"]
shortcode_atts()
shortcode_atts() は、ショートコードのパラメータにデフォルト値を設定する関数です。第1パラメータにデフォルト値の連想配列、第2パラメータにショートコードタグに指定した属性、第3パラメータにショートコード名を設定します。
add_shortcode('date', function($atts) {
$atts = shortcode_atts([
'before' => 'Today is ',
'after' => ' !',
], $atts, 'date');
return $atts['before'] . date('Y年 n月 j日') . $atts['after'];
});
プラグイン
テーマで設定したfunctions.php
などは、そのテーマでしか使用できません。汎用的に使用したい機能などは、プラグインにすればいいでしょう。
プラグインは、wp-content > plugins
にファイル、もしくはディレクトリを設置します。では、例としてsample
ディレクトリを追加して、その中にsample-plugin.php
を追加してください。
プラグインには、テーマと同じでコメントの設定が必要となります。いくつかの種類がありますので、次で確認してください。プラグインとして成立させるには、最低限Plugin Name
が必要となります。
<?php
/*
Plugin Name: サンプルプラグイン
Description: サンプルのプラグインです。
Version: 1.0
Author: ANTEZ
*/
これで、プラグインがインストールされている状態になり、有効化も可能となります。
例えば、既に作成しているショートコードをsample-plugin.php
に追加してみます。
add_shortcode('date', function($atts) {
$atts = shortcode_atts([
'before' => 'Today is ',
'after' => ' !',
], $atts, 'date');
return $atts['before'] . date('Y年 n月 j日') . $atts['after'];
});
ブロックエディター
ブロックエディターとは、現在のWordPressの本文入力などで採用されている、新しいエディターのことです。ブロックを選択して、内容を入力することができるという特徴があります。
ブロックエディターは、JavaScriptやCSSなどでカスタマイズできるのですが、WordPressではアクションフックで読み込むことが推奨されています。これにより、functions.php
内で一元管理でき、重複読み込みを回避できるなどのメリットが得られます。
wp_enqueue_script()
wp_enqueue_script() は、JavaScriptファイルをキューに入れ、適切な順番で処理をしてくれる関数です。第1パラメータに操作する際のハンドル名を指定し、この名前の末尾に-js
を付けたものが、読み込んだ際の<script>
タブのid
属性となります。第2パラメータでは読み込むスクリプトを指定します。第3パラメータでは、読み込むスクリプトを順番に配列で指定します。以下の場合だと、wp-blocks
が先に読み込まれますので、wp-blocks
に関するオブジェクトなどがJavaScriptで使用できるようになります。
では、ブロックエディターをフックとしたプラグイン内で使用してみます。ブロックエディターの素材ファイルを読み込む際のフックはenqueue_block_editor_assets
となります。
add_action('enqueue_block_editor_assets', function($atts) {
wp_enqueue_script(
'sample-script',
'http://sample.local/wp-content/plugins/sample/sample.js',
['wp-blocks'],
);
});
指定したパスの通りに、sample.jsを作成します。
alert('Hello!');
プラグインを有効化して、投稿画面を開いてください。Hello!
とアラートが表示されます。
plugins_url()
plugins_url() は、plugins
ディレクトリーの絶対パスを末尾のスラッシュなしで取得する関数です。第1パラメータには、URLを取得したいプラグインファイルのパスを指定します。また、第2パラメータにパスを指定すると、第1パラメータはそれを基点とします。つまり、次のように設定すると、sample.js
が指定されます。
例えば、先ほどのスクリプトの指定は次のようにします。
add_action('enqueue_block_editor_assets', function($atts) {
wp_enqueue_script(
'sample-script',
plugins_url('myeditor.js', __FILE__),
['wp-blocks'],
);
});
add_editor_style()
add_editor_style() は、ビジュアルエディターにCSSを読み込みます。これにより、公開ページのデザインをそのままビジュアルエディターで表現できます。
add_action('after_setup_theme', function() {
add_theme_support('editor-styles');
add_editor_style('/css/editor.css');
});
after_setup_theme
のタイミングで、add_theme_support
でeditor-styles
をすることで、ビジュアルエディターにスタイル機能を追加し、add_editor_style
でCSSを読み込みます。
例えば、/css/editor.css
を次のように設定してください。
p {
color: blue;
}
管理画面、本番画面ともに、pタグのテキストが赤色で表示されます。
wp.blocks.registerBlockStyle()
wp.blocks.registerBlockStyle() は、既存のブロックの動作を変更するためのAPIで、JavaScriptのスクリプトとなります。第1パラメータで適用するブロックを指定し、第2パラメータではクラス名とラベルを指定します。
どのようなブロックが存在するかは、次で確認できます。
これらブロックはcore
に格納されていますので、core/**
と指定することができます。
では、sample.js
を次のように記述してください。
wp.blocks.registerBlockStyle('core/paragraph', {
name: 'p text-danger',
label: 'デンジャー'
});
paragraph(段落)を指定しています。nameはクラス名となり、先頭にis-style-
が付与されます。この場合、is-style-p text-danger
がクラス属性に設定されます。label
は管理画面での表示名です。
カスタムブロック
ブロックは自分で作成することも可能で、自作したブロックをカスタムブロックといいます。なお、カスタムブロックに関しは公式からハンドブックが公開されており、チュートリアルなども公開されています。
カスタムブロックの説明は、これだけで1つのコンテンツになるくらいのボリュームですので、ここではこのチュートリアルを使用して、大まかに説明します。そして、ここからは多少フロントエンド開発っぽくなってきます。フロントエンドエンジニアにはおなじみの手法なのですが、そうでない方にはとっつきにくい所だと思います。プロジェクトの作成
カスタムブロックにはいくつかの作成方法がありますが、plugins
ディレクトリ内に作成するのが一般的です。plugins
ディレクトリに移動してnpx
でブロックのひな形である@wordpres/create-block
をインストールします。カスタムブロック名を指定しますが、これは任意の名前でいいです。これは、ReactのCreate React Appのようなもので、webpackやBabel、ESLintなどが自動で設定されています。
$ npx @wordpress/create-block gutenpride
なお、npx
や次に出てくるnpm
が分からない方は、次を参考にしてください。
途中、It might take a couple of minutes...
などと表示されますが、インストールが完了するまで待ってください。Code is Poetry
が表示されたら完了です。gutenpride
というディレクトリがインストールされますので、コマンドラインで移動してください。
いくつかのディレクトリとファイルが、インストールされています。src
ディレクトリ内にはカスタムブロックの開発用ファイルが格納されています。これがビルドされて、本番化のソース群となります。また、プラグイン名.php
がプラグインの設定ファイルです。
function create_block_gutenpride_block_init() {
register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'create_block_gutenpride_block_init' );
add_action
のinit
でcreate_block_gutenpride_block_init()
を実行しています。
register_block_type()
register_block_type() は、ブロックタイプを登録します。つまり、以下はPHPのマジカル定数を使用して、このディレクトリ内のbuild
ディレクトリを登録しています。
register_block_type( __DIR__ . '/build' );
ビルド
では、package.json
のscripts
に設定されているビルドを行いましょう。
$ npm run build
成功するとsrc
ディレクトリがビルドされ、build
ディレクトリが作成されています。管理画面でインストール済みプラグインを確認すると、プラグインのインストールが確認できますので、有効化をしてください。投稿画面のウィジェットの項目に、追加したプラグインが表示されています。
block.json
ブロックタイプのディレクトリを指定すると、そこに存在するblock.json
が読み込まれます。このファイルにはブロックタイプのメタデータを設定でき、例えば以下のような値が設定可能です。
-
apiVersion
ブロックが使用するBlock APIのバージョンで、最新のバージョンは2となります。 -
name
ブロックを識別する固有の文字列です。namespace/ブロック名
となり、namespaceはプラグインやテーマの名前となります。 -
version
ブロックのバージョンです。 -
title
表示される際のタイトルです。 -
category
ブロックのカテゴリを設定します。カテゴリはtext、media、design、widgets、theme、embed
から選択します。 -
icon
表示するアイコンを設定します。Dashiconsから選択できます。 -
description
ブロックの説明文です。 -
supports
使用できる機能を制御します。項目に関してはサポートを参照してください。 -
textdomain
翻訳するテキストがどこにあるかを示す識別子。この識別子を使用して、各言語の翻訳ファイルが作成されます。 -
editorScript
エディタースクリプトを定義します。 -
editorStyle
エディタースタイルを定義します。 -
style
スタイルを定義します。
その他の項目に関しては、次を参照してください。
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "create-block/gutenpride",
"version": "0.1.0",
"title": "Gutenpride",
"category": "widgets",
"icon": "smiley",
"description": "Example static block scaffolded with Create Block tool.",
"supports": {
"html": false
},
"textdomain": "gutenpride",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
}
index.js
では、src/index.js
を見てみましょう。次のように、Edit
とsave
を読み込んでいます。
import Edit from './edit';
import save from './save';
では、src/edit.js
のEdit
の定義を見てみます。
export default function Edit() {
return (
<p { ...useBlockProps() }>
{ __( 'Gutenpride – hello from the editor!', 'gutenpride' ) }
</p>
);
}
関数内に直接HTMLタグのようなものが設定されています。そう、これは紛れもなくJSX
ですね。どうやら、ここの文字列が実行結果に表示されていそうです。
index.js
に戻って、これが使用されている箇所を見てみましょう。
import Edit from './edit';
import save from './save';
では、src/edit.js
のEdit
の定義を見てみます。
registerBlockType('create-block/gutenpride', {
edit: Edit,
save,
});
wp.blocks.registerBlockType()
wp.blocks.registerBlockType() は、ブロックタイプの登録を行う関数です。第1引数にはブロックを識別する固有の文字列で、namespace/ブロック名
を渡します。第2引数にブロックタイプの設定をオブジェクトで渡します。この設定はblock.json
の設定より優先度が高いです。
では、次のように更新しましょう
registerBlockType('create-block/gutenpride', {
apiVersion: 2,
attributes: {
message: {
type: 'string',
source: 'text',
selector: 'div',
default: '',
}
},
edit: Edit,
save,
});
次に、編集画面を定義しているedit.js
を更新します。Edit
関数のパラメータに、先ほど定義したattributes
と属性を更新する関数であるsetAttributes
を、オブジェクトとして設定します。また、TextControl
コンポーネントを使用しますので、import
で読み込んで次のように設定をしてください。
import { __ } from'@wordpress/i18n';
import { useBlockProps } from'@wordpress/block-editor';
import { TextControl } from'@wordpress/components';
import'./editor.scss';
export default function Edit( { attributes, setAttributes } ) {
return (
<div { ...useBlockProps() }>
<TextControl
label={ __( 'Message', 'gutenpride' ) }
value={ attributes.message }
onChange={ ( val ) => setAttributes( { message: val } ) }
/>
</div>
);
}
これで、テキストフィールドが管理画面のカスタムフィールドに表示されます。ただし、まだ入力を保存する設定をしていないため、入力したテキストが保存できません。保存は、save.js
で設定します。
では、再ビルドを行ってください。管理画面を確認すると、それまで設置していたカスタムフィールドに「このブロックには、想定されていないか無効なコンテンツが含まれています」と表示されます。これは、カスタムフィールドの内容を変更したからですので、このカスタムフィールドは削除して、新たに設置しなおしてください。テキストが入力できますので、適当な文字列を入力して投稿してください。ページ上では、その文字列が表示されます。
save.js
も同じように更新しましょう。
export default function save( {attributes} ) {
return (
<div { ...useBlockProps.save() }>
{ attributes.message }
</div>
);
}
再ビルドを行い、新しくカスタムフィールドを設置してページを確認すると、入力したテキストが反映されています。
最後に
長い長い記事を読んでいただき、ありがとうございました。今回はひょっとしたらZennの記事の中で一番長いんじゃないかというくらい、長くなりました。Bookにする必要もないかなと始めたら、この有様です。
ここまでを知っていれば、後はエンジニアの方ならドキュメントを見ながら応用で進めて行けると思います。積極的にWordPressの仕様を学んでいこうとは思わないかもしれませんが、なぜ、この分野でWordPress一強が続いているのかがわかるような気がしませんか。何らかのサービスなどを作る際には、参考になると思います。
また、以下をカスタムブロックの環境構築のお供にどうぞ。
Discussion