5부 – WordPress 및 객체 지향 프로그래밍: WordPress 예제 – 구현: 관리 메뉴

게시 됨: 2022-02-04

객체 지향 프로그래밍에 대한 이전 기사에서 우리는 결국 객체 지향 플러그인을 위해 고안한 디자인에 대해 논의했습니다.

이제 가장 흥미로운 부분으로 들어가 어떻게 구현했는지 자세히 살펴보겠습니다!

객체 지향 프로그래밍의 기본, 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 Settings 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 는 호출 객체의 값입니다. 이 경우 $thisPressidium_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 { // ... }

이것은 객체 지향 프로그래밍의 핵심 개념 중 하나인 상속 의 좋은 예입니다. 클래스를 확장할 때 자식 클래스(이 경우 Settings_Page )는 부모 클래스에서 모든 public 및 protected 메서드, 속성 및 상수를 상속합니다.

이것을 사용하고 일부 기본값을 설정할 수 있습니다. 예를 들어 다음과 같이 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() 의 네 번째 인수)는 각 메뉴 페이지에 대해 고유해야 합니다.

Admin_Page 기본 클래스에서 이 메서드를 정의하려면 모든 단일 자식 클래스가 이 메서드를 재정의하도록 하는 방법이 필요합니다. 글쎄, 우리는 더 나은 것을 할 수 있습니다. 메서드의 서명을 선언하고 구현을 완전히 건너뛸 수 있습니다.

추상 메소드를 입력하십시오!

추상 클래스 및 메서드

추상 으로 정의된 메소드는 단순히 메소드의 서명을 선언하고 구현을 정의할 수 없습니다.

 /** * Return page slug. * * @return string */ abstract protected function get_slug();

최소한 하나의 추상 메서드를 포함하는 모든 클래스도 추상 이어야 합니다 . 즉, Admin_Page 클래스도 추상으로 정의해야 합니다.

 abstract class Admin_Page { // ...

여기에서 추상으로 정의된 클래스는 인스턴스화할 수 없다는 점을 지적하는 것도 중요합니다. 따라서 더 이상 Admin_Page 를 직접 인스턴스화할 수 없습니다.

다음은 클래스의 시각화입니다.

추상 클래스에서 상속할 때 자식 클래스는 부모 클래스 선언에서 추상으로 표시된 모든 메서드를 정의 해야 합니다 . 즉, Settings_Pageget_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 예제 – 디자인