• About Us
    • New York
  • Work
  • Capabilities
  • Careers
  • Technology
  • Blog
  • Contact Us
  • About Us
    • New York
  • Work
  • Capabilities
  • Careers
  • Technology
  • Blog
  • Contact Us
June 25, 2012

WordPress Plugin Design Patterns

Posted by Christopher Davis

With several publically released plugins under my belt and just as many custom themes and plugins for clients, I’ve found several distinct patterns emerge in my Plugins and themes. This post is so I can share them with you.

Plugin Directory Structure

your-plugin/

your-plugin.php

readme.txt

inc/

another-file.php

js/

a-script.js

css/

admin-style.css

images/

button.jpg

lang/

your-textdomain.pot

es_ES.po

es_ES.mo

Every plugin should be in its own folder. The only two files that should be in this root directory are your main plugin file and a readme. The inc folder should contain all your other PHP files. The js, css and images folders are for JavaScript, CSS and image files respectively. Finally the lang directory should contain your pot file and any po/mo files for internationalization.

Use a Base Class & OOP

The biggest issue I see with many plugins is the use of magic values – eg. strings or other data types that have special meaning. A great example: a settings name. Using a base class, provides a convenient way around this. You can define a base class that has several class constants with those magic strings and use that as a parent for other classes in your plugin.


<?php

class Your_Plugin_Base

{

const SETTING = ‘yourplugin_settings’;

// more stuff here

}

// elsewhere you in your plugin

class Your_Plugin_Front extends Your_Plugin_Base

{

public static function do_stuff()

{

$opts = get_option(self::SETTING);

// do stuff with $opts

}

}

// you can access the constants directly

$opts = get_option(Your_Plugin_Base::SETTING);

Alternatively, you can use this class as a sort-of namespace and fill it with functionality you’ll use throughout your plugin.

A final note on using Classes/OOP in your plugin: use static functions for hooks. This makes it easier for other developers to unhook your functions if necessary. I tend to use the get_class function to add hooks:


<?php

// example from SEO Auto Linker

class SEO_Auto_Linker_Post_Type extends SEO_Auto_Linker_Base

{

/*

* Nonce action

*/

const NONCE = ‘seoal_post_nonce’;

/*

* Sets up all the actions and filters

*

* @uses add_action

* @uses add_filter

* @since 0.7

*/

public static function init()

{

// register post type

add_action(

‘init’,

array(get_class(), ‘register’)

);

}

// snip

public static function register()

{

$labels = array(

‘name’              => __(‘Automatic Links’, ‘seoal’),

‘singular_name’     => __(‘Automatic Link’, ‘seoal’),

‘add_new’           => __(‘Add New Link’, ‘seoal’),

‘all_items’         => __(‘All Links’, ‘seoal’),

‘add_new_item’      => __(‘Add New Link’, ‘seoal’),

‘edit_item’         => __(‘Edit Link’,’seoal’),

‘new_item’          => __(‘New Link’, ‘seoal’),

‘search_items’      => __(‘Search Links’, ‘seoal’),

‘not_found’         => __(‘No Links Found’, ‘seoal’),

‘not_found_in_trash’ => __(‘No Links in the Trash’, ‘seoal’),

‘menu_name’         => __(‘SEO Auto Linker’, ‘seoal’)

);

$args = array(

‘label’         => __(‘Automatic Links’, ‘seoal’),

‘labels’        => $labels,

‘description’   => __(‘A container for SEO Auto Linker’, ‘seoal’),

‘public’        => false,

‘show_ui’       => true,

‘show_in_menu’  => true,

‘menu_position’ => 110,

‘supports’      => array(‘title’)

);

register_post_type(

self::POST_TYPE,

$args

);

}

// snip

} // end class

SEO_Auto_Linker_Post_Type::init();

Translate All the Strings

Always Translate Strings

Got a string that’s going to be exposed the user in some way?  Make sure it gets run through one of WordPress‘ numerous internationalization functions. Do this even if you don’t plan on releasing the plugin/theme. Many times you code can be repurposed for other clients/gigs/whatever – making sure its internationalized can potentially save you a lot of time down the road.

Also don’t forget to load your plugin’s text domain:


<?php // example from SEO Auto Linker

add_action(‘init’, ‘seoal_load_textdomain’);

function seoal_load_textdomain()

