Table of Contents
Reconstruction
Constructor
Auxiliary methods
1。初始条件
2.检查 $_POST 数组
2.删除元数据
3.消毒和保存
结论
Home Backend Development PHP Tutorial Refactor: Enhance the WordPress meta box for long-term maintenance

Refactor: Enhance the WordPress meta box for long-term maintenance

Aug 30, 2023 pm 08:37 PM

重构:增强 WordPress 元框以实现长期维护

In this series, we focus on building maintainable WordPress meta boxes. What I mean is that we have been working hard to create a WordPress plugin that is well organized, adheres to WordPress coding standards, and can be easily adjusted and maintained as the project continues to progress.

Although we have implemented some good practices, there is still room for refactoring. For this series, that's by design. Whenever you develop a project for a client or a large company, the chances are quite high that you will have to maintain an existing code base. So I hope we can go back to our code base to improve some of the code we wrote.

Please note that this article will not be written in the format of other articles - that is, it will not take a "first we do this, then we do this" approach to development. Instead, we'll highlight a few areas that need refactoring and then tackle them independently of the other changes we're making.

Reconstruction

To be clear, the act of refactoring (as defined by Wikipedia) is:

Refactoring improves non-functional properties of the software. Benefits include improved code readability and reduced complexity to improve source code maintainability, and the creation of a more expressive internal schema or object model to improve scalability.

In short, it makes code more readable, simpler, and easier to follow, all without changing the behavior of the code from the end user's perspective.

This can be accomplished in a number of different ways, each unique to a given project. In our case, we'll consider refactoring our constructor, some save methods, some helper methods, and so on.

Ultimately, our goal is to demonstrate some strategies you can use in your future WordPress efforts. My goal is to be as detailed as possible in this article; however, please note that there may be other refactoring opportunities that are not covered.

If that’s the case, that would be great! Feel free to make them on your own codebase instance. With that being said, let’s get started.

Constructor

If you look at our constructor:

<?php 
    	
public function __construct( $name, $version ) {

	$this->name = $name;
	$this->version = $version;

	$this->meta_box = new Authors_Commentary_Meta_Box();

	add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
	add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );

}
Copy after login

Please note that it is currently doing two things:

  1. Initialize attributes such as name and version
  2. Using WordPress Registration Hooks

It is common practice to view hook settings in the context of a WordPress plugin's constructor, but this is not a great place to start.

Constructors should be used to initialize all properties related to a given class so that when a user instantiates a class, he/she has everything needed to use the class.

Since they may not want to register the hook when initializing the class, we need to abstract it into its own initialize_hooks method. Our code should now look like this:

<?php

public function __construct( $name, $version ) {

    $this->name = $name;
    $this->version = $version;

    $this->meta_box = new Authors_Commentary_Meta_Box();

}

public function initialize_hooks() {
	
	add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
	add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
	
}
Copy after login

After that, we need to make sure to update the core code of authors-commentary.php so that it instantiates and registers the hook correctly.

<?php

function run_author_commentary() {
    
	$author_commentary = new Author_Commentary_Admin( 'author-commentary', '1.0.0' );
	$author_commentary->initialize_hooks();
	
}
run_author_commentary();
Copy after login

Here, the main difference is that we update the version number passed to the main class, and we also explicitly call the initialize_hooks function "inline">run_author_commentary in the context of <p> If you execute the code now, everything should look exactly the same as it did before the refactoring. </p> <p> I would also like to add that you can have a separate class responsible for coordinating hooks and callbacks so that the responsibility is in a separate class. As much as I like this approach, it's beyond the scope of this article. </p> <p>Next, let’s do the same thing with <code class="inline">class-authors-commentary-meta-box.php. Instead of creating a new function, we can simply rename the constructor because the constructor doesn't actually do anything. This means our code should look like this:

<?php 

public function __construct() {

    add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
    add_action( 'save_post', array( $this, 'save_post' ) );

}
Copy after login

Regarding:

<?php

public function initialize_hooks() {

    add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
    add_action( 'save_post', array( $this, 'save_post' ) );

}
Copy after login

The last change we need to make is to update the constructor in the main class so that it now reads the inside of the initialize_hooks function we created in the main plugin class.

<?php

public function initialize_hooks() {

    $this->meta_box->initialize_hooks();

    add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
    add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );

}
Copy after login

