Dalam siri ini, kami menumpukan pada membina kotak meta WordPress yang boleh diselenggara. Apa yang saya maksudkan ialah kami telah bekerja keras untuk mencipta pemalam WordPress yang tersusun dengan baik, mematuhi piawaian pengekodan WordPress, dan boleh diselaraskan dan diselenggara dengan mudah semasa projek itu terus berkembang.
Walaupun kami telah melaksanakan beberapa amalan yang baik, masih ada ruang untuk pemfaktoran semula. Untuk siri ini, itu mengikut reka bentuk. Setiap kali anda membangunkan projek untuk pelanggan atau syarikat besar, kemungkinan besar anda perlu mengekalkan asas kod sedia ada. Jadi saya harap kita boleh kembali ke pangkalan kod kami untuk menambah baik beberapa kod yang kami tulis.
Sila ambil perhatian bahawa artikel ini tidak akan ditulis dalam format artikel lain - iaitu, ia tidak memerlukan pendekatan "mula-mula kita buat ini, kemudian kita buat ini" untuk pembangunan. Sebaliknya, kami akan menyerlahkan beberapa kawasan yang memerlukan pemfaktoran semula dan kemudian menanganinya secara bebas daripada perubahan lain yang kami buat.
Untuk menjadi jelas, tindakan pemfaktoran semula (seperti yang ditakrifkan oleh Wikipedia) ialah:
Pemfaktoran semula menambah baik sifat tidak berfungsi perisian. Faedah termasuk kebolehbacaan kod yang lebih baik dan mengurangkan kerumitan untuk meningkatkan kebolehselenggaraan kod sumber, dan penciptaan skema dalaman atau model objek yang lebih ekspresif untuk meningkatkan kebolehskalaan.
Ringkasnya, ia menjadikan kod lebih mudah dibaca, lebih ringkas dan lebih mudah untuk diikuti, semuanya tanpa mengubah tingkah laku kod dari perspektif pengguna akhir.
Ini boleh dicapai dalam beberapa cara yang berbeza, setiap satu unik untuk projek yang diberikan. Dalam kes kami, kami akan mempertimbangkan untuk memfaktorkan semula pembina kami, beberapa kaedah simpan, beberapa kaedah pembantu, dan sebagainya.
Akhirnya, matlamat kami adalah untuk mempamerkan beberapa strategi yang boleh anda gunakan dalam usaha WordPress masa hadapan anda. Matlamat saya adalah untuk menjadi seperinci mungkin dalam artikel ini, bagaimanapun, sila ambil perhatian bahawa mungkin terdapat peluang pemfaktoran semula lain yang tidak dilindungi.
Jika itu yang berlaku, itu bagus! Jangan ragu untuk membuatnya pada contoh asas kod anda sendiri. Dengan itu, mari kita mulakan.
Jika anda melihat pembina kami:
<?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' ) ); }
Sila ambil perhatian bahawa ia sedang melakukan dua perkara:
Adalah amalan biasa untuk melihat tetapan cangkuk dalam konteks pembina pemalam WordPress, tetapi itu bukan tempat yang bagus untuk bermula.
Pembina harus digunakan untuk memulakan semua sifat yang berkaitan dengan kelas tertentu supaya apabila pengguna membuat instantiate kelas, dia mempunyai semua yang diperlukan untuk menggunakannya.
Memandangkan mereka mungkin tidak mahu mendaftarkan cangkuk semasa memulakan kelas, kami perlu mengabstrakkannya ke dalam kaedah initialize_hooks
nya sendiri. Kod kami kini sepatutnya kelihatan seperti ini: initialize_hooks
方法。我们的代码现在应该如下所示:
<?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' ) ); }
之后,我们需要确保更新authors-commentary.php的核心代码,以便它正确实例化并注册钩子。
<?php function run_author_commentary() { $author_commentary = new Author_Commentary_Admin( 'author-commentary', '1.0.0' ); $author_commentary->initialize_hooks(); } run_author_commentary();
这里,主要区别在于我们更新了传递给主类的版本号,并且我们还在 initialize_hooks
函数“内联”>run_author_commentary。
如果您现在执行代码,一切都应该与重构之前完全一样。
我还想补充一点,您可以有一个单独的类负责协调挂钩和回调,以便该责任位于单独的类中。尽管我很喜欢这种方法,但这超出了本文的范围。
接下来,让我们对 class-authors-commentary-meta-box.php
执行相同的操作。我们可以简单地重命名构造函数,而不是创建一个新函数,因为构造函数实际上并不执行任何操作。这意味着我们的代码应该如下所示:
<?php public function __construct() { add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) ); add_action( 'save_post', array( $this, 'save_post' ) ); }
对此:
<?php public function initialize_hooks() { add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) ); add_action( 'save_post', array( $this, 'save_post' ) ); }
我们需要做的最后一个更改是更新主类中的构造函数,以便它现在读取我们在主插件类中创建的 initialize_hooks
函数的内部。
<?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' ) ); }
再次刷新页面,您的插件应该仍然可以像重构之前一样正常运行。
在 Authors_Commentary_Meta_Box
类中,我们在 save_post
函数中有许多非常多余的条件。发生这种情况时,通常意味着大部分功能可以抽象为辅助函数,然后从最初放置它们的函数内调用。
让我们看一下现在的代码:
<?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' ); } } }
除了开始的方法太长之外,我们还可以清理一些东西:
not
和逻辑 OR
运算符的初始条件$_POST
<?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; }
<?php if ( ! $this->is_valid_post_type() || ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) { return; }
initialize_hooks
"inline"> dalam konteks . </ol>
<p>Jika anda melaksanakan kod sekarang, semuanya sepatutnya sama seperti sebelum pemfaktoran semula. </p>
🎜Saya juga ingin menambah bahawa anda boleh mempunyai kelas berasingan yang bertanggungjawab untuk menyelaraskan cangkuk dan panggil balik supaya tanggungjawab berada dalam kelas yang berasingan. Walaupun saya suka pendekatan ini, ia di luar skop artikel ini. 🎜
🎜Seterusnya, mari kita lakukan perkara yang sama dengan <code class="inline">class-authors-commentary-meta-box.php
. Daripada mencipta fungsi baharu, kita hanya boleh menamakan semula pembina kerana pembina sebenarnya tidak melakukan apa-apa. Ini bermakna kod kami sepatutnya kelihatan seperti ini: 🎜
<?php if ( ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) { return; }
<?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 ] ); }
initialize_hooks
yang kami buat dalam kelas pemalam utama.
if ( $this->value_exists( 'authors-commentary-comments' ) ) { // ... } else { // ... }
Authors_Commentary_Meta_Box
, kami mempunyai banyak syarat yang sangat berlebihan dalam fungsi save_post
. Apabila ini berlaku, ini biasanya bermakna kebanyakan fungsi boleh diabstraksikan ke dalam fungsi pembantu dan kemudian dipanggil dari dalam fungsi di mana ia diletakkan pada asalnya. 🎜
🎜Jom lihat kod sekarang: 🎜
<?php if ( '' !== get_post_meta( $post_id, 'authors-commentary-comments', true ) ) { delete_post_meta( $post_id, 'authors-commentary-comments' ); }
not
dan logik OR
🎜
🎜Syarat untuk menyemak sama ada maklumat wujud dalam tatasusunan $_POST
🎜
🎜Membersih, mengemas kini dan/atau memadamkan fungsi metadata yang berkaitan🎜
🎜
🎜Jadi mari kita lihat setiap satu daripada mereka secara individu dan berusaha untuk memfaktorkan semula fungsi ini. 🎜
第一个条件检查的目的是确保当前用户能够将数据保存到给定的帖子。现在,我们实际上是在检查当前帖子类型是否是有效的帖子类型,以及用户是否有权保存给定 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; }
现在,负责确定用户是否可以保存帖子元数据的所有逻辑都封装在专门设计用于精确评估的函数中。
我们从这个开始:
<?php if ( ! $this->is_valid_post_type() || ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) { return; }
现在我们有这个:
<?php if ( ! $this->user_can_save( $post_id, 'authors_commentary_nonce', 'authors_commentary_save' ) ) { return; }
阅读起来容易多了,不是吗?
接下来,在开始清理、验证和保存(或删除)元数据之前,我们将检查 $_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 ] ); }
接下来,重构最初调用 的所有调用!空( $_POST[ ... ] )
以便他们利用此功能。
例如,函数调用应如下所示:
if ( $this->value_exists( 'authors-commentary-comments' ) ) { // ... } else { // ... }
请注意,在该函数中放置的整个条件中,如果值不存在,则每次删除帖子元数据的评估看起来都完全相同。
例如,我们每次都会看到这样的东西:
<?php if ( '' !== get_post_meta( $post_id, 'authors-commentary-comments', true ) ) { delete_post_meta( $post_id, 'authors-commentary-comments' ); }
这显然是重构代码的机会。因此,让我们创建一个名为 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' ); } }
现在我们可以返回并替换所有 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' ); }
此时,我们实际上只有这部分代码的另一个方面需要重构。
现在,保存帖子元数据的方式是通过评估 $_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; }
接下来,我们可以更新清理调用以使用此方法。但在此之前,我们还需要编写一个小助手,负责使用经过净化的输入更新帖子元数据:
<?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 ); }
现在我们可以更新之前在函数中使用的所有条件,如下所示:
<?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' ); } }
请注意,我们实际上可以进一步重构这个特定的部分,这样就没有那么多的条件,但是考虑到文章的长度、时间的长度,并且还尝试引入一些其他策略,这将是留作练习,在您自己的时间完成。
到目前为止,我们已经完成了我们的插件。我们编写了一个插件,引入了一个元框,为撰写博客文章的作者提供选项。
此外,我们还采用了 WordPress 编码标准、一些强大的文件组织策略,并创建了许多辅助方法和抽象,这将帮助我们在未来的开发中维护这个特定的插件。
由于突出显示每一个重构机会并不容易,因此可能还需要进行其他更改。在您自己的时间里,请随意尝试自己实现其中一些。
总的来说,我希望您喜欢本系列并从中学到很多东西,并且我希望它能帮助您在未来基于 WordPress 的项目中编写更好、更易于维护的代码。
Atas ialah kandungan terperinci Refactor: Tingkatkan kotak meta WordPress untuk penyelenggaraan jangka panjang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!