Jumping Duck Media http://jumping-duck.com Telling Stories with Technology Wed, 02 Jan 2013 06:45:56 +0000 en-US hourly 1 http://wordpress.org/?v=3.5.1 WordPress Plugin Structure http://jumping-duck.com/tutorial/wordpress-plugin-structure/?utm_source=rss&utm_medium=rss&utm_campaign=wordpress-plugin-structure http://jumping-duck.com/tutorial/wordpress-plugin-structure/#comments Thu, 27 Dec 2012 16:00:34 +0000 Eric http://jumping-duck.com/?p=458 The power of WordPress lies in its pluggable infrastructure.  Unlike other content management applications which require you to edit the core code of the system to make changes, WordPress supports plugins.  These smaller applications tie in to a rich API provided by WordPress that allows you to change just about everything about the application and customize it as needed.

The official plugin repository on WordPress.org is currently home to over 20,000 distinct plugins.  Each one adds some new functionality to WordPress, giving you the ability to tweak content, change colors, adjust layouts, or integrate with external systems.  This doesn’t even begin to cover the hundreds of premium plugins you can find online that provide even richer functionality.

Most WordPress developers will, at some point, be asked to create some kind of plugin for a client site. These client plugins can range from a shortcode manager to some kind of advertisement rotation engine to an API integration with a third-party customer management system. Instead of focusing on the what for your plugins, this tutorial will focus on the how. Namely, the three different ways you can structure a WordPress Plugin.

Functional

The quickest, easiest approach is to use standard functions to define your custom functionality. For simple plugins, this is actually the best and most straight-forward approach.

All of your plugin code will reside in a single file – my-plugin.php – in the root of your /my-plugin directory. Prefixing every function name with a unique string (i.e. myplugin_) will prevent your code from colliding with any code shipped by another developer. It also makes it easy for other developers to remove and re-add action hooks and filters should they need to.

The following example code will add the number of draft posts to the Right Now box on the WordPress dashboard:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function myplugin_count_posts() {
  $posts = wp_count_posts();

  $num = number_format_i18n( $posts->draft );
  $text = _n( 'Draft', 'Drafts', intval( $posts->draft ), 'myplugin_translate' );

  if (  current_user_can( 'edit_posts' ) ) {
    $num = "<a href='edit.php'>$num</a>";
    $text = "<a href='edit.php'>$text</a>";
  }

  echo '<tr><td class="first b b">' . $num . '</td>';
  echo '<td class="t">' . $text . '</td></tr>';
}
add_action( 'right_now_content_table_end', 'myplugin_count_posts' );

This hook can easily be removed, reordered, or otherwise manipulated by other developers if they know the hook name. Keep things consistent in your code, and things will work well for community involvement.

Unfortunately, if your plugin is much more complex, the functional approach can quickly become a nightmare. Figuring out which functions are defined where in a large, monolithic file can be challenging. Once you start breaking your one file into smaller pieces of distinct functionality, though, you face other organizational difficulties.

For more complex plugins, you should begin structuring things in a class format.

Static Class

Just like prefixing function names can prevent function collision, making your functions all static members of a class will, essentially, “namespace” your plugin’s functionality. After prefixing, this is the easiest way to organize your plugin in such a way that it plays well with other systems in the WordPress infrastructure.

The trick is that action hooks and filters are now added using an array notation rather than a straight string. For example, instead of add_action( 'wp_head', 'myplugin_head' ), you would call add_action( 'wp_head', array( 'My_Plugin', 'head' ) ). Similar notation, but it’s important to include the class reference here, otherwise WordPress won’t know where your code is defined.

Breaking your function up into several files is best done when each file represents a distinct class. It’s easy to know which functionality is encapsulated within which class if you keep related functions together and are clear with your project names. It’s also relatively easy for other developers to manipulate your code later, so long as they also remember the static class notation you used with add_action().

Here is our functional example from above, but rewritten as a call from a static class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class My_Plugin {
  static function count_posts() {
    $posts = wp_count_posts();

    $num = number_format_i18n( $posts->draft );
    $text = _n( 'Draft', 'Drafts', intval( $posts->draft ), 'myplugin_translate' );

    if (  current_user_can( 'edit_posts' ) ) {
      $num = "<a href='edit.php'>$num</a>";
      $text = "<a href='edit.php'>$text</a>";
    }

    echo '<tr><td class="first b b">' . $num . '</td>';
    echo '<td class="t">' . $text . '</td></tr>';
  }
}
add_action( 'right_now_content_table_end', array( 'My_Plugin', 'count_posts' ) );

Some tutorials recommend an instantiated class with some static elements for adding/removing action hooks and filters. Their code will work, but is a bit hacky. Particularly if you’re ever in a place where the class can be instantiated more than once. With that in mind, I would never recommend that approach – either keep everything static, or go with my favorite pattern below.

Singleton

A singleton is a class that can only be instantiated once. Every other reference to the instantiated object is a reference to the same object. This is a pattern that works beautifully for plugins because, honestly, you only ever need to instantiate the plugin once. It’s also the way I prefer to build plugins since it keeps things clean, avails private variables to the plugin, and is an easy pattern to follow.

Basically, a singleton is a class with a read-only static instance and a private constructor. When you attempt to get the class instance, it checks to see if the class has been instantiated – if not, it fires the constructor internally and stores the constructed object inside the static instance. Now, every request for the instance returns the same object. Here’s a very basic example of a singleton class.

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton {
  private static $instance = false;

  public static function get_instance() {
    if ( ! self::$instance ) {
      self::$instance = new self();
    }
    return self::$instance;
  }

  private function __construct() { }
}

With a singleton class, you can have methods and members that are members of the class, can refer to each other, and can reference data (properties) which are private to the class itself. For example, if you build a singleton and populate it with certain properties that are meant to be read-only, you can store those values as private members of the class and expose public getter functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class My_Class {
  private $hidden_var; // Invisible outside of the class
  var $visible_var; // Visible outside the class

  public function get_hidden() {
    return $this->hidden_var;
  }

  public function __construct() {
    $this->hidden_var = 4;
    $this->visible_var = 6;
  }
}

$instance = new My_Class;
echo $instance->visible_var;  // Echos 6
echo $instance->hidden_var;   // Fatal Error
echo $instance->get_hidden(); // Echos 4

