Moving very fast, just glimpses of how you can do things, see these slides and full-length version at rrn/slides
Every site is different and has different needs
Themes do this too - lots of themes have functionality built in -- this is bad (if you ever think you might maybe want to change themes). Move your site's functions.php into a plugin, so when you change themes, you don't loose it.
<?php
/*
Plugin Name: Name Of The Plugin
Plugin URI: http://URI_Of_Page_Describing_Plugin
Description: A brief description of the Plugin.
Version: The Plugin's Version Number, e.g.: 1.0
Author: Name Of The Plugin Author
Author URI: http://URI_Of_The_Plugin_Author
License: A "Slug" license name e.g. GPL2
*/
function something(){
...
?>
Populates the plugin listing in admin
Only the name is required to show up in the listing, but description and version are useful.
Stop for questions?
Might be difficult at first, but you should be able to read through your plugin and know what it's doing.
Look at the WP coding standards, if you're new to writing code. (or in general)
Anything you create to be used by WP should be unique
Avoid collisions by two plugins with the function 'install' -- Using classes also works.
check while you're writing code that you're not causing errors left & right, much easier to do as you go than after everything's done. This will show errors with any plugin on your site, so if others are throwing errors deactivate them
/**
* This will log all errors notices and warnings to a file called
* debug.log in wp-content only when WP_DEBUG is true
*/
define('WP_DEBUG', true); // false
if (WP_DEBUG) {
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
@ini_set('display_errors',0);
}
/wp-content/plugins/
/wp-content/mu-plugins/
instantly activated, no update notifications, not in plugins list
/wp-content/
replaces default WP functionality - use a custom DB class, or a custom maintenance message
We're covering normal plugins, but it's good to know that these exist.
Stop for questions?
home_url()
: Site address (URL)
site_url()
: WordPress address (URL)
plugins_url('style.css',__FILE__)
: URL to other files inside your plugin folder
dirname(__FILE__)
: Absolute path to this file
Don't assume default directory structure.
People can (and do) change where wp-content is, rename it, etc
Good to start with, because you can later add a widget that just executes this function - you don't have to mess with any other WP APIs
If you wanted to display an image (like your logo) anywhere, you could create the template tag
<?php
/*
Plugin Name: Show My Logo
Description: A template tag to show my logo wherever I want.
*/
function show_my_logo(){
$logo_path = get_stylesheet_directory_uri() . "/image.png";
echo "<img src='$logo_path' class='my-logo'/>";
}
?>
That's a plugin. Looks for image.png in the theme directory, and prints it. If you're at all intimidated by making a plugin, don't be - they're not all complicated monsters, and they're generally better if they're not.
Use it anywhere, like you do with the_title()
, etc. Anywhere you put it, it will output your logo.
<?php
if ( function_exists('show_my_logo') )
show_my_logo();
?>
Wrap it in function_exists(), so that if you disable the plugin it doesn't break your theme.
A hook is a part of WordPress that you can connect your plugin to. When the hook is activated, it will run whatever has been connected to it.
the_title
, the_content
, the_excerpt
...capital_P_dangit
: This function hooks into the the_title
, the_content
, & comment_text
filter hooks, looks for any instance of 'Wordpress' and changes it to 'WordPress'.
The actions that run (and the order they run in) is determined by the page requested (admin pages run different actions than non-admin pages). When run, the action will run whatever has been hooked into it.
for a useful example, I'm actually grabbing someone else's example.
Adding a new color scheme to Twenty Eleven (from theme.fm's How to Child Theme Twenty Eleven)
<?php
function twentyeleven_color_schemes_orange( $color_schemes ) {
$color_schemes['orange'] = array(
'value' => 'orange',
'label' => __( 'Orange', 'twentyeleven' ),
'thumbnail' => get_stylesheet_directory_uri() . '/orange.png',
'default_link_color' => '#FFA500',
);
return $color_schemes;
} add_filter( 'twentyeleven_color_schemes', 'twentyeleven_color_schemes_orange' );
?>
add_filter takes the filter hook you want to use, and then the function you want to run as arguments.
Both this and add_action also have priority and arguments parameters - default priority is 10: a priority 5 filter will run before a priority 12. If you wanted to make another function that overwrites this orange value, give it a higher priority and it will run after (therefore overwriting the value). Arguments is the number of arguments given in the hook & expected by the function -- they should match.
do_action( 'your_action', $arg1, $arg2 )
apply_filters( 'your_filter', $arg1)
Can be used like any other hooks now:
add_action('your_action', 'a_function', 10, 2);
Will call a_function($arg1,$arg2)
wherever you put the do_action
, at priority 10 (normal).
Adding your own hooks makes your plugin easily customized by others, just like WP itself. Can have multiple arguments, just need to match with function & add_action
Stop for questions
We're pretending that the show my logo function had a parameter $large just to show using attributes. The $content var gets what is between the shortcode tags
function showlogo_shortcode_handler($atts, $content=null, $code="") {
$a = shortcode_atts( array(
'large' => false
), $atts );
show_my_logo($a['large']);
} add_shortcode('show-my-logo', 'showlogo_shortcode_handler');
Gives us the shortcode [show-my-logo] with (optional) attribute 'large' (defaults to false).
[show-my-logo large=true]
[show-my-logo]
Won't break a site if the plugin gets disabled (like a function call (without if function_exists) would), but it will display the shortcode on the site.
constructor
: information for the widget listing (name, description)widget
: what should output where the widget is placedupdate
: update the widget settings, make sure they're set as expectedform
: widget screen formThere's also a cheating way of doing this involving shortcodes, look it up if you're interested.
Questions?
Saving settings, user input, etc
add_option
uses the pre-existing wp_options
table to store your data.
Each option you add creates a new row in the database, so best practice is to only use one 'option' per plugin, and store your data as an array.
You can store arrays in option-rows, allowing you to still store as much information as you need. WP will automatically serialize them
add_post_meta($post_id, 'co_author', 'John Smith', true);
//post id, meta key, meta value, unique
update_post_meta($post_id, 'co_author', 'John Smith');
//post id, meta key, new value, [optional value to change if the key is not unique]
$co_author = get_post_meta($post_id, 'co_author', true);
//post id, meta key, [optional 'single']
This is best for information closely associated with posts. You'll need to know the post ID, but once you do, you can just use add_post_meta
or update_post_meta
. This adds a custom field to the post. If your key starts with '_', such as _count
, it shouldn't be shown to users. Otherwise, it will display in the 'custom fields' section. update automatically adds if the key doesn't exist, add will only add it if it's not there (or if it's not unique). In get_post_meta, if you leave out single it will return an array, even if you only have one value. If you have multiple values and set single to true, it will grab the first.
If you have information that requires a new table, WP has a class ($wpdb
) that abstracts the database. Even with this abstraction, you still need to know MySQL syntax to create/update the table correctly.
If you do feel comfortable enough to do this, there is a page on the codex which will help: http://codex.wordpress.org/Creating_Tables_with_Plugins.
Definitely out of the scope of this talk, but for awareness - if you need to create a new table, use the class abstraction.
Questions?
register_deactivation_hook(__FILE__,'my_p_deactivate');
function my_p_deactivate(){
// undo any changes you made to WP
// but don't delete data!
}
You can allow for translations of your plugin text by adding a domain and outputting your strings with __('your string', 'myp_domain')
or _e('your string','myp_domain')
function my_p_add_domain(){
load_plugin_textdomain( 'myp_domain', false,
dirname(plugin_basename( __FILE__ )) . '/translations/'
);
} add_action('init','my_p_add_domain');
your plugin's domain string, a deprecated var, and then the location to the .mo files
plugin_basename gets the directory after plugins/, so your plugin folder & filename
Are good things to do, look up on codex if running out of time
You can validate/sanitize your data before it goes into the database by using register_setting
.
register_setting( 'my_p_options_group', 'my_p_int_option', 'intval') );
register_setting( 'my_p_options_group', 'my_p_options', 'my_p_validate') );
function my_p_validate( $input ){
$input['text'] = wp_filter_nohtml_kses($input['text']);
$input['an_int'] = intval($input['an_int']);
$input['a_bool'] = ( $input['a_bool'] == 1 ? 1 : 0 );
return $input;
}