パート5– WordPressとオブジェクト指向プログラミング:WordPressの例–実装:管理メニュー
公開: 2022-02-04オブジェクト指向プログラミングに関する前回の記事では、オブジェクト指向プラグインの最終的な設計について説明しました。
今、私たちはそれをどのように実装したかをより深く掘り下げる最もエキサイティングな部分に入ります!
実装のいくつかの部分を一度に1ステップずつ説明し、オブジェクト指向プログラミングの非常に基本的なこと、PHP構文、いくつかのコアコンセプトについて説明し、SOLIDの原則についても詳しく説明します。
この記事の終わりまでに、OOPをよりよく理解し、独自のオブジェクト指向プラグインを作成することにワクワクすることを願っています。
入門
WordPressプラグインの開発全般に精通していることを前提としているため、プラグインのオブジェクト指向の側面に焦点を当てます。 プラグイン開発に不慣れな場合、または復習が必要な場合は、最初に最初のWordPressプラグインを作成する方法を学ぶ必要があります。
プラグインディレクトリ(つまり、/ wp-content / plugins / prsdm-limit-login-attempts)の下に新しいprsdm-limit-login-attempts.phpファイルを作成することにより、いつものように始めましょう。
メインのプラグインファイルには、既に使い慣れているプラグインヘッダーが含まれます。
/** * Plugin Name: PRSDM Limit Login Attempts * Plugin URI: https://pressidium.com * Description: Limit rate of login attempts, including by way of cookies, for each IP. * Author: Pressidium * Author URI: https://pressidium.com * Text Domain: prsdm-limit-login-attempts * License: GPL-2.0+ * Version: 1.0.0 */
そして、それに直接アクセスすることを防ぐための単純なifステートメント。
if ( ! defined( 'ABSPATH' ) ) { exit; }
今のところ必要なのはそれだけです。 このファイルは後で再検討します。
管理メニューの作成
プラグインを開発するとき、多くの場合、プラグインを構成する方法をユーザーに提供する必要があります。 そこで設定ページが登場します。設定ページを作成するために、WordPress設定APIを利用する管理メニューを追加します。
それでは、オブジェクト指向APIがどのように見えるかについて考え始めましょう。
理想的には、 Pressidium_LLA_Settings_Page
をインスタンス化して、それで完了したいと思います。 クラスのインスタンスを作成するには、 new
キーワードを使用する必要があります。
new Pressidium_LLA_Settings_Page();
それでは、 Pressidium_LLA_Settings_Page
クラスがどのように見えるかを考えてみましょう。
class
キーワードを使用して、新しいクラスを作成することから始めます。
class Pressidium_LLA_Settings_Page {}
他のWordPressプラグインとの名前の衝突を防ぐために、クラス名の前に一意の識別子であるPressidium_LLA_
を付ける必要があります。 プレフィックスは、他のプラグインがクラスを上書きしたり、誤って呼び出したりするのを防ぎます。 クラス名が一意である限り、または名前空間を使用している限り、他のプラグインとの競合は発生しません。
コンストラクター
次に、admin_menuとadmin_initにフックします。 簡単にするために、コンストラクターでadd_action()を呼び出すだけです(ネタバレ注意:これは後で変更します)。
class Pressidium_LLA_Settings_Page { /** * Settings_Page constructor. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_page' ) ); add_action( 'admin_init', array( $this, 'register_sections' ) ); } }
コンストラクターを持つクラスは、オブジェクトがインスタンス化されたときにこのメソッドを呼び出します。 したがって、 __construct()
メソッドは、実行する可能性のある初期化に最適です。
add_action()
呼び出しを詳しく見てみましょう。 過去にWordPressプラグインを開発したことがある場合は、次のようなものを期待しているかもしれません。
add_action( 'admin_menu', 'my_plugin_prefix_add_page' );
しかし、代わりに、次のものがあります。
add_action( 'admin_menu', array( $this, 'add_page' ) );
ここで配列の使用について混乱するかもしれません。 インスタンス化されたオブジェクトのメソッドをコールバック/呼び出し可能オブジェクトとして渡したい場合は常に、インデックス0のオブジェクトとインデックス1のメソッド名を含む配列を使用できます。
$ thisとは何ですか?
これは、オブジェクトコンテキスト内からメソッドが呼び出されたときに使用できる疑似変数です。 $this
は呼び出し元オブジェクトの値です。 この場合、 $this
はPressidium_LLA_Settings_Page
のインスタンスです。
さらに、すべての「関数」はクラスにラップされたメソッドになっているため、メソッド名の前にプレフィックスを付ける必要はありません。
名前空間
PHPの名前空間を使用すると、関連するクラス、インターフェイス、関数などをグループ化して、コードと内部PHPまたはサードパーティのクラス/関数との間の名前の衝突を防ぐことができます。
先に進んでそれらを使用してみましょう。これにより、クラスのプレフィックスを付ける必要がなくなります。
namespace
キーワードを使用して名前空間を宣言します。
namespace Pressidium;
名前空間はサブレベルで定義できます。
namespace Pressidium\Limit_Login_Attempts;
設定ページを作成しているので、「ページ」サブ名前空間を宣言して、管理ページに関連するものをグループ化します。
namespace Pressidium\Limit_Login_Attempts\Pages;
ついにPressidium_LLA_
プレフィックスを取り除くことができます!
namespace Pressidium\Limit_Login_Attempts\Pages; class Settings_Page { // ...
Settings_Page
クラスを含む別のWordPressプラグインは、そのクラスとクラスが同じ名前空間に存在しないため、もう問題ではありません。
同じ名前空間内でSettings_Page
をインスタンス化する場合、それを省略できます。
namespace Pressidium\Limit_Login_Attempts\Pages; $settings_page = new Settings_Page();
名前空間の外でSettings_Page
をインスタンス化するときは、次のように指定する必要があります。
namespace Another\Namespace; $settings_page = new \Pressidium\Limit_Login_Attempts\Pages\Settings_Page();
または、 use
演算子を使用してクラスをインポートすることもできます。
use Pressidium\Limit_Login_Attempts\Pages\Settings_Page; $settings_page = new Settings_Page();
フックコールバックの追加
次に、これらのadd_page()
)メソッドとregister_sections()
メソッドを宣言しましょう。
class Settings_Page { /** * Settings_Page constructor. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_page' ) ); add_action( 'admin_init', array( $this, 'register_sections' ) ); } /** * Add this page as a top-level menu page. */ public function add_page() { // TODO: Implement this method. } /** * Register sections. */ public function register_sections() { // TODO: Implement this method. } }
add_page()メソッドは、add_menu_page()WordPress関数を呼び出すだけです。
public function add_page() { add_menu_page( __( 'Limit Login Attempts Settings', 'prsdm-limit-login-attempts' ), __( 'Limit Login Attempts', 'prsdm-limit-login-attempts' ), 'manage_options', 'prsdm_limit_login_attempts_settings', array( $this, 'render' ), 'dashicons-shield-alt', null ); }
これは、WordPressプラグインを開発するための複雑な方法のようです。 追加の手順を使用して、WordPress関数を呼び出すだけです。
まあ、それは正確に「再利用可能」ではありません。追加したいすべての管理メニュー/ページに対して、この余分なコードをすべて作成する必要があります。
リファクタリング
オブジェクト指向プログラミングを利用してコードを再利用可能にするために、コードを少しリファクタリングしてみましょう。 add_page()
のハードコードされた値を、次のようないくつかのメソッドに置き換えることから始めます。
public function add_page() { add_menu_page( $this->get_page_title(), // page_title $this->get_menu_title(), // menu_title $this->get_capability(), // capability $this->get_slug(), // menu_slug array( $this, 'render' ), // callback function $this->get_icon_url(), // icon_url $this->get_position() // position ); }
これらのメソッドをprotected
たものとして定義するので、クラス自体とその子/親クラスからのみアクセスできます。
protected function get_page_title() { /* ... */ } protected function get_menu_title() { /* ... */ } protected function get_capability() { /* ... */ } protected function get_slug() { /* ... */ } protected function get_icon_url() { /* ... */ } protected function get_position() { /* ... */ }
すごい! これで、このクラスを、拡張元の再利用可能な汎用クラスとして使用できます。
再設計
これはおそらく最終的には起こるだろうとお話しました。 クラスを構築しながら、クラスのデザインを再考します。
これが基本クラスになるため、 Admin_Page
などのより一般的な名前に名前を変更します。 これまでのところ、次のようになります。
class Admin_Page { /** * Admin_Page constructor. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_page' ) ); add_action( 'admin_init', array( $this, 'register_sections' ) ); } /** * Add this page as a top-level menu page. */ public function add_page() { add_menu_page( $this->get_page_title(), // page_title $this->get_menu_title(), // menu_title $this->get_capability(), // capability $this->get_slug(), // menu_slug array( $this, 'render' ), // callback function $this->get_icon_url(), // icon_url $this->get_position() // position ); } /** * Register sections. */ public function register_sections() { // TODO: Implement this method. } protected function get_page_title() { /* ... */ } protected function get_menu_title() { /* ... */ } protected function get_capability() { /* ... */ } protected function get_slug() { /* ... */ } protected function get_icon_url() { /* ... */ } protected function get_position() { /* ... */ } }
これで、そのAdmin_Page
基本クラスを拡張する個別のSettings_Page
を作成できます。
class Settings_Page extends Admin_Page { // ... }
これは、オブジェクト指向プログラミングのコアコンセプトの1つである継承の優れた例です。 クラスを拡張する場合、子クラス(この場合はSettings_Page
)は、親クラスからすべてのパブリックおよび保護されたメソッド、プロパティ、および定数を継承します。
これを利用して、いくつかのデフォルト値を設定できます。 たとえば、次のようにget_icon_url()
メソッドを定義することにより、すべてのメニューページに汎用アイコンを設定します。
class Admin_Page { // ... /** * Return the menu icon to be used for this menu. * * @link https://developer.wordpress.org/resource/dashicons/ * * @return string */ protected function get_icon_url() { return 'dashicons-admin-generic'; } }
クラスがこれらのメソッドをオーバーライドしない限り、それらは元の機能を保持します。 したがって、デフォルトでは、すべての子クラスがその汎用アイコンを使用します。
ただし、特定のメニューページに別のアイコンを設定する場合は、次のように、子クラスのget_icon_url()
メソッドをオーバーライドするだけです。
class Settings_Page extends Admin_Page { protected function get_icon_url() { return 'dashicons-shield-alt'; } }
ただし、子クラスごとに異なる必要がある値がいくつかあります。 たとえば、メニュースラッグadd_menu_page()
の4番目の引数)は、メニューページごとに一意である必要があります。
Admin_Page
基本クラスでこのメソッドを定義する場合、すべての子クラスがこのメソッドをオーバーライドすることを確認する方法が必要になります。 まあ、私たちはさらに良いことをすることができます。 メソッドのシグネチャを宣言して、その実装を完全にスキップできます。
抽象メソッドを入力してください!
抽象クラスとメソッド
抽象として定義されたメソッドは、メソッドのシグネチャを宣言するだけであり、その実装を定義することはできません。
/** * Return page slug. * * @return string */ abstract protected function get_slug();
少なくとも1つの抽象メソッドを含むクラスも抽象でなければなりません。 つまり、Admin_Pageクラスも抽象として定義する必要があります。
abstract class Admin_Page { // ...
ここで、abstractとして定義されたクラスはインスタンス化できないことを指摘することも重要です。 そのため、 Admin_Page
を直接インスタンス化することはできなくなりました。
クラスの視覚化もここにあります:
抽象クラスから継承する場合、子クラスは、親クラスの宣言で抽象とマークされたすべてのメソッドを定義する必要があります。 つまり、 Settings_Page
はget_slug()
メソッドを実装する必要があります。
class Settings_Page extends Admin_Page { // ... protected function get_slug() { return 'prsdm_limit_login_attempts_settings'; } // ... }
同様に、 add_page()
が必要とする残りの保護されたメソッドを実装する必要があります。
管理ページのセクションとフィールドを登録してコンテンツをレンダリングする方法に進む前に、WordPressの設定について少し話しましょう。
設定API
すでに設定APIに精通していることを前提としています。 ただし、念のため、要点は次のとおりです。
- settings_fields()—設定ページのnonce、action、およびoption_pageフィールドを出力します。 基本的に、非表示のフォームフィールド。
- do_settings_sections()—特定の設定ページに追加されたすべての設定セクション(およびそのフィールド)を出力します。
- add_settings_section()—設定ページに新しいセクションを追加します。
- add_settings_field()—設定ページのセクションに新しいフィールドを追加します。
- register_setting()—設定とそのデータを登録します。
これにまだ慣れていない場合は、この記事を読むのをやめて、カスタムプラグインの設定ページを作成する方法に関する関連記事を確認してください。
同じページが表示されたので、 register_sections()
メソッドに戻りましょう。 もう一度、一歩下がってAPIについて考える必要があります。
Admin_Page
クラスでadd_page()
メソッドを定義したので、そこでもrender()
メソッドを定義します。 他のメソッドの戻り値を引数としてWordPress関数に渡します。
abstract class Admin_Page { // ... /** * Render this admin page. */ public function render() { ?> <div class="wrap"> <form action="options.php" method="post"> <h1><?php echo esc_html( $this->get_page_title() ); ?></h1> <?php settings_fields( $this->get_slug() ); do_settings_sections( $this->get_slug() ); submit_button( __( 'Change Options', 'prsdm-limit-login-attempts' ) ); ?> </form> </div> <?php } }
そうすれば、これらのWordPress機能を直接気にする必要がなくなります。 これは、将来追加する可能性のある管理ページは、 Settings_Page
と同じように子クラスを介して構築され、そのレンダリングはAdmin_Page
親クラスの継承されたrender()
メソッドを介して行われるためです。
結論
すごい! 管理メニューの登録と設定ページの追加を担当するクラスを作成しました。
シリーズの次の記事では、設定ページを作成し続け、そのセクション、フィールド、および要素を登録します。
オブジェクト指向プログラミングシリーズのパート6を読むには、ここをクリックしてください
関連項目
- WordPressとオブジェクト指向プログラミング–概要
- パート2– WordPressとオブジェクト指向プログラミング:実際の例
- パート3– WordPressとオブジェクト指向プログラミング:ΑWordPressの例–スコープの定義
- パート4– WordPressとオブジェクト指向プログラミング:WordPressの例–デザイン