$instance->visible_var = 2;   // Works
$instance->hidden_var = 2;    // Fatal Error

Removing action hooks and filters is straight forward because you always have access to the instance of the class that wired them up in the first place. This means it’s easy for developers down the road to manipulate your code.

Here’s the same plugin example from above, but rewritten as part of a singleton class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class My_Plugin {
  private static $instance = false;

  public static function get_instance() {
    if ( ! self::$instance ) {
      self::$instance = new self();
    }
    return self::$instance;
  }

  private function __construct() {
    add_action( 'right_now_content_table_end', array( $this, 'count_posts' ) );
  }

  public function count_posts() {
    $posts = wp_count_posts();

    $num = number_format_i18n( $posts->draft );
    $text = _n( 'Draft', 'Drafts', intval( $posts->draft ), 'myplugin_translate' );

    if (  current_user_can( 'edit_posts' ) ) {
      $num = "<a href='edit.php'>$num</a>";
      $text = "<a href='edit.php'>$text</a>";
    }

    echo '<tr><td class="first b b">' . $num . '</td>';
    echo '<td class="t">' . $text . '</td></tr>';
  }
}

$my_plugin = My_Plugin::get_instance();

Conclusion

Most developers are just beginning to embrace object-oriented design patterns with WordPress. Unfortunately, few of us have enough experience with OOP to discern good versus bad programming patterns. Many developers are using instantiated objects to encapsulate plugin functionality – and running the risk of multiple instances being created during a single request. Others are properly using static classes and objects, then running afoul of global variables when attempting to pass data from one static method to another.

The most efficient pattern for WordPress plugin development is, hands down, the singleton. It can only be instantiated once, and has the ability to store data internally for quick recall – meaning member functions can easily pass data back and forth without cluttering the global namespace.

Which patterns are you using for plugin development? What other alternatives have you found?

]]>
http://jumping-duck.com/tutorial/wordpress-plugin-structure/feed/ 10
jQuery as a Global Event Bus http://jumping-duck.com/tutorial/jquery-as-a-global-event-bus/?utm_source=rss&utm_medium=rss&utm_campaign=jquery-as-a-global-event-bus http://jumping-duck.com/tutorial/jquery-as-a-global-event-bus/#comments Wed, 17 Oct 2012 15:00:40 +0000 Eric http://jumping-duck.com/?p=413 Some time ago, I made a mistake. 1  Rather than taking the time to truly understand how events worked in jQuery, I built my own JavaScript library to handle event delegation.

It worked, but why reinvent the wheel?

It turns out jQuery is perfectly capable of serving as a global event bus for all of your code.  You just have to know how to use it.

What is an Event Bus?

In old-school programming models, every bit of code would talk to every other bit of code.  If one changed an element on a page or the data stored in an object, it would immediately tell everyone else working on that page or object about the change.  The central problem here is scalability – in order to keep things in sync, every piece of your code needs to know about every other piece of your code.

For a simple Hello World application, not a big deal.  For a larger program, though, this becomes a cumbersome nightmare.

An event bus alleviates this problem and allows you to write fully decoupled code.  Rather than looking at its neighbors to watch for changes, a piece of code will subscribe to an event through the event bus.  When another piece of code fires an event (again, through the event bus), every observer is notified.

Why Use One?

In WordPress, for example, this pattern takes the form of action and filter hooks.  You don’t need to know when or where an action or filter is fired, you just need to know its name and what parameters are passed.  WordPress’ core code doesn’t know anything about your plugin, it just fires its actions and passes data through filters when needed.  Likewise, your plugin code doesn’t know anything about the location of these hooks, only that they exist.

In this way, the do_action()/apply_filters() and add_action()/add_filter() functions serve as the API for a built-in PHP event bus.

This is actually what makes WordPress such an amazing platform to develop with.  It’s nearly infinitely extensible through this event-driven API and very approachable for developers to begin tying new code into.  This kind of extensibility, when placed in themes and plugins, makes those systems equally extensible.

Decoupling your code also makes it less fragile.

If your PHP code is tied to a WordPress action, and that action is removed, your code will merely stop.  It won’t necessarily break 2, and WordPress will continue to function as before.  Likewise, if someone else’s code is tied to your action, and they remove their code, nothing will stop working.

Consider this example code:

1
2
3
4
5
6
7
8
9
10
11
12
13
function update_remote_database() {
  $database_url = 'http://someremotesite.com/db';
  wp_remote_post(
    $database_url,
    array( 'body' => date_create( 'now ') )
  );
}

// In some other part of your code.
// Maybe another file even ...
wp_insert_post( $new_post_from_args );

update_remote_database();

Versus this example code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function update_remote_database() {
  $database_url = 'http://someremotesite.com/db';
  wp_remote_post(
    $database_url,
    array( 'body' => date_create( 'now ') )
  );
}
add_action( 'after_insert_post', 'update_remote_database' );

// In some other part of your code.
// Maybe another file even ...
wp_insert_post( $new_post_from_args );

do_action( 'after_insert_post', $new_post_from_args );

In the first example, you must always have the update_remote_database() function present.  As the application grows, this function might move to a location far removed from where it’s called.  If, later on, the remote database is disabled, how do you stop calling it?  In the first example, you have to remove the function and look for where it’s called to remove the reference as well.

In the second example, you just remove the hook.  The original callee doesn’t change because, well, it wasn’t actually calling the function directly in the first place.

How jQuery Does It

Events in jQuery are easy. If you want to listen to the click event on a particular element, you add your handler inside jQuery('#element-id').click(function() { ... });.  If you’ve done much web development work at all, you’ve seen code similar to that quite often.

But did you know jQuery supports custom events?

In reality, the .click() method is just shorthand for .on('click').  Looking at the second way of registering a click event listener, you can easily see how this can be extended with custom events.

Let’s say our code does some background processing of large chunks of data. 3  When the processing is complete, you want to trigger the “oliver-twist” event to let the system know you’re ready for more data.

To do things globally, it’s easiest to bind these events to the document object rather than to specific elements of the DOM.  This way, they’re accessible to everything, and your code doesn’t need to know anything about the page markup to function – remember, it’s all about decoupling.

In this example, we listen for the “oliver-twist” event and then pass in more data:

