現代のWordPress開発へのアプローチ方法(パート2)
公開: 2022-03-11WordPressは、地球上で最も広く使用されているサイトテクノロジーであり、正当な理由があります。 しかし、そのコアのレガシーコードは混乱しており、この問題はサードパーティの開発者に波及しています。 一部の開発者は、これを自分のWordPress PHPコードの手抜きをする言い訳と見なしていますが、このアプローチは、最も些細な変更を除いて、長期的にはより費用がかかります。
2部構成のシリーズのパート1では、プロジェクト全体とワークフローツールに焦点を当て、続いてフロントエンド開発を行いました。 今度は、強気に立ち向かい、PHPと格闘します。具体的には、バックエンドのWordPressコードを操作する際のベストプラクティスに従う方法です。 これはPHP/WordPressチュートリアルと考えるかもしれませんが、WordPressバックエンドのカスタマイズをすでに行っていることを前提として、もう少し高度です。
では、どの最新のソフトウェア設計原則とPHP機能が、あなたの時間に最高の価値をもたらすでしょうか? 以下は、私が強くお勧めする10のWordPressおよびPHP開発プラクティスです。
最新のWordPress開発のベストプラクティス#1:「関心の分離」に従ってください
関心の分離とは、機能や目的が異なるWordPressPHPコードの一部を混在させてはならないことを意味します。 代わりに、それらは別個のセクションまたはモジュールに編成され、定義されたインターフェースを介して相互にデータを渡す必要があります。 (インターフェースは、モジュールが入力として受け取る定義済みパラメーターのセットであり、出力されるものです。)密接に関連する用語は、単一責任の原則です。すべてのコードモジュール(または関数)は、1つのことだけを担当する必要があります。
これらの原則に従うことの最終的な目標は、モジュール式であり、したがって保守可能、拡張可能、および再利用可能なコードを作成することです。
それはかなり一口だったので、すべてを絡ませたWordPress PHP(WordPressコアから)の例を見てみましょう。 このスタイルのコーディングは、その内部の仕組みを理解することがほとんど不可能であるため、「スパゲッティコード」と呼ばれることがよくあります。 以下の抜粋は、簡潔にするために編集されています。 ただし、元のスタイルとフォーマットは保持されました。
$id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0; <table class="form-table"> <?php $blog_prefix = $wpdb->get_blog_prefix( $id ); $sql = "SELECT * FROM {$blog_prefix}options WHERE option_name NOT LIKE %s AND option_name NOT LIKE %s"; $query = $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', '%' . $wpdb->esc_like( 'user_roles' ) ); $options = $wpdb->get_results( $query ); foreach ( $options as $option ) { if ( strpos( $option->option_value, "\n" ) === false ) { ?> <tr class="form-field"> <th scope="row"><label for="<?php echo esc_attr( $option->option_name ); ?>"><?php echo esc_html( ucwords( str_replace( '_', ' ', $option->option_name ) ) ); ?></label></th> <?php if ( $is_main_site && in_array( $option->option_name, array( 'siteurl', 'home' ) ) ) { ?> <td><code><?php echo esc_html( $option->option_value ); ?></code></td> <?php } else { ?> <td><input class="<?php echo $class; ?>" name="option[<?php echo esc_attr( $option->option_name ); ?>]" type="text" value="<?php echo esc_attr( $option->option_value ); ?>" size="40" <?php disabled( $disabled ); ?> /></td> <?php } ?> </tr> <?php } } // End foreach </table>
まず第一に、それは完全に理解できません。 そして、私は唯一のコメントがEnd foreach
であることが大好きです。これは完全に冗長です。 データベースクエリ、クエリ結果処理、HTMLに埋め込まれた追加処理(気づかなかった場合はif
/ else
ネストされています)、出力エスケープ、およびHTMLテンプレートがすべて一緒にマッシュアップされています。 もう1つの問題は、実際のパラメーターを関数に渡すのではなく、グローバルな$_REQUEST
から直接取得される$id
パラメーターです。
これを見ると、WordPressコアが何年もほとんど同じままである理由は完全に理解できます。 この種のコードをリファクタリングすることは、特に既存の動作を維持しながら、誰もやりたくない本当に壮大なタスクです。
では、どうすればそれを適切に行うことができますか? 覚えておくべきことの1つは、本当の方法は1つではないということです。 私たちが努力すべき上記の品質について述べました。WordPressのカスタムPHPコードは、保守可能でモジュール式である必要があります。 上記のコードをモジュールに分割する方法を見てみましょう。
- もちろん、SQLクエリは別のモジュールに含める必要があります。 WordPressには、例として使用する必要のある、適切に抽象化された
WP_Query
クラスがすでにあります。 - すべてのHTMLはテンプレートに入ります。 PHPテンプレートについては以下で詳しく説明します。
- 残りのPHPコードは、関数でラップする必要があります。コードが長すぎる場合や1つの関数に対して複雑な場合は、いくつかの関数を使用します。
$id
などのパラメーターは、関数の引数を介して渡されます。
これは、上記の例を大幅に簡略化して書き直したものです。
function betterSiteSettings($args) { $data = WP_Settings_Query($args); // process $data here $context = array_merge([], $data_processed, $other_data); return Template::render('template.name', $context); }
最新のWordPress開発のベストプラクティス#2:グローバル変数を回避する
WordPressにはグローバル変数が多すぎます。 グローバル変数が悪いのはなぜですか? それらはあなたのWordPressPHPコードを追跡するのを難しくし、アプリケーションの状態を信頼できないものにします。 PHPコードのどの部分(つまり、WordPressにインストールされているプラグイン)もグローバル変数の読み取りと書き込みができるため、有効なデータが含まれている保証はありません。 ループのようなものでどのグローバル変数が使用されているかを理解しようとすることも、簡単な作業ではありません。
これを実際的な角度から見てみましょう。 この例はWooCommerceからのものです。 おそらくすべてのWordPress開発者はそれが何であるかを知っています—ループ:
<?php while ( have_posts() ) : the_post(); ?> <?php wc_get_template_part( 'content', 'single-product' ); ?> <?php endwhile; // end of the loop. ?>
上記のスニペットは、製品テンプレートをレンダリングします。 wc_get_template_part
に渡されたパラメーターがない場合、どの製品を表示するかをどのように知ることができますか? テンプレートを見ると、 global $product;
、したがって、現在の製品オブジェクトが格納されます。
ここで、商品を検索してフィルタリングするカタログページがあり、同じページにとどまりながら「商品の詳細」ポップアップを表示したいとします。 舞台裏では、フロントエンドスクリプトがAJAXリクエストを実行して、その特定の製品テンプレートを取得します。 パラメータを使用しないためwc_get_template_part('content', 'single-product')
を単純に呼び出すことはできません。したがって、これを機能させるには、いくつかのグローバル変数を設定する必要があります。
より複雑なユースケースには、複数のテンプレート、それらのテンプレートでトリガーされるフック、およびそれらのフックにコールバックを追加するサードパーティのプラグインが含まれます。 すぐにエスカレートできます。 これらのコールバックがどのグローバル状態に依存しているかを知る方法はありません。 サードパーティのプラグインは、コールバック内のグローバル変数を自由に変更できます。 システムを使用する代わりに、システムとの戦いを開始し、信頼できないグローバル状態に起因する奇妙なバグに遭遇します。
その製品IDをパラメーターとして渡す方が賢明ではないでしょうか。 そうすれば、WordPressで使用されるグローバル変数を台無しにすることを心配せずに、そのテンプレートを再利用できます。
最新のWordPress開発のベストプラクティス#3:オブジェクト指向プログラミング(OOP)を使用する
モジュール性は、オブジェクトとオブジェクト指向プログラミングの概念につながります。 非常に基本的なレベルでは、OOPはコードを整理する方法です。 関数と変数はクラスにまとめられており、それぞれクラスメソッドとプロパティと呼ばれます。 WordPressプラグインハンドブックでは、WordPressカスタムPHPコードを整理するためにOOPを使用することを推奨しています。
OOPの重要な原則は、メソッドとプロパティへのアクセスを制限することです。つまり、PHPの用語では、 private
またはprotected
ていることを示します。そのため、他のクラスのメソッドだけがそれらにアクセスして変更できます。 これのOOP用語はカプセル化です:データはクラス内にカプセル化され、そのデータを変更する唯一の方法は、提供されたクラスメソッドを使用することです。
これにより、コードベース全体のどこでも変更できるグローバル変数を使用する場合よりも、コードのデバッグと保守がはるかに簡単になります。 グローバルなWordPress post
変数について考えてみましょう。 コード内のどこからでもアクセスでき、多くの機能はそれを使用することに依存しています。 変更をWordPressのコア機能のみに制限できても、誰でも読むことができるとしたらどうでしょうか。 クラス内のグローバルpost
変数を非表示またはカプセル化し、その周りにインターフェイスを構築すると、これが可能になります。
これは、OOPの非常に基本的な説明であり、最新のWordPress開発でどのように使用できるかを示しています。 さらなる研究のために、私はカール・アレクサンダーの電子書籍、WordPressを使用したオブジェクト指向プログラミングの発見を徹底的にお勧めします。これはWordPressのOOPのトピックで利用できる最も包括的で有用なコンテンツを持っています。
OOPは特効薬ではないことを覚えておくことが重要です。悪いコードは、他のプログラミングパラダイムと同じように簡単にOOPで記述できます。
WordPress開発にPHPを使用することについてのいくつかの具体的なアドバイスに飛び込みましょう。
最新のPHPベストプラクティス#1:ターゲットPHP 7.0+
最新のPHP機能を使用するには、最新バージョンのPHPが必要です。 7.0より前のバージョンのPHPをサポートする理由はまったくありません。 WordPressコアでさえ、2019年末には早くもPHP7.0が必要になります。
それでも、互換性のない環境で「死の白い画面」を回避するために、最小バージョンを確認することをお勧めします。 以下のスニペットは、プラグインヘッダーを使用して、コード内にガード条件を含む最小のPHPバージョンを宣言する方法を示しています。
<?php /** * Plugin Name: My Awesome Plugin * Requires PHP: 7.0 */ // bails if PHP version is lower than required if (version_compare(PHP_VERSION, '7.0.0', '<')) { // add admin notice here return; } // the rest of the actual plugin here
最新のPHPベストプラクティス#2:PHP業界標準の採用(PSR-2コーディングスタイルガイド)
PSRは、PHP FrameworkInteropGroupによって公開された推奨事項です。 これらは、最新のPHPワークフローの事実上の業界標準であり、PHPコミュニティ全体がこれらの標準に準拠していると言っても過言ではありません。 PSR-2は、コーディングスタイルを説明する推奨事項です。 SymfonyやLaravelなどの人気のあるPHPフレームワークはPSR-2に従います。
WordPressコーディング標準の代わりにPSR-2を使用するのはなぜですか? 主な理由は、WordPress標準が廃止され、新しい言語機能を使用していないためです。 WordPressコアは独自の標準に従わなければならないので、それは理解できます。 ごく最近までPHP5.2をサポートする必要があり、PSR-2はPHP5.2と互換性がありません。

明らかではないかもしれませんが、コアにコミットしない限り、WordPressコーディング標準を使用する必要はありません。 PSR-2標準に準拠したプラグインをWordPressプラグインディレクトリに送信しても問題はありません。 実際、そうすることにはいくつかの非常に良い議論があります。
最新のPHPベストプラクティス#3:PHPテンプレートエンジンを使用する
PHPはテンプレートエンジンではありません。 それは1つとして始まりましたが、その後、完全な機能を備えたプログラミング言語に進化しました。テンプレートを作成するためにそれを使い続ける理由はありません。 PHPで最も人気のある2つのテンプレートエンジンはTwigとBladeで、それぞれSymfonyとLaravelで使用されています。 この記事では、テンプレートエンジンの例としてTwigを使用します。 ただし、Bladeには同等の機能があります。 両方を調べて、どちらが自分に最も適しているかを自分で判断することをお勧めします。
以下の例では、PHPテンプレートとそれに対応するTwigテンプレートを比較しています。 PHPの例では、出力の表示とエスケープは特に冗長です。
foreach ( $options as $option ) { ?> <tr class="form-field"> <th scope="row"> <label for="<?php echo esc_attr( $option->option_name ); ?>"> <?php echo esc_html( strtolower( $option->option_name ) ); ?> </label> </th> </tr> <?php } // End foreach
Twigでは、これはより簡潔で読みやすくなっています。
{% for option in options %} <tr class="form-field"> <th scope="row"> <label for="{{ option.option_name }}"> {{ option.option_name }} </label> </th> </tr> {% endfor %}
Twigの主な利点は次のとおりです。
- 読みやすく簡潔な構文
- 自動出力エスケープ
- 継承とブロックによるテンプレート拡張
パフォーマンス面では、TwigはPHPテンプレートにコンパイルされ、実質的にオーバーヘッドはありません。 Twigには、テンプレートのみに限定されたPHP言語構造のサブセットしかありません。 これにより、開発者はテンプレートからビジネスロジックを削除する必要があり、関心の分離が強制されます。
WordPress用のTwigもあります。 これはTimberと呼ばれ、より優れたテンプレートの作成を開始するための優れた方法です。 Timberスターターテーマは、OOP方式でテーマを整理する完璧な例です。
最新のPHPベストプラクティス#4:Composerを使用する
Composerは、PHPの依存関係マネージャーです。 これは、プロジェクトが使用しているライブラリを宣言し、それらのダウンロード、インストール、および更新を自動化できるツールです。 次に、各ライブラリを手動で要求するのではなく、Composerの自動ロードファイルvendor/autoload.php
を含める必要があります。
WordPressのプラグインとテーマは、サードパーティのライブラリを使用しないことがよくあります。 これは、WordPressがほぼすべてのニーズを満たす広範なAPIを備えていることと、バージョンの競合が発生する可能性があることが原因の1つです。 同じPHPライブラリを必要とするがバージョンが異なる2つのプラグインについて考えてみます。 最初に実行されるプラグインは正しいバージョンを取得し、2番目のプラグインもそのバージョンを取得します。 これはおそらく別の死の白い画面の状況です。
競合を回避するには、依存関係管理をアプリケーションレベル、つまりWordPressサイト全体で使用する必要があります。 これは、Roots(より具体的にはBedrock)が行うことです。 パッケージ(プラグインまたはテーマ)レベルで使用する場合、Composerはサードパーティライブラリを使用するときに競合を引き起こす可能性があります。 これは既知の問題です。 これまでに存在する唯一の解決策は、外部ライブラリの名前空間の名前を一意の名前に変更することであり、これは簡単な作業ではありません。
ただし、Composerにはまだ使用法があります。それは、独自のクラスの自動ロードです。 ただし、自動読み込みをさらに進める前に、PHP名前空間について理解する必要があります。
最新のPHPベストプラクティス#5:名前空間を使用する
WordPressコアはレガシープロジェクトであり、グローバル名前空間を使用するか、言い換えると、名前空間をまったく使用しません。 グローバルに宣言された(別のクラスまたは関数内にないことを意味する)クラスまたは関数は、コードベース全体のどこにでも表示されます。 それらの名前は、コードベース内だけでなく、現在使用されている、または将来使用される可能性のあるすべてのプラグインとテーマで一意である必要があります。
名前の衝突(たとえば、すでに存在する名前の関数を宣言する)は通常、死の白い画面につながりますが、それは望ましくありません。 WordPress Codexは、すべての関数とクラスの前に独自の何かを付けることをお勧めします。 したがって、 Order
のような単純なクラス名を使用する代わりに、 Akrte_Awesome_Plugin_Order
のようなものを取得します。ここで、「Akrte」は、作成したばかりの一意のプレフィックスです。
名前空間は、コードを整理し、名前の衝突を回避するのに役立つグループ(または、ファイルシステムの例えを使用する場合はフォルダー)として表示できます。 ネストされたフォルダーのように、スラッシュで区切られた複雑な名前空間を持つことができます。 (PHP名前空間は特に円記号を使用します。)
これらの名前空間部分はサブ名前空間と呼ばれます。 サンプルクラスAkrte_Awesome_Plugin_Order
は、名前空間を使用して実行した場合、 Akrte\Awesome_Plugin\Order
になります。 ここで、 Akrte
とAwesome_Plugin
は名前空間部分(またはサブ名前空間)であり、 Order
はクラス名です。 次に、 use
ステートメントを追加し、後でクラス名のみを使用できます。 それは間違いなく良く見えます:
use Akrte\Awesome_Plugin\Order; $a = new Order;
明らかに、名前空間は一意である必要があります。 したがって、最初の「ルート」サブ名前空間に一意の名前を付ける必要があります。これは通常、ベンダー名です。 例として、WooCommerceクラスWC_REST_Order_Notes_V2_Controller
は、次のような名前空間で再実行できます。
namespace WooCommerce\RestApi\V2\Controllers; class OrderNotes {}
WooCommerceコードベースは現在名前空間を使用しています。 たとえば、WooCommerceRESTAPIバージョン4では。
最新のPHPベストプラクティス#6:オートローダーを使用する
ほとんどのPHPワークフローでは、PHPファイルをリンクする通常の方法はrequire
またはinclude
ステートメントを使用することです。 プロジェクトが成長するにつれて、メインのプラグインファイルに数十のrequire
ステートメントが含まれます。 オートローダーはファイルのインクルードを自動化し、必要な場合にのみ実行します。 技術的には、コードで最初に検出されたときにクラスまたは関数を含むファイルをrequire
する関数です。 もうrequire
ステートメントを手動で追加する必要はありません。
オートローダーは特定のリクエストで使用されるモジュールのみをロードするため、多くの場合、パフォーマンスが大幅に向上します。 オートローダーがないと、リクエストでコードの10%しか使用されていない場合でも、コードベース全体が含まれます。
オートローダー関数は、クラスと関数がどのファイルに存在するかを知る必要があります。 そして、そのためのPHP-FIG標準であるPSR-4があります。
名前空間の一部であるプレフィックスは、ベースフォルダに対応するように指定されていることを示しています。 それに続くサブ名前空間は、ベースフォルダー内のフォルダーに対応します。 最後に、クラス名はファイル名に対応しています。 サンプルクラスAkrte\AwesomePlugin\Models\Order
には、以下のフォルダー構造が必要です。
/awesome-plugin awesome-plugin.php /includes /Models Order.php
名前空間プレフィックスAkrte\AwesomePlugin\
は、以下で説明するオートローダー構成で指定されているincludes
フォルダーに対応します。 Models
サブ名前空間には、対応するModels
フォルダーがあり、 Order
クラスはOrder.php
に含まれています。
幸い、オートローダー機能を自分で実装する必要はありません。 Composerは、オートローダーを作成できます。
- Composerをインストールします
- プロジェクトのルートフォルダーに
composer.json
ファイルを作成します。 次の行が含まれている必要があります。
{ "name": "vendor-name/plugin-name", "require": {}, "autoload": { "psr-4": { "Akrte\\AwesomePlugin\\": "includes/" } } }
-
composer install
ます。 - 次のように、メインプラグインのPHPファイルの先頭に
vendor/autoload.php
を含めます。
<?php /** * Plugin Name: My Awesome Plugin */ defined('ABSPATH') || exit; require __DIR__ . '/vendor/autoload.php'; // do stuff
名前空間に加えて、WooCommerceの最新のコードベースもComposerオートローダーを使用しています。
これらのPHP設計の原則をカバーしたら、すべてのPHPレッスンをWordPressバックエンドのカスタマイズに結び付けて最後の推奨事項を1つ作成します。
最新のWordPress開発のベストプラクティス#4:ルーツスタックの使用を検討する
ルーツは、最も包括的な最新のWordPress開発ワークフローです。 ただし、次の理由から、必ずしもすべてのWordPressプロジェクトで使用する必要はありません。
- 根は最初から使用する必要があります。 最も一般的な理由は、本当に。 既存のプロジェクトのリファクタリングはコストがかかりすぎます。
- 意見があります。 同意する場合は良い、同意しない場合は悪い。 たとえば、テーマを整理する他の方法を好む場合があります。 意見のあるプロジェクトも、「彼らのやり方」を学ぶのに時間がかかります。
- 誰もがそれを知っているわけではありません。 Rootsスタックで構築したサイトを維持するためにあなたの後に来る開発者は、それが何であるかを知らず、WordPressフォルダーで何が起こったのか疑問に思うかもしれません。 私たちは仲間のWordPress開発者について考える必要があります。
一般に、プロジェクトを使用する前に、強く意見が分かれているプロジェクトのすべての利点と欠点を完全に理解する必要があります。
最新のPHPとソフトウェアの原則:WordPressバックエンド開発を堅牢にする
ソフトウェアを書く本当の方法が1つもないことはかなり明白です。 関心の分離などの概念は数十年前のものです。 しかし、それが実際に何を意味するのかは常に争われてきました。 たとえば、CSSを考えてみましょう。 最初は、HTMLでstyle
としてインライン化した後、関心の分離とはCSSシートを分離することであると判断しました。
10年早送り:現在のJavaScriptアプリは、関心の分離の実装としてコンポーネントを使用しています。 フロントエンド開発者はCSS-in-JSに引き寄せられます。これは、基本的に、CSSをHTMLでインライン化することを意味します(まあ、それはそれほど単純ではありませんが、あなたは考えを理解します)。 サークルが完成しました!
ベストプラクティスは、常に開発者エクスペリエンスの向上に関するものです。
プログラムは、人々が読むことができるように、そして偶然にマシンが実行するためにのみ作成する必要があります。
Abelson&Sussman、コンピュータプログラムの構造と解釈
このPHPWordPressチュートリアルのいくつかのプラクティスは、プロジェクトにすばやく簡単に実装できます。 たとえば、オートローダー:プロジェクトごとに1回実行して、楽しんでください。 一方、新しいソフトウェアアーキテクチャのアイデアは、便利で快適になるために、時間、練習、および多数の反復を必要とします。 ただし、報酬ははるかに大きくなります。 あなたはあなたがすることでより効率的になるだけでなく、あなたがより多くすることを楽しむでしょう。 そして、あなたがクライアントのために行う仕事を定期的に楽しむことは、おそらくそれが持続可能である唯一の方法です。