Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
1. 10 Things Every Plugin
Developer Should Know
Dave Donaldson
Co-founder
Max Foundry
2. Overview
• Enable Debugging
• Prefix Your Functions
• Enqueue Scripts and Styles
• Your JS/CSS On Your Admin Pages Only
• AJAX in the Admin
• Extensibility Hooks
• Support Multisite
• Internationalization and Localization
• Security
• Helper Functions and Constants
4. Enable Debugging
• Don’t develop without it
• Don’t develop without it
• Don’t develop without it
• Don’t develop without it
• Don’t develop without it
• Don’t develop without it
• Don’t develop without it
5. Enable Debugging
In wp-config.php, comment out this line:
define(‘WP_DEBUG’, false);
And replace with these:
// Turns WP debugging on
define(‘WP_DEBUG’, true);
// Tells WP to log everything to the /wp-content/debug.log file
define(‘WP_DEBUG_LOG’, true);
// Doesn’t force the PHP ‘display_errors’ variable to be on
define(‘WP_DEBUG_DISPLAY’, false);
// Hides the errors from being displayed on-screen
@ini_set(‘display_errors’, 0);
6. Enable Debugging
• Visibility for WP errors and notices
• Notices are important for deprecated
functions
• Becomes part of your cadence
• Watch debug.log
• Use Debug Bar and Blackbox plugins
8. Prefix Your Functions
• All functions get loaded into the same
execution space…
• … which requires each function to be uniquely
named…
• … which means you should prefix your
functions
9. Prefix Your Functions
DO NOT be generic:
// Do you know how many people have
// these *exact* same functions?
function copy_file() {
}
function save_data() {
}
10. Prefix Your Functions
DO this instead:
// Assuming the name of your plugin
// is ‚My Awesome WordPress Plugin‛
function mawp_copy_file() {
}
function mawp_save_data() {
}
11. Prefix Your Functions
Classes are the one caveat:
class MawpCommon {
function copy_file() {
}
function save_data() {
}
}
12. Prefix Your Functions
Classes allow you to do this:
$common = new MawpCommon();
$common->copy_file();
$common->save_data();
14. Enqueue Scripts and Styles
• The WP enqueue functions are the proper way
to include javascript and stylesheets
wp_enqueue_script(‘thickbox’);
wp_enqueue_script(‘path-to-my-script.js’,
array(‘jquery’));
wp_enqueue_style(‘thickbox’);
wp_enqueue_style(‘path-to-my-styles.css’);
16. Your JS/CSS On Your Admin Pages
Only
• Devs adding their javascript and styles to every
admin page, including pages for other plugins, is
a HUGE PITA
• If you are one of these people, I have a bill to
send you
• These are your friends, and in turn, my friend:
– admin_print_scripts-{hookname}
– admin_print_styles-{hookname}
17. Your JS/CSS On Your Admin Pages
Only
add_action(‘admin_menu’, ‘mawp_admin_menu’);
function mawp_admin_menu() {
$admin_pages = array();
$admin_pages[] = add_submenu_page();
$admin_pages[] = add_submenu_page();
foreach ($admin_pages as $admin_page) {
add_action(‚admin_print_scripts-{$admin_page}‛, ‘mawp_admin_scripts’);
add_action(‚admin_print_styles-{$admin_page}‛, ‘mawp_admin_styles’);
}
}
function mawp_admin_scripts() {
wp_enqueue_script();
}
function mawp_admin_styles() {
wp_enqueue_style();
}
19. AJAX in the Admin
• Very useful for creating an improved user
experience
• Consists of the following:
– A nonce
– A little jQuery
– The wp_ajax hook
20. AJAX in the Admin
A nonce:
<form id=‚mawp_form‛ method=‚post‛>
<?php wp_nonce_field(‚mawp_nonce_action‛, ‚mawp_nonce_name‛) ?>
</form>
21. AJAX in the Admin
A little jQuery:
<script type=‚text/javascript‛>
jQuery(document).ready(function() {
jQuery(‚#some_button‛).click(function() {
var form_data = jQuery(‚#mawp_form‛).serialize();
form_data += ‚&action=mawp_do_stuff‛;
jQuery.ajax({
type: ‚POST‛,
url: ‚<?php echo admin_url(‘admin-ajax.php’) ?>‛,
data: form_data,
success: function(message) {
// Display the message
}
});
});
});
</script>
22. AJAX in the Admin
The wp_ajax hook:
add_action(‘wp_ajax_mawp_do_stuff’, ‘mawp_do_stuff’);
function mawp_do_stuff() {
if (isset($_POST)) {
if (check_admin_referer(‘mawp_nonce_action’, ‘mawp_nonce_name’)) {
// Do some stuff
$message = ‘Han shot first’;
echo $message;
die();
}
}
}
24. Extensibility Hooks
• Allows other devs to extend your plugin
• A plugin with plugins is a mini-ecosystem
• Actions and filters
– Actions: used for executing functions
– Filters: used for manipulating data
25. Extensibility Hooks
• Actions
– do_action()
• Creates hookable location for custom actions
– add_action()
• Attaches a function to a hook created with do_action()
– has_action()
• Checks if an action has been created with do_action()
– remove_action()
• Removes an action that was created with do_action()
26. Extensibility Hooks
• Filters
– apply_filters()
• Creates hookable location for custom filters
– add_filter()
• Attaches a filter to hook created with apply_filters()
– has_filter()
• Checks if a filter has been created with apply_filters()
– remove_filter()
• Removes a filter that was created with apply_filters()
27. Extensibility Hooks
Action example:
function mawp_do_stuff() {
do_action(‘mawp_do_stuff_before’);
// Logic for doing stuff goes here
do_action(‘mawp_do_stuff_after’);
}
add_action(‘mawp_do_stuff_before’, ‘your_before_action’);
function your_before_action() {
// Do stuff at the beginning of mawp_do_stuff
}
add_action(‘mawp_do_stuff_after’, ‘your_after_action’);
function your_after_action() {
// Do stuff at the end of mawp_do_stuff
}
33. Support Multisite
function mawp_call_function_for_each_site($function) {
global $wpdb;
// Hold this so we can switch back to it
$current_blog = $wpdb->blogid;
// Get all blogs in the network and invoke function for each one
$sql = ‚SELECT blog_id FROM $wpdb->blogs‛;
$blog_ids = $wpdb->get_col($wpdb->prepare($sql));
foreach ($blog_ids as $blog_id) {
switch_to_blog($blog_id);
call_user_func($function);
}
// Now switch back to the root blog
switch_to_blog($current_blog);
}
35. Internationalization and
Localization
• i18n: Internationalization
• l10n: Localization
• What’s the difference?
– i18n: Changing software so it’s not hardwired to a
single language/culture/locale
– l10n: Adding resources to the software so that a
particular language/culture/locale is supported
36. Internationalization and
Localization
• Don’t blindly discount non-English speaking
cultures
• Europe is a huge market
• Some people won’t buy if not in their
language
• IT’S TOO EASY NOT TO DO FROM THE
BEGINNING!
37. Internationalization and
Localization
• 4 basic functions:
__(): Makes a string translatable
_e(): Echoes translatable string
_n(): For plural translations
_x(): Provides translation context
• Must type out the text domain, cannot store it
as a variable
38. Internationalization and
Localization
add_action(‘init’, ‘mawp_load_textdomain’);
function mawp_load_textdomain() {
$languages_folder = dirname(plugin_basename(__FILE__));
$languages_folder .= ‘/languages/’;
// 1st param is the text domain and must be unique, so best
// practice is to name it the same as your plugin folder. The
// 2nd param corresponds to a deprecated function, so you can
// always set it to false.
// IMPORTANT: text domain CANNOT include underscores!
load_plugin_textdomain(‘mawp’, false, $languages_folder);
}
39. Internationalization and
Localization
// Using __()
$fact = __(‘Han shot first.’, ‘mawp’);
// Using _e()
_e(‘Han shot first.’, ‘mawp’);
// Using _n()
printf(_n(‘Saved %d item.’, ‘Saved %d items.’, $count, ‘mawp’), $count);
// Using _x()
echo _x(‘Comment’, ‘column name’, ‘mawp’);
40. Internationalization and
Localization
• Create the POT and MO files
• These are the files that translators need
• Generated by various tools
– Poedit
42. Security
• Many WordPress vulnerabilities don’t come
from the core
• Data can’t be trusted
• General rule: validate input, escape output
• WP has many functions to help you
43. Security
• For protecting against XSS attacks:
esc_url()
esc_url_raw()
esc_js()
esc_html()
esc_attr()
esc_textarea()
44. Security
• For protecting against SQL injection attacks:
$wpdb->prepare()
$wpdb->insert()
$wpdb->update()
$wpdb->escape()
esc_sql()
45. Security
• For sanitizing data input:
sanitize_email()
sanitize_file_name()
sanitize_user()
sanitize_text_field()
sanitize_html_class()
sanitize_key()
sanitize_option()
46. Security
• You don’t want to be the next TimThumb
• Big topic, lots to know
• Tomorrow: “Secure All The Things!”, Dougal
Campbell
48. Helper Functions and Constants
• Useful for finding plugin and content folders
• Folder locations in WP can be changed
• Try to avoid hardcoded locations