1
2
3
4
5
6
7
$(document).on('olver-twist', function() {
  if(has_more_data) {
    process_data();
  } else {
    alert('Done!');
  }
});

Then, after our data is finished processing, we trigger the “oliver-twist” event:

1
2
3
4
5
6
7
8
9
10
11
12
13
function process_data() {
  setTimeout( async_process_data, 100 );
}

function async_process_data() {
  do_something();

  if(done) {
    $(document).trigger('olver-twist');
  } else {
    setTimeout( async_process_data, 100 );
  }
}

What’s Next?

Is your code extensible?  Does it use custom events to signal when it’s starting to do something or completing execution?  Where could you add some custom events to make it easier for third-party libraries to tie themselves in?

The Plupload library, for example, is a heavy user of custom events to let you know when files are added to a queue, uploaded, erred, etc.  It has proven to be a remarkably flexible library, and is hugely popular as a result – if you use WordPress and upload media, then you’re already using it and didn’t even know it.

Can your library be as flexible – and as widely used – as a result of enabling custom events?

Notes:

  1. Actually, I make mistakes quite often. Daily in fact. But let’s not dwell on this …
  2. Unless, of course, you’ve written it in such a way that it fails under these conditions.
  3. I know, JavaScript is single-threaded.  However, there are ways you can chunk up the processing of large quantities of data using setTimeout() so that the browser doesn’t become non-responsive. You’ll still need a way to know when it’s done …
]]>
http://jumping-duck.com/tutorial/jquery-as-a-global-event-bus/feed/ 1
Using XML-RPC in WordPress http://jumping-duck.com/tutorial/using-xml-rpc-in-wordpress/?utm_source=rss&utm_medium=rss&utm_campaign=using-xml-rpc-in-wordpress http://jumping-duck.com/tutorial/using-xml-rpc-in-wordpress/#comments Tue, 09 Oct 2012 15:00:13 +0000 Eric http://jumping-duck.com/?p=397 It was brought to my attention last week that there aren’t very many good tutorials on the web regarding the use of XML-RPC in WordPress.  Sure, there are plenty that talk about how easy it is to use and how great of a tool it can be, but few examples explaining just how it can be used.

I use WordPress for just about everything.  For websites, for forums, for ebook sales, for presentations, and most recently for an SMS gateway to a travel blog.  The thing is, I can’t always post to WordPress the way I want to.  I will be in Haiti next week and won’t have access to a computer or a laptop, but I still want to update my blog so I can communicate with friends and family at home.  XML-RPC to the rescue!

Well, not exactly.

The first part of my application is actually a custom handler for SMS messages that I set up on my server.  I won’t get into that part of the system for now; instead, I’ll explain how the system updates a remote blog hosted on WordPress.com using XML-RPC.

The Tools

There is just about no limit to what you can do with WordPress through XML-RPC calls.  You can add posts, edit comments, upload images, manage taxonomies, and even configure site options.  If there’s something you want to do that’s not exposed through the API, you can add your own calls with a simple filter.

From the receiving end of things, the XML-RPC system in WordPress is fantastic.  All of the ugly XML is converted to native PHP objects (and arrays and strings) so you can program along without needing to worry about content structs, unclosed tags, or remembering whether to use <int> or <i4> to mark a number.

The heavier part of the API is the sending end of things.  How do you get your data into that scary-looking content struct?  How do you structure your XML so WordPress can read it?  How do you interpret errors thrown by the server?

Luckily, these questions are already answered for you.

Most systems support their own XML-RPC library – WordPress is no different.  While there is a robust server library available, there is also a robust client library available as well.  You can use this library to execute XML-RPC requests from within WordPress to interact with or consume data from any XML-RPC server you like.

The Framework

In the case of my SMS link, I need to pass a “new post” request to WordPress.com.  I could simply use an existing service like IFTTT to trigger post creation 1, but their system doesn’t support post formats.  I want to keep my regular posts separate from my SMS updates, so I’ll be using the “status” post format for these separate updates.

Creating a post with a specified post format requires a custom call through my own, self-hosted XML-RPC client.  Luckily, I’m already using WordPress to host the SMS gateway, so I can use WordPress to push the update to the server as well.

Just include the Incutio XML-RPC library that ships with WordPress to get base functionality and WordPress’ internal HTTP XML-RPC client library to get started.  The first is the workhorse that translates native PHP objects and collections back and forth into XML-RPC structures.  The second is a beautiful abstraction of the request/response process that makes live so much easier.

1
2
include_once( ABSPATH . WPINC . '/class-IXR.php' );
include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );

Walking Through a Request

Every WordPress installation ships with a default XML-RPC endpoint. 2  In most cases, it’s discoverable as well – just check for the <link rel="pingback ...> tag in your site’s header to see where it’s at.  Probably something like http://yoursite.com/xmlrpc.php.

We’ll start building our request by creating a new client pointed at that endpoint.

1
$client = new WP_HTTP_IXR_CLIENT( 'http://yoursite.com/xmlrpc.php' );

Now let’s make a call.  For this specific request, we want to call wp.newPost to create the new post.  We’ll pass in an array of arguments based on the API that WordPress presents:

  • 0 - The blog ID, but it’s not really used.
  • ericmann – My WordPress username for the site.
  • ….. – My WordPress password 3
  • array() – The content structure. An associative array of the fields I want set for the newly created post.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$result = $client->query( 'wp.newPost', array(
    0,
    "ericmann",
    "....",
    array(
        'post_status'  => 'publish',
        'post_title'   => 'SMS Update',
        'post_content' => $_REQUEST['text'],
        'post_format'  => 'status',
        'terms_names'  => array(
            'category' => array(
                'Field Update'
            ),
            'post_tag' => array(
                'mobile',
                'update'
            )
        )
    )
) );

Nothing really fancy is happening here.  You could think of this as simply invoking wp_insert_post() on a remote site.  Really, that is what you’re doing.  When WordPress receives the request, it sanitizes the data (to make sure you aren’t sending garbage), calls wp_insert_post(), and returns the ID of the newly created post.

Now on the client side, you check to see if the request was successful.  If it was, you’ll get true.  If it wasn’t, you’ll get back false as a result and can check the error property of your client object to see what all happened.

