Indonesian (Bahasa Indonesia) translation by Ari Gustiawan (you can also view the original English article)
Wptuts Terbaik 2011: setiap minggu daru Januari, kita akan meninjau kembali beberapa posting favorit kami dari 2011. Perkembangan plugin dapat sering merasa seperti barat yang liat jika Anda membuat sesuatu dari awal tanpa boilerplate atau plugin yang serupa untuk bekerja - Tom 2 bagian seri Maintainable WordPress widget/Plugins yang dapat dipelihara menawarkan beberapa petunjuk praktis yang harus menjaga tetap di jalan!
Ketika datang ke pengembangan perangkat lunak, framework dan perpustakaan itu populer karena mereka membantu, kan? Mereka menyediakan cara yang konsisten untuk menulis dan mengatur kode dengan harapan membuat pembangunan dan pemeliharaan semudah mungkin.
Masalahnya adalah, prinsip-prinsip yang sama yang berlaku untuk lebih besar, sistem tingkat perusahaan sama berlaku untuk proyek-proyek kecil - seperti WordPress plugins - dikembangkan oleh tim kecil. Dan sama seperti sistem yang lebih besar penuh dengan bagian yang bergerak, seperti halnya dengan WordPress Plugin.
Misalnya: Anda punya kode inti yang bertanggung jawab untuk berkomunikasi dengan WordPress (melalui filter, action, dan hook), panel kontrol administrasi, client-side view, JavaScript file, style sheet, file lokalisasi dan seterusnya yang dicapai menggunakan setidaknya empat bahasa pemrograman yang berbeda.
Selama waktu saya menghabiskan di pembangunan WordPress, saya telah membuat beberapa boilerplate yang saya gunakan untuk memulai setiap proyek saya. Tutorial ini akan melihat kode Boilerplate Widget WordPress saya, bagaimana memanfaatkan dalam proyek-proyek baru, dan contoh aplikasi dengan harapan dapat membantu Anda mendapatkan proyek WordPress berikutnya untuk awal yang solid.
Widget Boilerplate
Organisasi
Ketika datang untuk pengembangan, saya biasanya mencoba untuk menjaga hal-hal tetap sederhana mungkin dengan perencanaan hanya untuk fitur yang diperlukan; Namun, ini adalah salah satu kasus di mana saya bertujuan untuk menjadi lengkap. Hal ini hampir selalu lebih mudah untuk memulai perencanaan boilerplate ketika Anda tahu semua komponen yang dapat masuk ke dalam sistem.
Plugin dapat akhirnya terdiri dari berikut:
- Kode inti plugin
- Style sheet
- Java script
- File lokalisasi
- Markup
- Gambar
Mempertimbangkan semua hal di atas, widget boilerplate direktori akan diletakkan seperti ini:



