How to give your plugin pluggable functions

The amazing pluggable machine – photo by lukasWP

Pluggable functions are functions that can be overridden by others.  The key is which is defined first.  So to make one your plugin’s functions pluggable one should define it  as late as possible.  So others can get in first of course, but not so late that your plugin tries to use it before it is defined.

Understanding the sequence of wordpress actions is important. Some key action points in order of lateness are:

  • plugins_loaded
  • after_setup_theme
  • init (often used by plugins to initialise)
  • wp_loaded (when wp is fully loaded)
  • wp (when the wp object loads)

To make your plugin function pluggable by a theme or another plugin it needs to be defined AFTER the themes and the other plugins. So if your functions are mainly to do with output, you could move them as far back as the ‘wp’ action say.

In your main plugin file:

add_action ('wp','amr_load_pluggables', 10);    //move it later and a low priority

function amr_load_pluggables() {
    require_once('amr-pluggable.php');
}

The Pluggable Functions

Each pluggable function must test that it has not already been defined

if (!function_exists( 'the_pluggable_function')) {
    the_pluggable_function($parameters) {
    // the code
    }
}

The Override Function

The coder doing the overwriting  (ie plugging the pluggable function ) then just defines the function normally in their own plugin, or in their themes functions.php.  All they have to do is not bury it inside an action that executes AFTER the ‘wp’ action (or the action that loads the pluggable files).

Oh and it would be a good idea to fully understand where / when that pluggable function gets called and what it is supposed to do, what values to return etc.  You do not want to cause nasty side effects.  Looking at the code of the pluggable function is a good place to start.

Conditional Override

If they wanted to only override under certain circumstances, EG:  If you want to override ONLY on certain post types and only if certain conditions are met on the single view, then one could do

add_action('wp', 'define_my_override_function', 1) {
// using wp action as well as we need the post query et to have been done already, but a higher priority so will execute before the pluggable function load.
}
function define_my_override_function() {
global $post;
    if (is_single() and ($post->post_type === 'event') and (whatever other criterai)) {
 // then overwrite the pluggable, requires the pluggable loading to be later in the wp action sequence, say on action 'wp' late priority
        function the_pluggable_function($parameters) {
        // your code here
        }
     }
}

Post meta key, sometimes case sensitive, sometimes not…..

Lower case love... by gazeronly

If you have been banging your head against the proverbial brickwall trying to debug a intermittment post_meta bug then this may help.

I googled all aspects, but did not find any post to shed light.  Eventually figured it out….

Put simply:

  • get_post_meta() is case sensitive on the meta-key

BUT

  • update_post_meta is NOT case sensitive

Thus If there is a pre-existing meta record with a key in UPPERCASE, then one can

  1. issue an update for a lowercase key that will
  2. update the UPPERCASE key, and not create a lower case record. (Usually update will ‘add’ if no record exists).

Delete_post_meta() has the same behaviour – you can try to delete a lowercase key, but the uppercase version will get deleted (too?)

Then of course when you try to fetch with your same lwoercase key that you did the update with, the fetch will fail as it does not exist – only the uppercase key exists.

That was fun trying to debug……

See trac ticket raised for details or progress.

Mysql db collation

It seems it has a lot to do with the mysql db collation being used.  The default in many db setups is a _ci (case insensitive one) – they are faster and give more ‘natural’ sort orders, although that very much depends on the language you are using.

The get_post_meta behaves differently apparently because wordpress caches the data so one is not necessarily querying the database.

If you are keen to know more, see

 

WordPress html5 validation – Bad value for attribute rel

A green for go amongst the red - photo by my buffo

If you want to get rid of the rel attributes that cause the html5 validation to fail.  There is some difference of opinion around this.

BUT,

  • your client may not understand – the site must be html5 AND valid!
  • I miss that green 100% valid reassurance when I am testing although I like to test with default wordpress and default theme… what to do?

If you want that green 100% valid response back, regardless, then……

Remove the rel attributes to get the green back

A bunch of actions and filters and yes,  you have to use a child theme with own header and footer unfortunately as some is hardcoded in the header.php

Add to child theme  functions.php or a temporary plugin:

remove_action( 'wp_head', 'index_rel_link' );
remove_action( 'wp_head', 'wp_generator' );
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wlwmanifest_link');
remove_action('wp_head','adjacent_posts_rel_link_wp_head');
remove_action('wp_head','start_post_rel_link');

 

Theme edits

Footer.php

copy to child theme and edit footer.php

  • line 26 remove rel=”generator”

Header.php

copy to child theme and edit header.php

<link rel="profile" href="http://gmpg.org/xfn/11" />
  • line 74 remove rel=”home”

 

Another option: Replace rel attributes with accepted ones:

The links need a rel attribute, so choose a valid one and replace the invalid ones:

add_filter('parent_post_rel_link', 'amr_remove_rel_up');
 function amr_remove_rel_up($link) {
 return (str_replace ("rel='up'","rel='xxxxx'", $link));
 }
 add_filter('next_post_rel_link', 'amr_remove_rel_next');
 add_filter('prev_post_rel_link', 'amr_remove_rel_prev');
 add_filter('start_post_rel_link', 'amr_remove_rel_start');
 add_filter('end_post_rel_link', 'amr_remove_rel_end');
 add_filter('index_rel_link', 'amr_remove_rel_index');

etc.....