1
2
3
4
5
6
if ( $result ) {
    update_post_meta( $new_post_id, 'posted', 'Success' );
} else {
    $error = $client->error->message;
    update_post_meta( $new_post_id, 'posted', 'Failed: ' . $error );
}

If you absolutely need the ID back as well, you can set the debug flag to true on the client object and it will record both the method call and the method response.

What’s Next?

Making requests is pretty simple, but if you want to get started and are worried about corrupting your database, WordPress ships with two test methods in its XML-RPC server:

  • demo.sayHello – Returns a standard “Hello!” message.
  • demo.addTwoNumbers – Accepts an array containing two numbers and returns the sum.

So to get started, you can merely create a request using one of these test messages: 4

1
2
3
4
5
6
7
8
9
include_once( ABSPATH . WPINC . '/class-IXR.php' );
include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );

$client = new WP_HTTP_IXR_CLIENT( 'http://wordpress.com/xmlrpc.php' );
$client->debug = true;

$hello = $client->query( 'demo.sayHello' );

$addition = $client->query( 'demo.addTwoNumbers', array( 55, 17 ) );

These commands should give you these blocks of XML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0"?>
<methodCall>
<methodName>demo.sayHello</methodName>
<params>
</params></methodCall>
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param>
      <value>
      <string>Hello!</string>
      </value>
    </param>
  </params>
</methodResponse>

<?xml version="1.0"?>
<methodCall>
<methodName>demo.addTwoNumbers</methodName>
<params>
<param><value><array><data>
  <value><int>55</int></value>
  <value><int>17</int></value>
</data></array></value></param>
</params></methodCall>
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param>
      <value>
      <int>72</int>
      </value>
    </param>
  </params>
</methodResponse>

Notes:

  1. They’re using an XML-RPC client under the surface as well!
  2. This will be customizable with a filter in an upcoming version of WordPress, but even when filtered the endpoint will still be available somewhere.
  3. You didn’t really think I’d give you my password, did you?
  4. Yes, I have tested this exact code. It works just fine.
]]>
http://jumping-duck.com/tutorial/using-xml-rpc-in-wordpress/feed/ 9
Theme-ready Shortcodes in WordPress http://jumping-duck.com/tutorial/theme-ready-shortcodes-in-wordpress/?utm_source=rss&utm_medium=rss&utm_campaign=theme-ready-shortcodes-in-wordpress http://jumping-duck.com/tutorial/theme-ready-shortcodes-in-wordpress/#comments Fri, 05 Oct 2012 15:00:28 +0000 Eric http://jumping-duck.com/?p=388 A few months back, I taught you how to make your widgets theme-ready by extracting the actual markup into an overridable template.  Now, we’re going to do the same for shortcodes.

And for those of you wanting to see this in practice, stay tuned for the release of version 2.5 of WP Publication Archive in a few weeks.  I’m using this technique to make markup easy to change.

Why Use Templates?

The beauty of WordPress is its flexibility.  With a limited amount of technical know-how, you can build a website in minutes that looks completely different from anything else built on the same platform.  It can be as unique as you want and as customized to you as can be.

This flexibility is extended through WordPress’ theme system.  If you have a WordPress site, you’ve used a theme.  What you might now know about the theme, though, is it’s just a template.

WordPress populates a few code objects based on the queried page (whatever link you followed to get to the site), then hands those objects off to the loaded template to render things to the page.  It’s flexible, because WordPress doesn’t know (or need to know) anything about the template.  You can render your content as HTML, XML, JSON, or whatever other capitalized acronym you want.

We’re going to use a template for our shortcode for the very same reason – our plugin will provide a default display for the content, but really that can be replaced by any other template the end user chooses.

Populating the Data

It doesn’t really matter how you build your data so long as you’re precise in the way your data is constructed and used.  The new version of WP Publication Archive, for example, globalizes a variable and populates it with an array.  This array contains, among other things, a collection of publications that need to be displayed whenever the user enters the [wp-publication-archive] shortcode.

The variable has to be global in scope so that the template can access it.  Be very precise with your global object name so no other plugins step all over it.  It might also be a good idea to pass the object through a filter before loading the template as well to provide the highest level of flexibility possible:

1
2
3
4
5
6
7
8
9
10
11
// Get a global container variable and populate it with our data
global $wppa_container;
$wppa_container = array(
    'publications' => $publications,
    'total_pubs'   => $total_pubs,
    'limit'        => $limit,
    'offset'       => $offset,
    'paged'        => $paged,
    'post'         => $post
);
$wppa_container = apply_filters( 'wppa_publication_list_container', $wppa_container );

Loading the Template

Now we actually load of the template.  Be sure to set an easy-to-remember name – I typically prefix my template files with template. so I can remember which files in the plugin might be overridden by a theme.  A descriptive name will also help users know what the file is for:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Get the publication list template
$template_name = apply_filters( 'wppa_list_template', 'template.wppa_publication_list.php' );
$path = locate_template( $template_name );
if ( empty( $path ) ) {
    $path = WP_PUB_ARCH_DIR . 'includes/' . $template_name;
}

// Start a buffer to capture the HTML output of the shortcode.
ob_start();

include( $path );

$output = ob_get_contents();

ob_end_clean();

// Because globals are evil, clean up afterwards.
unset( $wppa_container );

return $output;

The idea behind this code is to check first if the theme has a similarly-named file.  If so, load that one up.  This file is placed either by the theme developer or the end user specifically to work with your plugin.  Make sure you respect that and defer to their markup.  If the file doesn’t exist, though, load some kind of fallback from within the plugin.

This fallback file should serve as an example to other developers how you think content should appear, but it is not a strict expectation.  Consider it more of an example for how to build a shortcode template.

Output Buffer

Notice in this example I’m using an output buffer.  Normally, I wouldn’t encourage that.  Shortcodes, thought, return data rather than output the data.  But template files should always be geared towards presentation.

It’s easiest to write the template file as if it’s an output file.  Use raw HTML and php’s echo to generate things.  This way it stays in-line with the widget templates we’ve done before and with themes (as templates) as well.

Building Markup

The shortcode template should have no functionality or logic.  Zero. None.

The template file is 100% markup.  You might throw in a loop or two to iterate through collections, but there should be no queries or other data fetching in the file.  Everything you’re looping through should be provided in the global object you passed in earlier.