Refresh the page again and your plugin should still function as it did before the refactoring.

Auxiliary methods

In the Authors_Commentary_Meta_Box class we have a lot of very redundant conditions in the save_post function. When this happens, it usually means that much of the functionality can be abstracted into helper functions and then called from within the function where they were originally placed.

Let’s take a look at the current code:

<?php
    
public function save_post( $post_id ) {

	/* If we're not working with a 'post' post type or the user doesn't have permission to save,
	 * then we exit the function.
	 */
	if ( ! $this->is_valid_post_type() || ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) {
		return;
	}

	// If the 'Drafts' textarea has been populated, then we sanitize the information.
	if ( ! empty( $_POST['authors-commentary-drafts'] ) ) {

		// We'll remove all white space, HTML tags, and encode the information to be saved
		$drafts = trim( $_POST['authors-commentary-drafts'] );
		$drafts = esc_textarea( strip_tags( $drafts ) );

		update_post_meta( $post_id, 'authors-commentary-drafts', $drafts );

	} else {

		if ( '' !== get_post_meta( $post_id, 'authors-commentary-drafts', true ) ) {
			delete_post_meta( $post_id, 'authors-commentary-drafts' );
		}

	}

	// If the 'Resources' inputs exist, iterate through them and sanitize them
	if ( ! empty( $_POST['authors-commentary-resources'] ) ) {

		$resources = $_POST['authors-commentary-resources'];
		$sanitized_resources = array();
		foreach ( $resources as $resource ) {

			$resource = esc_url( strip_tags( $resource ) );
			if ( ! empty( $resource ) ) {
				$sanitized_resources[] = $resource;
			}

		}

		update_post_meta( $post_id, 'authors-commentary-resources', $sanitized_resources );

	} else {

		if ( '' !== get_post_meta( $post_id, 'authors-commentary-resources', true ) ) {
			delete_post_meta( $post_id, 'authors-commentary-resources' );
		}

	}

	// If there are any values saved in the 'Published' input, save them
	if ( ! empty( $_POST['authors-commentary-comments'] ) ) {
		update_post_meta( $post_id, 'authors-commentary-comments', $_POST['authors-commentary-comments'] );
	} else {

		if ( '' !== get_post_meta( $post_id, 'authors-commentary-comments', true ) ) {
			delete_post_meta( $post_id, 'authors-commentary-comments' );
		}

	}

}
Copy after login

Besides the starting method being too long, we can also clean up some things:

  1. Initial conditions using logical not and logical OR operators
  2. Check $_POST Conditions for whether information exists in the array
  3. Cleaning, updating and/or deleting functions of associated metadata

So let's look at each of them individually and work on refactoring this function.

1。初始条件

第一个条件检查的目的是确保当前用户能够将数据保存到给定的帖子。现在,我们实际上是在检查当前帖子类型是否是有效的帖子类型,以及用户是否有权保存给定 WordPress 传递的当前随机数值。

现在,代码如下:

如果这不是有效的帖子类型或用户没有保存权限,则退出此功能。

这并不是很糟糕,但绝对可以改进。让我们将其合并到单个评估中,而不是使用 OR ,使其显示为:

如果用户没有保存权限,则退出此功能。

幸运的是,这是一个相对容易的修复。由于保存的帖子类型有助于确定用户是否有权保存帖子,因此我们可以将该逻辑移至 user_can_save 函数中。

因此,让我们将 is_valid_post_type 函数移至 user_can_save 函数中:

<?php

private function user_can_save( $post_id, $nonce_action, $nonce_id ) {

    $is_autosave = wp_is_post_autosave( $post_id );
    $is_revision = wp_is_post_revision( $post_id );
    $is_valid_nonce = ( isset( $_POST[ $nonce_action ] ) && wp_verify_nonce( $_POST[ $nonce_action ], $nonce_id ) );

    // Return true if the user is able to save; otherwise, false.
    return ! ( $is_autosave || $is_revision ) && $this->is_valid_post_type() && $is_valid_nonce;

}
Copy after login

现在,负责确定用户是否可以保存帖子元数据的所有逻辑都封装在专门设计用于精确评估的函数中。

我们从这个开始:

<?php
    
if ( ! $this->is_valid_post_type() || ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) {
	return;
}
Copy after login

现在我们有这个:

<?php
    
if ( ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) {
	return;
}
Copy after login

阅读起来容易多了,不是吗?

2.检查 $_POST 数组

接下来,在开始清理、验证和保存(或删除)元数据之前,我们将检查 $_POST 集合以确保数据确实存在。

我们可以编写一个小的辅助函数来为我们处理这个评估。虽然我们本质上是编写了一些代码,使我们的评估更加冗长,但与我们直接保留它们相比,条件语句读起来会更清晰一些。

首先,引入以下函数(注意它接受一个参数):

<?php

/**
 * Determines whether or not a value exists in the $_POST collection
 * identified by the specified key.
 *
 * @since   1.0.0
 *
 * @param   string    $key    The key of the value in the $_POST collection.
 * @return  bool              True if the value exists; otherwise, false.
 */
private function value_exists( $key ) {
    return ! empty( $_POST[ $key ] );
}
Copy after login

接下来,重构最初调用 的所有调用!空( $_POST[ ... ] ) 以便他们利用此功能。

例如,函数调用应如下所示:

if ( $this->value_exists( 'authors-commentary-comments' ) ) {
    // ...
} else {
	// ...
}
Copy after login

2.删除元数据

请注意,在该函数中放置的整个条件中,如果值不存在,则每次删除帖子元数据的评估看起来都完全相同。

例如,我们每次都会看到这样的东西:

<?php

if ( '' !== get_post_meta( $post_id, 'authors-commentary-comments', true ) ) {
    delete_post_meta( $post_id, 'authors-commentary-comments' );
}
Copy after login

这显然是重构代码的机会。因此,让我们创建一个名为 delete_post_meta 的新函数,并让它封装所有这些信息:

<?php

/**
 * Deletes the specified meta data associated with the specified post ID 
 * based on the incoming key.
 *
 * @since    1.0.0
 * @access   private
 * @param    int    $post_id    The ID of the post containing the meta data
 * @param    string $meta_key   The ID of the meta data value
 */
private function delete_post_meta( $post_id, $meta_key ) {
    
	if ( '' !== get_post_meta( $post_id, $meta_key, true ) ) {
		delete_post_meta( $post_id, '$meta_key' );
	}
	
}
Copy after login

现在我们可以返回并替换所有 else 条件评估以调用此单个函数,使其读取如下内容:

<?php
    
// If the 'Drafts' textarea has been populated, then we sanitize the information.
if ( $this->value_exists( 'authirs-commentary-drafts' ) ) {

	// We'll remove all white space, HTML tags, and encode the information to be saved
	$drafts = trim( $_POST['authors-commentary-drafts'] );
	$drafts = esc_textarea( strip_tags( $drafts ) );

	update_post_meta( $post_id, 'authors-commentary-drafts', $drafts );

} else {
	$this->delete_post_meta( $post_id, 'authors-commentary-drafts' );
}
Copy after login

此时,我们实际上只有这部分代码的另一个方面需要重构。

3.消毒和保存

现在,保存帖子元数据的方式是通过评估 $_POST 集合中数据是否存在的过程来完成的,并根据信息类型对其进行清理,然后将其保存到帖子元数据中。

理想情况下,我们希望在自己的函数中清理数据,并将帖子元数据保存在自己的函数中。因此,我们需要引入新的功能。

首先,让我们进行消毒工作。因为我们正在处理 textareas 和数组,所以我们需要通过几种方法来处理清理调用。由于我们要么使用数组,要么不使用数组,所以我们可以创建一个函数,该函数接受一个可选参数,表示我们是否正在使用数组。

如果我们不使用数组,那么我们会将传入的数据视为文本;否则,我们会将其视为数组:

<?php
    
/**
 * Sanitizes the data in the $_POST collection identified by the specified key
 * based on whether or not the data is text or is an array.
 *
 * @since    1.0.0
 * @access   private
 * @param    string        $key                      The key used to retrieve the data from the $_POST collection.
 * @param    bool          $is_array    Optional.    True if the incoming data is an array.
 * @return   array|string                            The sanitized data.
 */