{

load_plugin_textdomain(

‘seoal’,

false,

dirname(plugin_basename(__FILE__)) . ‘/lang/’

);

}

Define a Few Constants

Chances are you’re going to need a few things throughout your plugin:

  • The URI of your plugin’s directory – very useful for enqueueing scripts and styles
  • The full path of your plugin’s directory – useful for includes
  • Your plugins basename (optional) – used in a few filters, such as the “plugin action links”

I usually define these constants outside of my base class. WordPress has a few functions you should use to get these values as well.


<?php

// plugin example

define(‘YOURPLUGIN_PATH’, plugin_dir_path(__FILE__));

define(‘YOURPLUGIN_URL’, plugin_dir_url(__FILE__));

define(‘YOURPLUGIN_NAME’, plugin_basename(__FILE__));

// theme example

define(‘YOURTHEME_PATH’, trailingslashit(get_template_directory()));

define(‘YOURTHEME_URL’, trailingslashit(get_template_directory_uri()));

// use these constants to enqueue scripts/styles and such

add_action(‘wp_enqueue_scripts’, ‘yourplugin_enqueue’);

function yourplugin_enqueue() {

wp_enqueue_script(

‘myscript’,

YOURPLUGIN_URL . ‘js/myscript.js’,

array(),

);

});

// or to include files

require_once(YOURPLUGIN_PATH . ‘inc/some-file.php’);

Separate your Code

At the very least, separate admin and front end components where it make sense to do so. Then in your main plugin file, you can conditionally include the file.


if(is_admin())

{

require_once(YOURPLUGIN_PATH . ‘inc/admin.php’);

}

else

{

require_once(YOURPLUGIN_PATH . ‘inc/front.php’);

}

You could also split up your plugins functionality across multiple files and only include files when a feature is enabled. That senario isn’t feasible for single serving plugins.

Document as You Go

Include inline documentation in your code; use whatever format you see fit. If the function is hooked is hooked into something, mention what hooks is used. This is for you as the developer – it helps a lot when you have to go back and read your own code later. It also makes it easier for people to jump in and contribute to your plugin if it happens to be publicly released.


<?php

/**

* Hooked into ‘wp_enqueue_scripts’, adds the plugins scripts and styles for

* the front end

*

* @since 1.0

* @uses wp_enqueue_script

* @return null

*/

function yourplugin_enqueue() {

wp_enqueue_script(

‘myscript’,

YOURPLUGIN_URL . ‘js/myscript.js’,

array(),

);

});

devDevelopmentwordpresswordpress plugin
Previous
Next

Latest White Papers

  • Shifting Plans for 2020 & Beyond
  • Game On: How Brands Can Log Into A Diverse Multi-Billion Dollar Industry
  • What CCPA Means For Brands
  • How Google is Improving Consumer Data Privacy
  • Ways to Prepare for the Cookieless Future
  • See all White Papers

Featured Posts

  • Ad Age Names PMG #1 Best Place to Work in 2021
  • Hindsight 2020 & Looking Ahead to 2021
  • Preparing for Streaming’s Growth & The Future of TV Buying
  • MediaPost Names PMG Independent Agency of the Year
  • PMG Client Portfolio Trends During Amazon Prime Day 2020

Categories

  • Consumer Insights
  • Content
  • Creative Design
  • Data Analytics
  • Development
  • Digital TV & Video
  • Ecommerce
  • Industry News
  • Local
  • Mobile
  • Paid Search
  • PMG Culture
  • Programmatic & Display
  • SEO
  • Social Media
  • Structured Data
Fort Worth

2845 West 7th Street
Fort Worth, TX 76107

Dallas

3102 Oak Lawn Avenue
Suite 650
Dallas, TX 75219

Austin

823 Congress Avenue
Suite 800
Austin, TX 78701

London

33 Broadwick Street
London
W1F 0DQ

New York

120 East 23rd Street
New York, NY 10010

Get in touch

(817) 420 9970
info@pmg.com

Subscribe to the PMG Newsletter
© 2021 PMG Worldwide, LLC, All Rights Reserved
  • Contact
  • Privacy Policy
 Tweet
 Share
 Tweet
 Share
 Tweet
 Share
 LinkedIn
We and our partners use cookies to personalize content, analyze traffic, and deliver ads. By using our website, you agree to the use of cookies as described in our Cookie Policy.