The end user might elect to add their own additional logic (third party plugins might add meta to your plugin), and they can definitely do that.  But you, as the initial developer, should not.  Keep it simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
global $wppa_container;
extract( $wppa_container );
?>
<div class="publication-archive">
<?php foreach( $publications as $publication ) { ?>
    <?php $pub = new WP_Publication_Archive_Item( $publication->ID, $publication->post_title, $publication->post_date ); ?>
    <div class="single-publication">
        <?php $pub->the_thumbnail(); ?>
        <?php $pub->the_title(); ?>
        <?php $pub->the_authors(); ?>
        <?php $pub->the_uri(); ?>
        <?php $pub->the_summary(); ?>
        <?php $pub->the_keywords(); ?>
        <?php $pub->the_categories(); ?>
    </div>
<?php } ?>
</div>

What’s Next?

From here, any developer can drop a template.wppa_publication_list.php file into their theme and replace my default markup with whatever custom markup they choose.  They can use only HTML tags (<aside>, <section>, and the like), they can write out XML, they can reposition elements, etc.  It’s entirely up to them.

But the end user only ever has to enter one shortcode.  Like I said, simple.

Other plugin developers can also hook into the template loading process and inject some custom template as well.  Perhaps another plugin is built to specifically extend WP Publication Archive to add additional meta information and markup – they can hook in and add their own template instead.

]]>
http://jumping-duck.com/tutorial/theme-ready-shortcodes-in-wordpress/feed/ 0
The Anatomy of an Exploit http://jumping-duck.com/tutorial/the-anatomy-of-an-exploit/?utm_source=rss&utm_medium=rss&utm_campaign=the-anatomy-of-an-exploit http://jumping-duck.com/tutorial/the-anatomy-of-an-exploit/#comments Tue, 31 Jul 2012 16:00:45 +0000 Eric http://jumping-duck.com/?p=309 I’m a huge fan of security. I spend many a weekend experimenting with new encryption techniques, hash algorithms, and security protocols.

As a result, I also come across several different server exploits in the wild. PHP hacks, .htaccess hacks, JavaScript injection, etc. I once even saw a server hacked through a corrupt PNG image that installed a PHP console when it was loaded.

To a new developer, is is all pretty scary stuff. Here’s an example of an exploit I came across last week – and how to both prevent and recover from it.

The Exploit

A friend alerted the world via Twitter to an odd issue posted in the WordPress forums.  A specific site was being redirected to a Russian website, but only if you visited with a mobile device.

I loaded the website both on my desktop and Android phone to see the difference – sure enough, the page loaded fine on the PC and the phone got Russian spam.

Next, I turned to Fiddler to see what else I could diagnose.

With a desktop user agent, everything came across the wire just fine.  Substituting a mobile user agent string – or any string containing the words “Android” or “iPhone” yielded somewhat different results:

There is now a coded block of JavaScript injected above the opening <!DOCTYPE html> tag.  When decoded, this script writes a new script tag to the browser.  This script tag loads a remote URL that forces a redirect from the site you’re on to a site of the hacker’s choosing.

I followed up with my results in the forums, and mentioned them on Twitter.  That’s when Sucuri Security joined the conversation and confirmed this is a known malware bug.

How To Fix It

Most known bugs also have known fixes – in this case, the exploit was a poorly secured .htaccess file that loads the extra script based on the user agent passed in the request.  Flushing the file is usually enough to remove it.

But that’s never enough for me.

Once an attacker has access to your system, they’ll likely install more than one back door.  Yes, .htaccess is obviously corrupt.  But there might be code lurking in a random PHP or JavaScript file on the server, just waiting to re-infect your site.

The best way to recover a WordPress site is to:

  1. Change your FTP password (this might be the hacker’s original way in)
  2. Change your MySQL password (keep your database secure – also change this in wp-config.php)
  3. Check your wp-config.php file line by line to make sure it’s clean. Compare it to the wp-config-sample.php file from a fresh download of WordPress to be sure.
  4. Reinstall WordPress. This means deleting everythingexcept for your configuration file, themes, and plugins
    • Ideally, you’ll also remove all themes and plugins and reinstall them from clean sources as well. If you can’t, make sure you go through each line of every PHP file and make sure there isn’t anything hinky going on there. 1
  5. Go through your entire /uploads directoy and make sure no rogue files or scripts are lying around
  6. Restore your database from the most recent (clean) backup
    • If you don’t have a backup, get ready for a long night of going through data tables manually to be sure there isn’t anything hiding in the database
    • And really, why don’t you have an automated backup? Set one up now while you’re at it!
  7. Ask another developer to double check your work to be sure you haven’t missed anything.

In a pinch, you can also hire the experts at Sucuri to clean things up for you. They know what they’re doing and have likely cleaned up this specific hack already.

Don’t Get Hacked in the First Place

There’s quite a bit you can do to harden your site before it gets hacked. Here are just a few quick recommendations:

  • Change your WordPress admin password regularly. And don’t use the same password anywhere else.
  • Use different passwords and logins for WordPress admin, FTP, and MySQL.
  • If you’re running your own VPS, don’t do anything as root.
  • If you can, turn off FTP altogether. If you absolutely need it, consider SFTP instead.
  • Check your system access logs for weirdness regularly.
  • Make routine backups of your filesystem and database so you can recover quickly from problems.
  • Consider signing up with a malware monitoring service – Sucuri happens to offer this, too.

Notes:

  1. Yes, I did just use the word hinky in a professional post. Get over it. :-)
]]>
http://jumping-duck.com/tutorial/the-anatomy-of-an-exploit/feed/ 0
Doing it Wrong the Right Way http://jumping-duck.com/tutorial/doing-it-wrong-the-right-way/?utm_source=rss&utm_medium=rss&utm_campaign=doing-it-wrong-the-right-way http://jumping-duck.com/tutorial/doing-it-wrong-the-right-way/#comments Tue, 17 Jul 2012 15:00:04 +0000 Eric http://jumping-duck.com/?p=302 Telling someone there’s a right way to include a plugin in a theme is like telling someone there’s a right way to cheer for the Beavers during the Oregon Civil War.

There is no right way.

However, there are still ways to do it if you absolutely need to.

Let’s admit it. As developers, we’re lazy.  We don’t like installing multiple tools when they could be bundled into one package.  We don’t like teaching our clients the difference between functionality and presentation.  We don’t like documenting the multiple items we installed on a client site so the next guy can not break things when he works on it.