private function sanitize_data( $key, $is_array = false ) {

	$sanitized_data = null;

	if ( $is_array ) {

		$resources = $_POST[ $key ];
		$sanitized_data = array();

		foreach ( $resources as $resource ) {

			$resource = esc_url( strip_tags( $resource ) );
			if ( ! empty( $resource ) ) {
				$sanitized_data[] = $resource;
			}

		}

	} else {

		$sanitized_data = '';
		$sanitized_data = trim( $_POST[ $key ] );
		$sanitized_data = esc_textarea( strip_tags( $sanitized_data ) );

	}

	return $sanitized_data;

}
Copy after login

接下来,我们可以更新清理调用以使用此方法。但在此之前,我们还需要编写一个小助手,负责使用经过净化的输入更新帖子元数据:

<?php

private function update_post_meta( $post_id, $meta_key, $meta_value ) {
    
    if ( is_array( $_POST[ $meta_key ] ) ) {
        $meta_value = array_filter( $_POST[ $meta_key ] );
	}

    update_post_meta( $post_id, $meta_key, $meta_value );
}
Copy after login

现在我们可以更新之前在函数中使用的所有条件,如下所示:

<?php
    
public function save_post( $post_id ) {

	if ( ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) {
		return;
	}

	if ( $this->value_exists( 'authors-commentary-drafts' ) ) {

		$this->update_post_meta(
			$post_id,
			'authors-commentary-drafts',
			$this->sanitize_data( 'authors-commentary-drafts' )
		);

	} else {
		$this->delete_post_meta( $post_id, 'authors-commentary-drafts' );
	}

	if ( $this->value_exists( 'authors-commentary-resources' ) ) {

		$this->update_post_meta(
			$post_id,
			'authors-commentary-resources',
			$this->sanitize_data( 'authors-commentary-resources', true )
		);

	} else {
		$this->delete_post_meta( $post_id, 'authors-commentary-resources' );
	}

	if ( $this->value_exists( 'authors-commentary-comments' ) ) {

		$this->update_post_meta(
			$post_id,
			'authors-commentary-comments',
			$_POST['authors-commentary-comments']
		);

	} else {
		$this->delete_post_meta( $post_id, 'authors-commentary-comments' );
	}

}
Copy after login

请注意,我们实际上可以进一步重构这个特定的部分,这样就没有那么多的条件,但是考虑到文章的长度、时间的长度,并且还尝试引入一些其他策略,这将是留作练习,在您自己的时间完成。

结论

到目前为止,我们已经完成了我们的插件。我们编写了一个插件,引入了一个元框,为撰写博客文章的作者提供选项。

此外,我们还采用了 WordPress 编码标准、一些强大的文件组织策略,并创建了许多辅助方法和抽象,这将帮助我们在未来的开发中维护这个特定的插件。

由于突出显示每一个重构机会并不容易,因此可能还需要进行其他更改。在您自己的时间里,请随意尝试自己实现其中一些。

总的来说,我希望您喜欢本系列并从中学到很多东西,并且我希望它能帮助您在未来基于 WordPress 的项目中编写更好、更易于维护的代码。

The above is the detailed content of Refactor: Enhance the WordPress meta box for long-term maintenance. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Describe the SOLID principles and how they apply to PHP development. Describe the SOLID principles and how they apply to PHP development. Apr 03, 2025 am 12:04 AM

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

How to automatically set permissions of unixsocket after system restart? How to automatically set permissions of unixsocket after system restart? Mar 31, 2025 pm 11:54 PM

How to automatically set the permissions of unixsocket after the system restarts. Every time the system restarts, we need to execute the following command to modify the permissions of unixsocket: sudo...

How to debug CLI mode in PHPStorm? How to debug CLI mode in PHPStorm? Apr 01, 2025 pm 02:57 PM

How to debug CLI mode in PHPStorm? When developing with PHPStorm, sometimes we need to debug PHP in command line interface (CLI) mode...

Explain the concept of late static binding in PHP. Explain the concept of late static binding in PHP. Mar 21, 2025 pm 01:33 PM

Article discusses late static binding (LSB) in PHP, introduced in PHP 5.3, allowing runtime resolution of static method calls for more flexible inheritance.Main issue: LSB vs. traditional polymorphism; LSB's practical applications and potential perfo

How to send a POST request containing JSON data using PHP's cURL library? How to send a POST request containing JSON data using PHP's cURL library? Apr 01, 2025 pm 03:12 PM

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...

Explain late static binding in PHP (static::). Explain late static binding in PHP (static::). Apr 03, 2025 am 12:04 AM

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

See all articles