Kita akan melihat di setiap direktori secara rinci nanti dalam artikel.
Kerangka
Selain file organisasi, saya juga ingin menulis rintisan kode yang digunakan untuk menggerakkan widget. Wordpress [1] memiliki penjelasan rinci mengenai API Widget [2] dan karena ada cara yang disaraknakn untuk membuat mereka, saya mencoba untuk mengikutinya.
Selain itu, saya penggemar menulis kode saya dalam cara object-oriented dengan komentar kode untuk membantu menjelaskan apa yang terjadi di setiap daerah kode. Dengan demikian, kode widget awal terlihat seperti ini:
<?php /* Plugin Name: TODO Plugin URI: TODO Description: TODO Version: 1.0 Author: TODO Author URI: TODO Author Email: TODO License: Copyright 2011 TODO ([email protected]) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // TODO: change 'Plugin_Name' to the name of your actual plugin class Plugin_Name extends WP_Widget { /*--------------------------------------------------*/ /* Constructor /*--------------------------------------------------*/ /** * The widget constructor. Specifies the classname and description, instantiates * the widget, loads localization files, and includes necessary scripts and * styles. */ // TODO: This should match the title given in the class definition above. function Plugin_Name() { // Define constnats used throughout the plugin $this->init_plugin_constants(); // TODO: update classname and description $widget_opts = array ( 'classname' => PLUGIN_NAME, 'description' => __('Short description of the plugin goes here.', PLUGIN_LOCALE) ); $this->WP_Widget(PLUGIN_SLUG, __(PLUGIN_NAME, PLUGIN_LOCALE), $widget_opts); load_plugin_textdomain(PLUGIN_LOCALE, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' ); // Load JavaScript and stylesheets $this->register_scripts_and_styles(); } // end constructor /*--------------------------------------------------*/ /* API Functions /*--------------------------------------------------*/ /** * Outputs the content of the widget. * * @args The array of form elements * @instance */ function widget($args, $instance) { extract($args, EXTR_SKIP); echo $before_widget; // TODO: This is where you retrieve the widget values // Display the widget include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/widget.php'); echo $after_widget; } // end widget /** * Processes the widget's options to be saved. * * @new_instance The previous instance of values before the update. * @old_instance The new instance of values to be generated via the update. */ function update($new_instance, $old_instance) { $instance = $old_instance; // TODO Update the widget with the new values return $instance; } // end widget /** * Generates the administration form for the widget. * * @instance The array of keys and values for the widget. */ function form($instance) { // TODO define default values for your variables $instance = wp_parse_args( (array)$instance, array( '' => '' ) ); // TODO store the values of widget in a variable // Display the admin form include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/admin.php'); } // end form /*--------------------------------------------------*/ /* Private Functions /*--------------------------------------------------*/ /** * Initializes constants used for convenience throughout * the plugin. */ private function init_plugin_constants() { /* TODO * * This provides the unique identifier for your plugin used in * localizing the strings used throughout. * * For example: wordpress-widget-boilerplate-locale. */ if(!defined('PLUGIN_LOCALE')) { define('PLUGIN_LOCALE', 'plugin-name-locale'); } // end if /* TODO * * Define this as the name of your plugin. This is what shows * in the Widgets area of WordPress. * * For example: WordPress Widget Boilerplate. */ if(!defined('PLUGIN_NAME')) { define('PLUGIN_NAME', 'Plugin Name'); } // end if /* TODO * * this is the slug of your plugin used in initializing it with * the WordPress API. * This should also be the * directory in which your plugin resides. Use hyphens. * * For example: wordpress-widget-boilerplate */ if(!defined('PLUGIN_SLUG')) { define('PLUGIN_SLUG', 'plugin-name-slug'); } // end if } // end init_plugin_constants /** * Registers and enqueues stylesheets for the administration panel and the * public facing site. */ private function register_scripts_and_styles() { if(is_admin()) { $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.js', true); $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/admin.css'); } else { $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.css', true); $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/widget.css'); } // end if/else } // end register_scripts_and_styles /** * Helper function for registering and enqueueing scripts and styles. * * @name The ID to register with WordPress * @file_path The path to the actual file * @is_script Optional argument for if the incoming file_path is a JavaScript source file. */ private function load_file($name, $file_path, $is_script = false) { $url = WP_PLUGIN_URL . $file_path; $file = WP_PLUGIN_DIR . $file_path; if(file_exists($file)) { if($is_script) { wp_register_script($name, $url); wp_enqueue_script($name); } else { wp_register_style($name, $url); wp_enqueue_style($name); } // end if } // end if } // end load_file } // end class add_action('widgets_init', create_function('', 'register_widget("Plugin_Name");')); // TODO remember to change this to match the class definition above ?>
Melihat ada sejumlah TODO di seluruh kode. Ini berguna terutama dalam konteks menulis kode di atas boilerplate.
Perhatikan bahwa ada tiga bagian utama dari kode, seperti:
- Constructor. Fungsi ini bertanggung jawab untuk inisialisasi widget, mengimpor file lokalisasi dan termasuk menyertakan JavaScript dan style sheet.
- Fungsi API. Fungsi-fungsi ini adalah tiga fungsi yang diperlukan untuk mengelola, menampilkan dan memperbarui widget.
- Fungsi pembantu. Ini adalah fungsi private saya gunakan untuk membantu dengan tugas yang berulang atau yang diperlukan.
Tiga paling penting fungsi di atas, fungsi API diperlukan untuk mengembangkan plugin Anda.
- widget() ekstrak nilai yang disimpan dan merender ke view public
- update() akan membuat bertanggung jawab untuk memperbarui nilai yang sebelumnya telah disimpan dengan nilai-nilai yang diberikan oleh pengguna
- form() menjadikan bentuk administrasi dan menyediakan fungsionalitas yang diperlukan untuk menyimpan nilai-nilai baru.
Karena plugin sering dibagi antara fungsi administrasi dan fungsi untuk klien, saya membagi sumber JavaScript, style sheet, dan HTML dengan sesuai. Saya namai file ini sesuai dan tulisan rintisan mereka yang benar:
Sumber JavaScript:
admin.js:
jQuery(function($) { // Place your administration-specific code here });
widget.js:
jQuery(function($) { // Place your public facing JavaScript here });
Style sheet:
admin.css:
/* This style sheet is used to style the admin option form of the widget. */
widget.css:
/* This style sheet is used to style the public view of the widget. */
Views:
<!-- This file is used to markup the administration form of the widget. --> <!-- This file is used to markup the public facing widget. -->
Mudah, kan? Anda dapat lihat (dan fork!) seluruh boilerplate ini termasuk file lokalisasi dan README pada GitHub.
Sekarang ada tempat untuk segalanya dan ketika tiba saatnya untuk dikirm, Anda hanya mengecualikan file tertentu dari pembangunan akhir...
Contoh yang bekerja dengan jaringan sosial Anda
Ketika datang ke pemrograman, praktek membantu dalam mempelajari bahasa baru atau tip jadi di sini adalah sebuah contoh cepat tentang cara menggunakan boilerplate di atas untuk menciptakan sebuah widget yang sederhana untuk membuatnya mudah untuk berbagi link Anda ke Twitter, Facebook, dan Google+.
Pertama, kami akan mencantumkan persyaratan:
- View administrasi untuk memasukkan nilai-nilai. Ini termasuk markup dan gaya.
- Menghadap viewpublic untuk menampilkan link ke jaringan sosial. Ini juga termasuk markup dan gaya.
- Pilihan untuk menyimpan Twitter username, nama pengguna Facebook, dan ID Google+
Kedua, mari kita membuka boilerplate dan mulai stubbing bagian-bagian yang diperlukan.
Pertama, kita mendefinisikan nama nilai-nilai plugin, slug, dan nilai lokal. Ini digunakan berulang-ulang seluruh kode Jadi bagus untuk menyimpan mereka sebagai konstanta agar dengan mudah mengambil mereka. Temukan fungsi init_plugin_constants() dan pastikan bahwa kode Anda terlihat seperti ini:
private function init_plugin_constants() { if(!defined('PLUGIN_LOCALE')) { define('PLUGIN_LOCALE', 'my-social-network-locale'); } // end if if(!defined('PLUGIN_NAME')) { define('PLUGIN_NAME', 'My Social Networks'); } // end if if(!defined('PLUGIN_SLUG')) { define('PLUGIN_SLUG', 'My-Social-Networks'); } // end if } // end init_plugin_constants
Setelah itu, kita perlu menyiapkan konstruktor:
function My_Social_Network() { // Define constants used throughout the plugin $this->init_plugin_constants(); $widget_opts = array ( 'classname' => PLUGIN_NAME, 'description' => __('A simple WordPress widget for sharing a few of your social networks.', PLUGIN_LOCALE) ); $this->WP_Widget(PLUGIN_SLUG, __(PLUGIN_NAME, PLUGIN_LOCALE), $widget_opts); load_plugin_textdomain(PLUGIN_LOCALE, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' ); // Load JavaScript and stylesheets $this->register_scripts_and_styles(); } // end constructor
Dan potong fungsi-fungsi API:
function widget($args, $instance) { extract($args, EXTR_SKIP); echo $before_widget; $twitter_username = empty($instance['twitter_username']) ? '' : apply_filters('twitter_username', $instance['twitter_username']); $facebook_username = empty($instance['facebook_username']) ? '' : apply_filters('facebook_username', $instance['facebook_username']); $google_plus_id = empty($instance['google_plus_id']) ? '' : apply_filters('google_plus_id', $instance['google_plus_id']); // Display the widget include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/widget.php'); echo $after_widget; } // end widget function update($new_instance, $old_instance) { $instance = $old_instance; $instance['twitter_username'] = strip_tags(stripslashes($new_instance['twitter_username'])); $instance['facebook_username'] = strip_tags(stripslashes($new_instance['facebook_username'])); $instance['google_plus_id'] = strip_tags(stripslashes($new_instance['google_plus_id'])); return $instance; } // end widget function form($instance) { $instance = wp_parse_args( (array)$instance, array( 'twitter_username' => '', 'facebook_username' => '', 'google_plus_id' => '' ) ); $twitter_username = strip_tags(stripslashes($new_instance['twitter_username'])); $facebook_username = strip_tags(stripslashes($new_instance['facebook_username'])); $google_plus_id = strip_tags(stripslashes($new_instance['google_plus_id'])); // Display the admin form include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/admin.php'); } // end form
Versi akhir dari plugin akan terlihat seperti ini:
<?php /* Plugin Name: My Social Network Plugin URI: http://github.com/tommcfarlin/My-Social-Network Description: A simple WordPress widget for sharing a few of your social networks. Version: 1.0 Author: Tom McFarlin Author URI: http://tommcfarlin.com Author Email: [email protected] License: Copyright 2011 My Social Network ([email protected]) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class My_Social_Network extends WP_Widget { /*--------------------------------------------------*/ /* Constructor /*--------------------------------------------------*/ /** * The widget constructor. Specifies the classname and description, instantiates * the widget, loads localization files, and includes necessary scripts and * styles. */ function My_Social_Network() { // Define constants used throughout the plugin $this->init_plugin_constants(); $widget_opts = array ( 'classname' => PLUGIN_NAME, 'description' => __('A simple WordPress widget for sharing a few of your social networks.', PLUGIN_LOCALE) ); $this->WP_Widget(PLUGIN_SLUG, __(PLUGIN_NAME, PLUGIN_LOCALE), $widget_opts); load_plugin_textdomain(PLUGIN_LOCALE, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' ); // Load JavaScript and stylesheets $this->register_scripts_and_styles(); } // end constructor /*--------------------------------------------------*/ /* API Functions /*--------------------------------------------------*/ /** * Outputs the content of the widget. * * @args The array of form elements * @instance */ function widget($args, $instance) { extract($args, EXTR_SKIP); echo $before_widget; $twitter_username = empty($instance['twitter_username']) ? '' : apply_filters('twitter_username', $instance['twitter_username']); $facebook_username = empty($instance['facebook_username']) ? '' : apply_filters('facebook_username', $instance['facebook_username']); $google_plus_id = empty($instance['google_plus_id']) ? '' : apply_filters('google_plus_id', $instance['google_plus_id']); // Display the widget include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/widget.php'); echo $after_widget; } // end widget /** * Processes the widget's options to be saved. * * @new_instance The previous instance of values before the update. * @old_instance The new instance of values to be generated via the update. */ function update($new_instance, $old_instance) { $instance = $old_instance; $instance['twitter_username'] = strip_tags(stripslashes($new_instance['twitter_username'])); $instance['facebook_username'] = strip_tags(stripslashes($new_instance['facebook_username'])); $instance['google_plus_id'] = strip_tags(stripslashes($new_instance['google_plus_id'])); return $instance; } // end widget /** * Generates the administration form for the widget. * * @instance The array of keys and values for the widget. */ function form($instance) { $instance = wp_parse_args( (array)$instance, array( 'twitter_username' => '', 'facebook_username' => '', 'google_plus_id' => '' ) ); $twitter_username = strip_tags(stripslashes($new_instance['twitter_username'])); $facebook_username = strip_tags(stripslashes($new_instance['facebook_username'])); $google_plus_id = strip_tags(stripslashes($new_instance['google_plus_id'])); // Display the admin form include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/admin.php'); } // end form /*--------------------------------------------------*/ /* Private Functions /*--------------------------------------------------*/ /** * Initializes constants used for convenience throughout * the plugin. */ private function init_plugin_constants() { if(!defined('PLUGIN_LOCALE')) { define('PLUGIN_LOCALE', 'my-social-network-locale'); } // end if if(!defined('PLUGIN_NAME')) { define('PLUGIN_NAME', 'My Social Networks'); } // end if if(!defined('PLUGIN_SLUG')) { define('PLUGIN_SLUG', 'My-Social-Networks'); } // end if } // end init_plugin_constants /** * Registers and enqueues stylesheets for the administration panel and the * public facing site. */ private function register_scripts_and_styles() { if(is_admin()) { $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.js', true); $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/admin.css'); } else { $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.css', true); $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/widget.css'); } // end if/else } // end register_scripts_and_styles /** * Helper function for registering and enqueueing scripts and styles. * * @name The ID to register with WordPress * @file_path The path to the actual file * @is_script Optional argument for if the incoming file_path is a JavaScript source file. */ private function load_file($name, $file_path, $is_script = false) { $url = WP_PLUGIN_URL . $file_path; $file = WP_PLUGIN_DIR . $file_path; if(file_exists($file)) { if($is_script) { wp_register_script($name, $url); wp_enqueue_script($name); } else { wp_register_style($name, $url); wp_enqueue_style($name); } // end if } // end if } // end load_file } // end class add_action('widgets_init', create_function('', 'register_widget("My_Social_Network");')); ?>
Selanjutnya, mari kita tambahkan beberapa gaya untuk form administrasi. Temukan /css/admin.css dan tambahkan kode berikut:
.wrapper fieldset { border: 1px solid #ddd; width: 90%; padding: 5%; } .option { margin: 12px 0 12px 0; } .option input { width: 100%; }
Dan mari kita menulis markup yang akan merender view dari form administrasi:
<div class="wrapper"> <fieldset> <legend> <?php _e('My Social Networks', PLUGIN_LOCALE); ?> </legend> <div class="option"> <label for="twitter"> <?php _e('Twitter Username', PLUGIN_LOCALE); ?> </label> <input type="text" id="<?php echo $this->get_field_id('twitter_username'); ?>" name="<?php echo $this->get_field_name('twitter_username'); ?>" value="<?php echo $instance['twitter_username']; ?>" class="" /> </div> <div class="option"> <label for="facebook"> <?php _e('Facebook Username', PLUGIN_LOCALE); ?> </label> <input type="text" id="<?php echo $this->get_field_id('facebook_username'); ?>" name="<?php echo $this->get_field_name('facebook_username'); ?>" value="<?php echo $instance['facebook_username']; ?>" class="" /> </div> <div class="option"> <label for="google_plus"> <?php _e('Google+ ID', PLUGIN_LOCALE); ?> </label> <input type="text" id="<?php echo $this->get_field_id('google_plus_id'); ?>" name="<?php echo $this->get_field_name('google_plus_id'); ?>" value="<?php echo $instance['google_plus_id']; ?>" class="" /> </div> </fieldset> </div><!-- /wrapper -->
Akhirnya, kita perlu untuk menulis beberapa markup untuk membuat tampilan public menghadap widget kalau sudah live di blog sebenarnya:
<h3> <?php _e('My Social Networks', PLUGIN_LOCALE); ?> </h3> <ul class="my-social-networks"> <?php if(strlen(trim($twitter_username)) > 0) { ?> <li> <a href="http://twitter.com/<?php echo $twitter_username; ?>"> <?php _e('Twitter', PLUGIN_LOCALE); ?> </a> </li> <?php } // end if ?> <?php if(strlen(trim($facebook_username)) > 0) { ?> <li> <a href="http://facebook.com/<?php echo $facebook_username; ?>"> <?php _e('Facebook', PLUGIN_LOCALE); ?> </a> </li> <?php } // end if ?> <?php if(strlen(trim($google_plus_id)) > 0) { ?> <li> <a href="http://plus.google.com/<?php echo $google_plus_id; ?>"> <?php _e('Google+', PLUGIN_LOCALE); ?> </a> </li> <?php } // end if ?> </ul><!-- /my-social-networks -->
Selesai dan selesai. Tidak buruk, kan? Cukup banyak pekerjaan dan fungsionalitas yang dilakukan relatif cepat.

Anda dapat men-download kode sumber kerja (termasuk README terkait) untuk widget ini pada GitHub atau tepat di sini di Wptuts.
Pada akhirnya, memelihara jumlah proyek perangkat lunak untuk mencoba untuk mengatur kompleksitas. Meskipun boilerplate di atas *bukan * cara mengatur atau mengelola kode, ia memiliki "efektif * cara untuk mengatur kode dan aku telah menemukan sangat berguna dalam banyak proyek-proyek saya dan mudah-mudahan hal ini membantu Anda dalam pekerjaan dimasa depan.
Ingat, Anda dapat mengambil salinan boilerplate dan proyek contoh dari repositori GitHub mereka masing-masing. Saya juga sangat merekomendasikan bookmark WordPress Codex [1]. Itu adalah sumber luar biasa bagi siapa saja yang mencari untuk melakukan pengembangan WordPress lebih lanjut.
Pindah ke bagian dua...
Periksa bagian kedua dari seri ini tutorial yang mana kami akan dapat menggali lebih dalam menciptakan plugin yang dapat dipelihara! Kita akan melihat bagaimana untuk menggunakan hook
dalam WordPress - dan kemudian kami akan benar-benar menempatkan boilerplate kami untuk digunakan membuat plugin lain yang berguna. Siap untuk bagian dua?