We’re lazy. As a result, we try to take shortcuts whenever possible – one of those shortcuts is bundling plugins with themes to extend WordPress’ functionality.  But if you must take such a shortcut, here are the “right” ways to invoke _doing_it_wrong().

TGM Plugin Activation

A couple of fantastic WordPress developers have taken the time to pull together a utility class for placing plugin dependencies in themes: TGM Plugin Activation.

Add this class to your theme and register its plugin dependencies.  Then, when users activate your theme, you can automatically download, install, and activate any missing required plugins. This has a huge benefit – the plugins are regular WordPress plugins and are installed using regular WordPress functionality.  In other words, when updates are released, WordPress handles the updates exactly the same way as any other update.

The downside, though, is the somewhat large footprint of the class.  The single PHP file is a whopping 2,000 lines of code – so for automatically including smaller plugins it can be a bit overkill.

Copy the Implementation of mu-plugins

This is the pattern modeled by Alex King in his tutorial – it involves bundling the plugin directly with the theme and loading the core plugin file the same way WordPress does.  The advantage here is that you’re not doing anything exotic – you use the same functionality WordPress does to load the plugin.  In addition, using Alex’s model, your bundled version of the plugin is automatically overridden by a standalone installation of the plugin.

The downside, though, is that you’re including the plugin in a location WordPress doesn’t expect.  It won’t detect updates to the plugin, so if things change you need to re-release the theme.

Use Filters

The right way to include plugin functionality in a theme is to not include plugin functionality in a theme.

Instead, build your theme under the assumption that the plugin is installed and active.  Then, hide any dependent functionality behind hooks – actions and filters.  You want to add specific social sharing widgets below a post? Great! But don’t call custom_sharing_widgets() directly.  Instead, add a hook to your theme and wire the hook up in your theme’s functions file:

1
2
3
4
5
6
// In functions.php
if ( function_exists( 'custom_sharing_widgets' ) )
  add_action( 'my_theme_below_post', 'custom_sharing_widgets' );

// In single.php
do_action( 'my_theme_below_post' );

If the plugin is installed, the widgets are automatically placed in the right area of the theme. If not, nothing happens. Using actions like this, you can support multiple similar plugins – just tie in the same hooks. Then your users can decide on their own which plugin to use to add this functionality.

Actions and filters are insanely powerful, and you can define as many as you need.  Just look at premium themes like the Genesis framework and all the awesome hooks they provide.  It’s relatively simple to customize the layout and hooking in new functionality.

Just remember, plugins and themes are meant to server vastly different purposes.  Mix and match at your own risk.

]]>
http://jumping-duck.com/tutorial/doing-it-wrong-the-right-way/feed/ 1
Why Sponsor WordCamp Portland http://jumping-duck.com/news/why-sponsor-wordcamp-portland/?utm_source=rss&utm_medium=rss&utm_campaign=why-sponsor-wordcamp-portland http://jumping-duck.com/news/why-sponsor-wordcamp-portland/#comments Wed, 11 Jul 2012 16:00:00 +0000 Eric http://jumping-duck.com/?p=295 This August, I’ll be attending WordCamp Portland.

I’ll also be speaking at WordCamp Portland.

Last week, I also decided to sponsor WordCamp Portland.

Why all the investment?  It’s simple.  I love Portland.  I love WordPress.  And I have a blast spending money on the things that I love.

My first WordCamp ever was in Portland.  I had just been exposed to the platform and didn’t really know any other developers. Or users. Or anyone who had even heard of WordPress.  My blog at the time was still hosted on Blogger, and I was using e107 to power my first website.

A friend actually had to talk me in to going. He even paid for my ticket.  Honestly, in the beginning I couldn’t care less for WordPress.

What Changed?

The best thing about WordPress isn’t the database, the UI, the Codex, or even the fact that it’s free.  The best thing about WordPress is the community that surrounds it.  The developers who build it, the writers who document it, and the flesh-and-blood people who use it at the end of the day.

Getting to meet other WordPress users was exciting.  We could relate to one another’s issues and talk at great length about our experience.  We also had a great time watching Jane Wells show off some awesome improvements to the UI.

My first WordCamp sold me on the platform.  I stopped worrying about the other (clunkier) CMS platforms and began to hone in on actually using a system and getting to know the people who made it.  I build my first plugin during WordCamp.  I wrote my first core patch not long after that.

So Why Sponsor?

WordPress has done a great deal to impact my life – I believe in giving back to the causes and organizations that have helped me so they might continue to help others.  After all, my goal in life is to help others launch their dreams – what better way than by helping fund the same event that helped launch mine?

Sponsoring also means I have 2 extra tickets in my pocket to give away.  I’ll hold on to them for now (there are plenty of tickets left for salego buy one), but you can probably expect some kind of contest/giveaway as the event grows near.  Stay tuned, and maybe you can join me at this awesome event!

]]>
http://jumping-duck.com/news/why-sponsor-wordcamp-portland/feed/ 1
Merging WordPress Multisite http://jumping-duck.com/tutorial/merging-wordpress-multisite/?utm_source=rss&utm_medium=rss&utm_campaign=merging-wordpress-multisite http://jumping-duck.com/tutorial/merging-wordpress-multisite/#comments Thu, 07 Jun 2012 16:00:44 +0000 Eric http://jumping-duck.com/?p=281 When I first set up my personal website network, I got a bit carried away.  Once I had the first two sites in a multisite network, I started splitting out every category of my blog into its own site – each with its own domain.

At the peak, I had:

  • One site for my personal profile – linking to all the other sites
  • One site for a professional portfolio
  • One site for my business blog
  • One site for my Christianity blog
  • One site for my creative writing portfolio
  • One site for political discussions
  • One site for a personal journal

Then I read a great article by Ipstenu about why you shouldn’t use WordPress Multisite and decided I should rein things in a bit.  Categories of content should be categories instead of full sites.

This started a huge migration of content.  I set up a clean WordPress installation and started moving all of my posts, pages, categories, tags, etc from the schismed sites into the new one.  Everything was clean and ready to go … except for one thing. External links.

