Here is where you will define your own admin sub page
8 |
9 |
--------------------------------------------------------------------------------
/scripts/script.js:
--------------------------------------------------------------------------------
1 | jQuery(document).ready(function($) {
2 | // $() will work as an alias for jQuery() inside of this function
3 | });
4 |
5 | (function($) {
6 | // Place your javascript in here
7 |
8 | // This is a self executing anonymous function which will keep your scripts from using up
9 | // names in the global name space, and will prevent collisions with other scripts.
10 |
11 | // $() will work as an alias for jQuery() inside of this function
12 | })(jQuery);
13 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This is a boilerplate of a WordPress plugin which contains a number of different things that your plugin might want to implement, like localization, adding scripts and styles, custom post types, custom taxonomies and shortcodes.
2 |
3 | The ambition of this plugin is to be a set of best practices on how to solve common tasks when writing a plugin for WordPress, your input and suggestions are welcome.
4 |
5 | Usage instructions:
6 |
7 | 1. Search for @todo in the file and change the names and stuff so that your plugin will be unique.
8 | 2. In the __construct( ) function; uncomment the different types of functionality that you need.
9 | 2a. (optional) If needed, uncomment the register_activation_hook( ) call
10 | 2b. (optional) If needed, uncomment the call to install_db( ) from the install( ) function and define your tables
11 | 3. Be a good open source developer; post bug reports, fixes, suggestions, ideas on better ways to handle stuff in the plugin.
12 |
13 | Thanks!
14 |
15 | @emomilol
16 | @mikaeljorhult
17 | @rickard2
18 |
--------------------------------------------------------------------------------
/widgets/my-widget.php:
--------------------------------------------------------------------------------
1 | __("Plugin boilerplate description", $this->plugin_name));
13 | parent::WP_Widget(false, __('Plugin boilerplate', $this->plugin_name), $options);
14 | }
15 |
16 | /**
17 | * Logic for handling updates from the widget form
18 | * @param array $new_instance
19 | * @param array $old_instance
20 | * @return array
21 | */
22 | function update($new_instance, $old_instance) {
23 | // Insert update logic here, and check that all the values in $new_instance are valid for your particular widget
24 |
25 | return $new_instance;
26 | }
27 |
28 | /**
29 | * Function for handling the widget control in admin panel
30 | * @param array $instance An array of current values for this instance
31 | * @return void
32 | */
33 | function form($instance) {
34 | // Get stored preferences, remember to escape them!
35 | $title = strlen($instance['title']) > 0 ? esc_attr($instance['title']) : esc_attr($this->default_title);
36 |
37 | ?>
38 |
39 |
40 | 0 ? $title : $this->default_title;
59 |
60 | echo $before_widget;
61 | echo $before_title . $title . $after_title;
62 |
63 | // Insert your widget markup here
64 |
65 | echo $after_widget;
66 | }
67 | }
68 |
69 | // register Widget
70 | // @todo rename to your widgets name
71 | function plugin_boilerplate_widget_register() {
72 | register_widget( 'plugin_boilerplate_widget' );
73 | }
74 |
75 | // @todo rename to the function name 3 lines above
76 | add_action( 'widgets_init', 'plugin_boilerplate_widget_register' );
--------------------------------------------------------------------------------
/plugin-boilerplate.php:
--------------------------------------------------------------------------------
1 |
33 | * @todo Add your name here
34 | * @todo Change class name to something more appropriate
35 | */
36 | class WP_Plugin_Boilerplate {
37 | /**
38 | * This value will be used for
39 | * - the gettext text domain
40 | * - the sub-folder when adding scripts and styles
41 | * - the handle for scripts and styles
42 | * Please make sure that this value corresponds to the folder name where your plugin resides.
43 | * @var string
44 | * @todo Change this value to your plugin name
45 | */
46 | private $plugin_name = "plugin_boilerplate";
47 |
48 | /**
49 | * The constructor is executed when the class is instatiated and the plugin gets loaded.
50 | */
51 | function __construct() {
52 | // Uncomment any of these calls to add the functionality that you need.
53 |
54 | //add_action('init', array($this, 'init_custom_post_types'), 20);
55 | //add_action('init', array($this, 'init_localization'), 20);
56 | //add_action('init', array($this, 'init_scripts'), 20);
57 | //add_action('init', array($this, 'init_styles'), 20);
58 | //add_action('init', array($this, 'init_shortcodes'), 20);
59 | //add_action('admin_menu', array($this,'init_admin_menu'));
60 | }
61 |
62 | /**
63 | * This function is executed when the plugin is activated. To activate it just uncomment
64 | * the line at the bottom of this file with the register_activation_hook( ... ) function
65 | * @return void
66 | */
67 | static function install() {
68 | // Uncomment this if you need database tables.
69 | //self::install_db();
70 |
71 | // Perform your activation tasks in here.
72 | }
73 |
74 | /**
75 | * This function is executed from install( ) and is used if you need database tables.
76 | * @return void
77 | */
78 | static function install_db() {
79 | global $wpdb;
80 |
81 | /**
82 | * This value represent the current version of the layout of the database tables. This value
83 | * needs to be increased every time you change something in your database layout.
84 | * @var integer
85 | */
86 | $db_version = 1;
87 |
88 | /**
89 | * To create tables, dbDelta from wp-admin/includes/upgrade.php is needed
90 | */
91 | require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
92 |
93 | /**
94 | * @todo Change myplugin to your plugin name
95 | */
96 | $option_name = 'myplugin-db-version';
97 | $current_version = null;
98 | $current_version = get_option($option_name);
99 |
100 | // Check if the latest version is already installed
101 | if($current_version == $db_version) {
102 | return;
103 | }
104 |
105 | // In this example two tables is defined, 'table1' and 'table2'. This example tries
106 | // to illustrate how the tables gets upgraded. The layout of the tables is currently at
107 | // version three and two upgrade routines are defined for upgrading the tables from the
108 | // first and second version. Note that the changes in the database layout needs to be added
109 | // to the $structure[ ] array _and_ to the $upgrade[ ] array. $structure[ ] is used when the
110 | // plugin is installed on a new system and $upgrade[ ] is used for upgrading.
111 |
112 | // Define tables
113 | $tables = array('table1', 'table2');
114 | $structure = array(
115 |
116 | // Definition for 'table1'
117 | "(`id` int(11) unsigned NOT NULL auto_increment,
118 | `field1` varchar(255) NOT NULL,
119 | `field2` varchar(255) NOT NULL,
120 | `field3` varchar(255) default NULL,
121 | `field4` tinyint(3) unsigned NOT NULL default '0',
122 | `field5` timestamp NOT NULL default CURRENT_TIMESTAMP,
123 | PRIMARY KEY (`id`) )",
124 |
125 | // Definition for 'table2'
126 | "(`id` int(11) unsigned NOT NULL auto_increment,
127 | `field1` varchar(255) NOT NULL,
128 | `field2` varchar(255) NOT NULL,
129 | `field3` varchar(255) NOT NULL,
130 | PRIMARY KEY(`id`) )"
131 | );
132 | $upgrade = array();
133 |
134 | // Routines for upgrading, the structure is
135 | // $upgrade[ from db version ][ table name ]
136 | // Routine should include %s for table prefix.
137 | // Upgrade routines are applied in order from current version to the newer version. Routines for upgrading
138 | // only has to be defined once.
139 |
140 | // Example of an upgrade routine which will add two fields to table1 when the plugin gets upgraded from
141 | // DB version 1 to a later version.
142 | $upgrade[1] = array("table1" => "ALTER TABLE %stable1 ADD `field3` varchar(255) default NULL, ADD `field4` tinyint(3) unsigned NOT NULL default '0'");
143 |
144 | // Example of an upgrade routine which will add one field to table1 and one field to table2 when the plugin
145 | // gets upgraded from DB version 2 to a later version.
146 | $upgrade[2] = array("table1" => "ALTER TABLE %stable1 ADD `field5` timestamp NOT NULL default CURRENT_TIMESTAMP", "table2" => "ALTER TABLE %stable2 ADD `field3` varchar(255) NOT NULL" );
147 |
148 | // Iterate tables and create them
149 | foreach ($tables as $key => $table) {
150 | if($wpdb->get_var(sprintf("SHOW TABLES LIKE '%s%s'", $wpdb->prefix, $table)) != $wpdb->prefix . $table) {
151 | // Table doesn't exist, create it.
152 |
153 | $sql = sprintf("CREATE TABLE %s%s %s DEFAULT CHARSET=utf8", $wpdb->prefix, $table, $structure[$key]);
154 | dbDelta($sql);
155 | } else {
156 | // Table exists, check if there's any upgrade routines defined.
157 | // The upgrade routines are applied in order from previous to current version
158 |
159 | for ($i = $current_version; $i < $db_version; $i++) {
160 | if (strlen($upgrade[ $i ][ $table ]) > 0) {
161 | $sql = sprintf($upgrade[ $i ][ $table ], $wpdb->prefix);
162 | $wpdb->query($sql);
163 | }
164 | }
165 | }
166 | }
167 |
168 | if ($current_version === false) {
169 | add_option($option_name, $db_version);
170 | } else {
171 | update_option($option_name, $db_version);
172 | }
173 | }
174 |
175 | /**
176 | * Loading the gettext textdomain first from the WP languages directory,
177 | * and if that fails try the subfolder /languages/ in the plugin directory.
178 | * @return void
179 | */
180 | function init_localization() {
181 | if(!load_plugin_textdomain($this->plugin_name, '/wp-content/languages/')) {
182 | load_plugin_textdomain($this->plugin_name, '/wp-content/plugins/' . $this->plugin_name . '/languages/');
183 | }
184 | }
185 |
186 | /**
187 | * Loading the javascripts, first using jquery using the CDN and then the file
188 | * /scripts/script.js from the plugin directory. By default the script is enqueued
189 | * in the page footer for faster page loading.
190 | * @return void
191 | */
192 | function init_scripts() {
193 | // Only enqueue scripts on frontend.
194 | if(!is_admin()) {
195 | // Only enqueue the script if it actually exists.
196 | if(file_exists(dirname(__FILE__) . '/scripts/script.js')) {
197 | if(function_exists('plugins_url')) {
198 | wp_enqueue_script($this->plugin_name . '-script', plugins_url('/scripts/script.js', __FILE__), array('jquery'), '1.0', true);
199 | } else {
200 | wp_enqueue_script($this->plugin_name . '-script', WP_PLUGIN_URL . '/' . $this->plugin_name . '/scripts/script.js', array('jquery'), '1.0', true);
201 | }
202 | }
203 | }
204 | }
205 |
206 | /**
207 | * Loading the stylesheet for this plugin.
208 | * @return void
209 | */
210 | function init_styles() {
211 | // Only enqueue styles on frontend and if the stylesheet actually exists.
212 | if(!is_admin() && file_exists(dirname(__FILE__) . '/styles/style.css')) {
213 | if(function_exists('plugins_url')) {
214 | wp_enqueue_style($this->plugin_name . '-stylesheet', plugins_url('/styles/style.css', __FILE__), array(), '1.0', 'all');
215 | } else {
216 | wp_enqueue_style($this->plugin_name . '-stylesheet', WP_PLUGIN_URL . '/' . $this->plugin_name . '/styles/styles.css', array(), '1.0', 'all');
217 | }
218 | }
219 | }
220 |
221 | /**
222 | * Add a shortcode for this plugin. It's recommended to change the code
223 | * to prevent from collisions. (The second value in the array)
224 | * @return void
225 | */
226 | function init_shortcodes() {
227 | add_shortcode('shortcode', array($this, 'plugin_boilerplate_shortcode'));
228 | }
229 |
230 | /**
231 | * This function will be executed when the plugin shortcode is used in a page
232 | * or post. This is where you put the code to be executed
233 | * @param array $atts
234 | * @param string $contents
235 | * @return string
236 | */
237 | function plugin_boilerplate_shortcode($atts, $contents = '') {
238 | // Extracting all the values sent as arguments with this shortcode
239 | extract(shortcode_atts(array(
240 | 'attribute' => 'default',
241 | ), $atts));
242 |
243 | // It's recommended to use output buffering to catch the contents and then return it.
244 | ob_start();
245 |
246 | // Perform the tasks of this function in here, and echo everything that you want to
247 | // output to the browser.
248 |
249 | // Fetch the output that you just echoed, and put it into the $content variable.
250 | $content = ob_get_clean();
251 |
252 | // Remember to always RETURN the content from the shortcode function, otherwise
253 | // the result won't be placed in the correct part of the page.
254 | return $content;
255 | }
256 |
257 | /**
258 | * Loading custom post types and taxonomies for this plugin.
259 | * @return void
260 | */
261 | function init_custom_post_types() {
262 | // Register post_type as custom post type with post_type taxonomy as a taxonomy
263 | register_post_type('post_type', array(
264 | 'labels' => array(
265 | 'name' => __('Post Types', 'plugin-boilerplate'),
266 | 'singular_name' => 'Post type',
267 | 'add_new' => 'Add new',
268 | 'add_new_item' => 'Add new post type',
269 | 'edit_item' => 'Edit post type',
270 | 'new_item' => 'New post type',
271 | 'view_item' => 'Show post type',
272 | 'search_items' => 'Search post type',
273 | 'not_found' => 'Not found',
274 | 'not_found_in_trash' => 'No post type was found in trash',
275 | 'parent_item_colon' => 'Parent:'
276 | ),
277 | 'public' => true,
278 | 'exclude_from_search' => true,
279 | 'query_var' => true,
280 | 'rewrite' => true,
281 | 'capability_type' => 'post',
282 | 'hierarchical' => false,
283 | 'show_in_nav_menus' => false,
284 | 'menu_position' => null,
285 | 'supports' => array('title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments')
286 | ));
287 |
288 | register_taxonomy('post_type_taxonomy', 'taxonomy', array(
289 | 'hierarchical' => true,
290 | 'labels' => array(
291 | 'name' => 'Taxonomies',
292 | 'singular_name' => 'Taxonomy',
293 | 'search_items' => 'Search taxonomy',
294 | 'all_items' => 'All taxonomies',
295 | 'parent_item' => 'Parent taxonomy',
296 | 'parent_item_colon' => 'Parent taxonoy:',
297 | 'edit_item' => 'Edit taxonomy',
298 | 'update_item' => 'Update taxonomy',
299 | 'add_new_item' => 'Add new taxonomy',
300 | 'new_item_name' => 'Taxonomy name',
301 | 'menu_name' => 'Taxonomies',
302 | ),
303 | 'show_ui' => true,
304 | 'query_var' => true,
305 | 'rewrite' => array('slug' => 'taxonomy')
306 | ));
307 | }
308 |
309 | /**
310 | * Adds a new menu with the name "My Admin Menu" and let's anyone that
311 | * can publish posts be able to use it.
312 | * @return void
313 | */
314 | function init_admin_menu() {
315 | // Add the menu page
316 | add_menu_page('Plugin Boilerplate Admin Menu', 'BP menu', 'publish_posts', $this->plugin_name . '-admin-menu', array($this,'main_menu_page'));
317 |
318 | // Also let's add a submenu
319 | add_submenu_page($this->plugin_name . '-admin-menu', 'Plugin Boilerplate Sub-Menu', 'BP submenu', 'publish_posts', $this->plugin_name . '-admin-submenu', array($this, 'sub_menu_page'));
320 | }
321 |
322 | /**
323 | * This function will be executed when the admin page is to be loaded
324 | * @return void
325 | */
326 | function main_menu_page() {
327 | // Include the HTML from a separate file to keep the plugin class clean
328 | require "pages/admin_main.php";
329 | }
330 |
331 | /**
332 | * This function will be executed when the admin sub page is to be loaded
333 | * @return void
334 | */
335 | function sub_menu_page() {
336 | // Include the HTML from a separate file to keep the plugin class clean
337 | require "pages/admin_options_page.php";
338 | }
339 | }
340 |
341 | /**
342 | * Register the plugin
343 | * @todo Change 'Plugin_Boilerplate' in the anonymous function to the name of the class
344 | */
345 | add_action("init", create_function('', 'new WP_Plugin_Boilerplate();'));
346 |
347 |
348 | // Uncomment this if you need an install routine, remember to change the class name.
349 | //register_activation_hook(__FILE__, array('WP_Plugin_Boilerplate', 'install'));
350 |
351 | // Ending PHP tag is not needed, it will only increase the risk of white space
352 | // being sent to the browser before any HTTP headers.
--------------------------------------------------------------------------------