I’ve never understood why, but sometimes people actually like what I write.  They link to it.  People follow those links and comment.  So when http://mindsharestrategy.com/2011/how-to-publish-a-wordpress-plugin-subversion/ becomes http://eamann.com/tech/how-to-publish-a-wordpress-plugin-subversion/, what happens to my traffic?

Redirection

The first thing I did was install a plugin called Redirection on my new site.  I knew that my URL structure was going to be different before and after the merge, so I was able to set up redirects between the old structure and the new structure.

Using the URL structure above as an example, I mapped /2011/how-to-publish-a-wordpress-plugin-subversion/ to http://eamann.com/text/how-to-publish-a-wordpress-plugin-subversion/?ref=mindshare.

The query argument at the end does two things:

  1. It lets me track how many people are being directed to my site from old URLs
  2. It lets me display a message on my site explaining why the design and URL has changed if I want to

Server Configuration

Now that the redirects were in place, all I had to do was point the domains at the new location.

I use Nginx to power my WordPress sites, so pointing my Mindshare domain at my EAMann site was a matter of the domain as a server_name in my configuration:

1
2
3
4
5
6
7
server {
  listen      80;
  server_name eamann.com mindsharestrategy.com;
  root        /var/www/html/website;

  # Rest of Nginx configuration below ...
}

Anyone trying to visit an old post or page from Mindshare Strategy is now redirected automatically to the same content on the new site.

Root Domains

Unfortunately, this failed to handle the root domain – all of my old domains stayed the same but presented content from the new site.  I could have mapped a redirect from / to http://eamann.com, but there’d be no way to see if the traffic was coming from Mindshare Strategy, Prose Painting, Grounded Christianity, or one of my other sites.

So instead of placing the domain directly in my main site’s configuration, I broke each domain into a separate server profile and used Nginx’ internal rewriting to redirect traffic:

1
2
3
4
5
6
7
8
9
10
11
server {
  listen      80;
  server_name mindsharestrategy.com;

  location = / {
    rewrite ^ http://eamann.com/category/biz/?ref=mindshare permanent;
  }

  location / {
    rewrite ^ http://eamann.com$request_uri permanent;
  }

This configuration still maps all post and page requests through WordPress so that the Redirection plugin can do its work.

It also forces a redirect of the root domain to a specific page I design – in the case of Mindshare Strategy, all visitors are mapped to the category archive for Business posts.

]]>
http://jumping-duck.com/tutorial/merging-wordpress-multisite/feed/ 0
How to Contribute to WordPress Core http://jumping-duck.com/tutorial/contribute-to-wordpress/?utm_source=rss&utm_medium=rss&utm_campaign=contribute-to-wordpress http://jumping-duck.com/tutorial/contribute-to-wordpress/#comments Tue, 22 May 2012 16:00:32 +0000 Eric http://jumping-duck.com/?p=272 My first ever contribution to WordPress was trimming whitespace from keys stored in the WordPress options table.

Basically, I removed a space.

But since then, I’ve contributed quite a few other patches to the project I love.  Eleven of them have actually made it in to the core codebase!

At the Portland WordPress User Group meetup a few weeks ago, I gave a 5-minute presentation explaining how everyone could get involved with WordPress; both developers and non-developers.  Still, people ask all the time how they can see their changes reflecting in WordPress core.

So here’s an example of how a recent contribution I wrote made its way into the yet-to-be-released WordPress 3.4.

The Idea

I am on just about every social networking site possible.  Each site adds its own features, and one I really love on Google+ is the ability to scroll back to the top of the page by clicking an empty spot on their top-level toolbar.

I love this feature so much, I find myself clicking on every top-level toolbar in the vain hope that someone has knocked off Google’s code.  Unfortunately, this usually leads to nothing more than a few seconds of confusion before I manually scroll to the top.

With WordPress 3.4, though, I was told that the “admin bar” was being converted to a more generic “toolbar.”  It no longer represents just administrative functions, but can be wholly integrated into the theme to present a better customer experience.

This announcement came with a tweet from a friend suggesting we roll our own version of Google’s scroll-to-top feature.

I was hooked.

The Ticket

I spent my lunch break reading through the JavaScript in WordPress that controls the toolbar.  Apparently it loads two sets of functions—one that uses jQuery and one that doesn’t.

Build a jQuery scroll-to-top feature was easy.  That change amounted to a whopping single line of code:

1
$('html, body').animate({ scrollTop: 0 }, 'fast');

I generally try to avoid jQuery dependency in my client projects, though, so building out a version that worked in the absence of jQuery was vital.  Sure, the jQuery version works fine on the administrative side of WordPress, but for the toolbar to be a front-end tool as well, I needed to port the feature there.

My lunch break work evolved into some after-dinner work as I took a look at some stock “scroll to top” scripts I found on Google and some scrolling features I’d built out for past client projects.  Eventually, I had a working script, so I created a new ticket on Trac to host my work:

Ticket #19534

Google+ introduced a fantastic feature with their toolbar. If you’re scrolled far down a page, clicking any non-link in the toolbar automatically scrolls back to the top of the page.

When viewing a very long WordPress front-end (or a long list of comments/large settings page on the WordPress back-end), this would be a fantastic tool. It’s also better to have a consistent UX control built in to the system rather than the various spin-your-own hacks different developers have built over the years.

I propose we add this “back to top” functionality to the WordPress toolbar. It should necessarily work with or without jQuery (in situations where themes don’t enqueue jQuery on the front-end but still display the toolbar).

It didn’t take long for some others to test my code and verify that it did work as advertised.  After a day or so, though, someone pointed out that my cursory Trac search failed to pull up an even older ticket requesting the same feature.  So my ticket was closed as a duplicate and I made my way over to the original post.

The Patch Process

After transporting my initial patch to the right Trac ticket, I asked the community for some additional feedback.

The first feedback, ironically, was my own.  I tried cleaning up some of the stylistic elements of my code (I’m a stickler for elegant code structures) and hit a snag with some single-line logic statements.  I fixed my patch and submitted a new copy.

Then Daryl Koopersmith took a look and cleaned up my code a bit more.  His code was definitely cleaner, but didn’t seem to work on some older versions of IE due to an inconsistency with those versions’ implementation of JavaScript.

I took another look (since I debug IE issues daily) and found the particular elements that needed fallbacks for the older browsers.  A few quick changes took us to a third version of the patch.

While I was making these changes, though, someone proposed the idea of just loading jQuery on the front end of the site by default.  I’m very much opposed to this, and made that clear in the comments, but the discussion continued beyond just the ticket.  Most of the WP team is fairly active on Twitter and in IRC as well, so we hash out debates in multiple locations.

The final patch came from Andrew Ozz.  It was nearly identical to my last patch, except it removed some redundant logic checks.  Sometimes it’s just not necessary to verify that true === true.

A New Feature

After this final patch, now that the feature had been properly reviewed by the community and tested independently in multiple browsers, it was committed to Core.  Andrew Ozz tagged the commit with “props ericmann” to give me credit, and my name will be forever inscribed in the list of WordPress contributors.

Today, you can click an empty spot on the toolbar of all my sites to scroll to the top of the page (I’m running 3.4-beta everywhere).  You can also use this feature on WordPress.com as they run several pre-release features on their network, too.

How You Can Get Involved

So how do you get involved with WordPress core development?  It’s an easy, X-step process:

  1. Decide what you want to change. You might have found a bug in WP, there might be a feature you want added, or you might find an unpatched ticket on Trac that appeals to you.  If there isn’t a Trac ticket for the bug/feature already, create one.
  2. Check out WordPress via Subversion. You’ll need a local copy of the WordPress codebase to make changes.  Check out a fresh copy of WordPress trunk so you’re up-to-date with the latest changes.
  3. Make your changes.  Then, using Subversion, export a patch that shows what you’ve changed.  Upload this patch file to the Trac ticket you made the changes for.
  4. Engage the community.  Take some time to talk about your change on Twitter, in IRC, on your blog, etc.  If the community doesn’t know you’re making changes, the changes will never happen.  Be sure to explain why you think the change is important or valuable, and be ready to collaborate with other developers to make it happen.

Disclaimers

Not every patch you submit to Trac will make it in to WordPress core.  Some changes affect too narrow an audience to belong in the core codebase.  If someone claims “that’s plugin territory” it’s because they think the number of users will benefit is just too small to warrant rolling your change in with the core project.

Don’t take this personally.

You can always write a plugin that extends the same functionality.  Use the plugin to prove your code and try to convince the community that your changes belong in core.  If you’re persistent, you will be heard.  Just don’t overdo it.

Also, keep in mind that the WordPress community operates as a meritocracy – those who have contributed the most are listened to the most.  If you’re new to the project, it might take some time for you to earn your place at the table.  Keep writing good code and contributing in meaningful ways to the project and your voice will be heard.

]]>
http://jumping-duck.com/tutorial/contribute-to-wordpress/feed/ 9
Classy Plugins http://jumping-duck.com/tutorial/classy-plugins/?utm_source=rss&utm_medium=rss&utm_campaign=classy-plugins http://jumping-duck.com/tutorial/classy-plugins/#comments Tue, 15 May 2012 16:00:28 +0000 Eric http://jumping-duck.com/?p=249 I was asked a few weeks ago why I structured my WordPress plugins the way I do.

Anyone who has spent any time looking at my code knows that I like to keep my main functions in a class and wire up action hooks and filters in the root of the plugin.  But few people have asked me why I set things up this way.

My explanation is in two parts:

  1. Writing clean code
  2. Writing easy-to-maintain code

Though it should be noted now that, while this particular development style makes heavy use of classes within PHP, this is not object-oriented programming.

Let me say again – this is not object-oriented programming.  I use classes often to define custom objects, but in this situation I use them merely as convenient wrappers for code.

Writing Clean Code

Ideally, code should be self-documenting.

Function names should be concise yet descriptive.  Variable names should reflect what’s contained within them.  I should be able to tell from glancing at your code what it does without looking to external documentation.

Where code isn’t enough to explain what’s happening, a quick in-line comment usually is.

To stick to this idea, I like to name my plugin functions after the WordPress hooks they tie to.  If I want to hook onto the init hook, I’d like to do so with a function named init().

And that’s a problem because that function name is already used.

To keep things clean, I make all of my plugin functions public, static members of a class.  Then, I can specify the class name when hooking in to WordPress and can keep things clean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class My_Plugin {
  public static function init() {
    add_image_size( 'mp-image', 120, 140, true );
  }

  public static function query_vars( $public_vars ) {
    $public_vars[] = 'mp-paged';
    return $public_vars;
  }

  public static function the_content( $content ) {
    global $post;
    if( 'mp_post_type' != $post->post_type )
      return $content;

    $mp_post = new MP_Post( $post );
    return $mp_post->summary;
  }
}

A lot of other developers prefix their function names.  I have no problem with this as an alternative practice.  I just have my own preferences for code organization.

Easy-to-maintain Code

I keep all of my hooks in one place so I don’t need to hunt for them later.

My first experience with an “advanced theme framework” was what should have been a 2-hour design project.  Instead I spent 2 weeks hunting through the code and referencing online documentation to find out which hooks were defined in which files so I could override them.

It was painful.

As much as I like the elegance of seeing a fire_main_engines() or similar method in a plugin root (leaving that function to call others that wire up the hooks), that kind of model is difficult to maintain.  If all of the hooks are instead defined in one spot, it’s easy to add new ones, remove deprecated ones, or just see at a glance every part of the plugin that interacts with WordPress.

1
2
3
4
5
6
require_once( 'lib/class.my-plugin.php' );

add_action( 'init',        array( 'My_Plugin', 'init' ) );

add_filter( 'query_vars',  array( 'My_Plugin', 'query_vars' ) );
add_filter( 'the_content', array( 'My_Plugin', 'the_content' ) );

What We Gain

The folder structures of my plugins are very uniform and easy to follow. The root directory contains a single PHP file with plugin information, licensing, and all of the hooks used by the system. There’s also a readme file containing a changelog, FAQs, and other useful information. If the plugin adds presentation elements, there are a few screenshots.

The /lib folder contains PHP files with static classes that wrap the functionality of the plugin. They are either require()ed or include()ed by the root PHP file.

You can browse the base file in the root directory to see where my plugin ties in to WordPress. Based on the function and class name in the hook, you know exactly which file to look at for the actual functionality.

Is this the best way to do things? I don’t know for sure. All I do know is that it’s clean and efficient.

]]>
http://jumping-duck.com/tutorial/classy-plugins/feed/ 3