Plugin Update: Category Template Hierarchy 1.3

Download Category Template Hierarchy Version 1.3 from the WordPress Plugin Repository

I’ve release an update to the Category Template Hierarchy plugin, a particular bug report prompted the update but there are a couple of other changes as well.

I use this plugin for three sites I’ve worked on for Sears / Kmart, so over time I make  minor changes to resolve issues I notice or improve how it works, but I don’t always have time to release those changes publicly.

A recent bug report forced to release a fix, and gave me an opportunity to update the plugin. Some of these changes effect how the plugin behaves, so it could impact your site if you depend on this plugin to keep your theme working. Here are the changes

  1. Improved performance be removing completely unnecessary logic to determine current category while building the list of potential templates to use. (No behavioral effect)
  2. Changed the filter used by the plugin. Before it used the very broad and general ‘template_redirect’ filter, but that caused obvious problem with other parts of the hierarchy, so not it uses the ‘category_template’.
  3. In addition to changing which filter is being used, the plugin used to `include()` the `get_query_template()` function, but now returns `locate_template`. This should resolve a bug where global variables such as $post were not available from within the loop.
  4. Logic in the `is_child_of_category()` and `is_parent_of_category()` has changed to check `!isset($child_category->parent) || !isset($parent_category)` instead of `empty($child_category) || empty($parent_category)`. This could effect your code if you use these conditional tags for anything in your theme.

The only item that does not effect any behavior is #1. Items #2 and #3 change the way the template hierarchy effect other parts of the native Template Hierarchy, so if you’ve seen strange behavior with non-category templates then you’ll definitely benefit from these changes. Item #4 is important as well, since it simply makes the conditional results much more accurate.

I don’t know how often people use the conditional functions, or how many of the couple thousand people who’ve downloaded this plugin actually use it at all – but I really appreciate the bug reports and any feedback. As I’ve said, I use these plugins myself on productions sites – so the public QA is always appreciated.

Download Category Template Hierarchy Version 1.3 from the WordPress Plugin Repository

Enjoy!


Simple Hook Widget – WordPress Plugin

Download: WordPress Plugin Directory

This widget allows the user to insert a hook, with a name of their choosing, in any sidebar.

The hook can be anything, an existing hook from the WordPress Core, a plugin, a theme, or something you’ve come up with on the fly. Once the hook exists, your plugins, your theme, or the WordPress Core to make something happen with that hook.

This can be used in conjunction with other more complex plugins, to give the user control of then things occur (yes, that is intentionally vague). It can also serve as a quick alternative to making very simple widgets tied to code from a theme. Say you have a chunk of code which already exists on your site, you’d like to also have it placed in a sidebar, but don’t want to make a widget out of it (since its entirely theme-centric). You could simply hook this chunk of code to a custom hook and use the Simple Hook Widget to place that custom hook in the sidebar. This is absolutely not an endorsement toward that strategy for widget development, but there may be times where such on option is useful to a developer in a pinch.

This widget also contains an internal hook, which will be your hook, prefixed with simplehookupdate_. So if you use this plugin to create a hook name ‘testhook’, the widget, aside from creating the ‘testhook’ in the chosen sidebar location, will also create a hook called ‘simplehookupdate_testhook’. This hook occurs within the update method of the WP_Widget class, immediately before $instance is returned.

All in all its very simple, and intentionally so. I hope developers can find some useful uses for it – I know I already have a very complex plugin in the works that will utilize this. Please feel free to make suggestions or ask questions.

 


Incorrect Datetime Bug Plugin – WordPress

Download: WordPress Plugin Directory

This plugin was create to work around a problem that -I have to assume- only occurs after a database migration, where certain configurations in MySQL lead to several odd symtoms including but not limited to:

  • Loss of ability to create new posts
  • Loss of ability to update posts
  • Admin interface reverts to lowest settings such as the ‘Publish’ button says ‘Submit Draft’.
  • Errors regarding invalid timestamps
In addition, this problem is often accompanied by an error like the following:
WordPress database error: [Incorrect datetime value: ‘0000-00-00 00:00:00’ for column ‘post_date_gmt’ at row 1]

INSERT INTO `mg_posts` (`post_author`,`post_date`,`post_date_gmt`,`post_content`,`post_content_filtered`,`post_title`,`post_excerpt`,`post_status`,`post_type`,`comment_status`,`ping_status`,`post_password`,`post_name`,`to_ping`,`pinged`,`post_modified`,`post_modified_gmt`,`post_parent`,`menu_order`,`guid`) VALUES (‘1′,’2011-08-23 03:32:43′,’0000-00-00 00:00:00′,”,”,’Auto Draft’,”,’auto-draft’,’post’,’closed’,’open’,”,”,”,”,’2011-08-23 03:32:43′,’0000-00-00 00:00:00′,’0′,’0′,”)

The inability to pass zero dates breaks the ability to actually create a new post, but it also seems to have the odd secondary effect of confusing the heck out of nonces (noces are a security feature), probably because they too rely on timestamps.

This plugin strips out the sql_modes listed below from @@SESSION, thereby eliminating the problem while only effecting database sessions WordPress starts and not the whole database.

Explanation and history of the problem

The cause of this problem stems from an old (soon to be deprecated) odd behavior/feature of MySQL which WordPress came to depend on. My understanding is that it stems from problems in MySQL with regard to using the MySQL NOW() function in some contexts – so as a workaround it was decided that if a date of all zeros was entered on a column that was set as NOT NULL, then that date would not be rejected, but instead would be converted to the current date – to mimic NOW().

Subsequently this method was marginalized as generally a bad idea – and now values exist for a setting called sql_mode, which turn this behavior off and force errors when a null value is passed to a NOT NULL field. In many cases when there is an actual DBA in charge of the database, they will assign these values to the production database to force what outside of MySQL would be normal SQL behavior.

There are 3 sql_modes which will trigger the error by disabling the ability to enter zero dates.

  • NO_ZERO_DATE
  • NO_ZERO_IN_DATE
  • TRADITIONAL
It’s worth mentioning that the ALLOW_INVALID_DATES mode does NOT solve the problem, even though by the name of it, it would seem that it might.

The solution

This plugin solves the problem with minimal effect to the database environment. All this plugin does it check to see if the sql_modes in question are set, and if they are, it removes them.

Importantly, this plugin changes @@SESSION.sql_mode and not @@GLOBAL.sql_mode. By changing sql_mode via the session, it only takes effect on each specific connections WordPress makes with the database rather than changing it for the entire database permanently – as such this will have no effect whatsoever on any applications that might happen to be using the same database.

Other manifestations, alternative solutions.

WARNING: Whenever applicable, consult your DBA before making any changes to production databases.

This problem may (I have no idea) in fact be more common during installation. The errors are different, and although I have seen them, I do not have them handy at this time. In any case, if the sql_modes are set during installation – the process will fail from the start – because of this, it is my presumption that anyone encountering the errors as described above – has probably recently migrated to a new database, or perhaps recently acquired an enthusiastic new DBA who has made some changes.

This plugin DOES NOT FIX this problem for those encountering during installation – thats impossible because WordPress ignores all plugins during installation – so there is no way to hack around it via plugin and fix it before installation occurs.

If you are encountering this problem during installation you will need to find an alternative way to remove the modes. If this is a production environment this may require the cooperation of a DBA who may not like the idea. If met with resistance, I suggest the asking for the modes to be temporarily removed for installation, and then set back after its dont – at which point this plugin will handle the problem from then on.

If your encountering this locally, or on a environment whose database you have access to modify, you will want to make as few changes as possible, so go to whatever interface you use (command line, phpMyAdmin, whatever) and run this line of SQL:

SELECT @@GLOBAL.sql_mode;

This will show you all the sql modes currently defined. Copy all them them but if you have NO_ZERO_DATE, NO_ZERO_IN_DATE, or TRADITIONAL remove them. Then update sql_mode with the remaining modes as such:

SET @@GLOBAL.sql_mode = "STRICT_TRANS_TABLES,STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO";

Please don’t simply use the sql_mode definition I have shown above, this is only an example – be sure to use the modes from your database configuration. Remember to keep everything together NO SPACES ALLOWED in the definition.

Finally, if your just working locally and don’t care about these sql_modes, you can just clear them all.

SET @@GLOBAL.sql_mode = "";

This will do the trick but is absolutely not recommended as a fix for production sites that might share environments.

Irrelevant Note: I struggled with naming this plugin, and settled on the terminology seen in the error message.


Moving the Uploads Directory in WordPress

To give context, I will start from the beginning,… If you’ve come here simply looking for any way to move the uploads directory – skip all this and jump straight to Moving the Uploads Directory…

Moving wp-content

There are many times when its a great idea to move some of the default locations of certain directories in WordPress. At my current job, we have a handful of sites that all share a the same plugins and theme folders. However, when I arrived at this position a few months ago, they had done this by using symbolic links – this causes problems with many plugins due to their use of the __FILE__ magic constant. As a result it was necessary to modify many of the 3rd party plugins we had remove that constants use.

In WordPress we can change the default location of the wp-content folder by defining a couple constants in wp-config.php as explained in the Codex:

define( 'WP_CONTENT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/blog/wp-content' );
define( 'WP_CONTENT_URL', 'http://example/blog/wp-content');

Plugins can be moved similarly as the same section in the Codex explains. What happens here is we are simply telling WordPress where we want to put wp-content or plugins, rather than confusing the issue by having it point to a directory where they wont be via symbolic links.

This is extremely useful, by doing this we can share our plugins and themes across multiple instances of WordPress without having to push code out and maintain each one individually. Moreover, many if not most developers using source control on multiple environments probably already ignore wp-config.php – or at least have some way of distinguishing environments within wp-config.php.

Moving the uploads directory…

While discussing the necessary changes in wp-config with team members, I realized we might run into a hitch with the uploads directory, which resides within wp-content. While we wanted to share plugins and themes, we certainly did not want to share content.

Initial googling resulted in no clear documentation as to how to move the uploads folder out of wp-content – and the codex page describing the the way to move wp-content makes no mention of either themes or uploads. So while I considered the possibility of leaving wp-content where it was, and moving themes and plugins, I could not find a way to move themes out of wp-content. I eventually found that we could filter the wp_upload_dir() function, or that we could update the ‘upload_path’ option – but both of these methods would require a plugin which would need to be maintained in source control, need to be turned on, and need to have an interface to allow a human to add the correct information depending on the environment. This to me seemed like a lot of work for something that started out with 2 lines in wp-config.php – not only that but it makes the entire exercise pointless, as there is already an option in the general settings to manually change it. A manual change is not what we needed. There had to be some other way.

Eventually I made my way through the core code to find out that there is an undocumented constant called UPLOAD which wp_upload_dir() checkes for – if its defined it will used it, if its not it will create a path by combining WP_CONTENT_DIR (which as we saw above, we can define in wp-config) with the ‘/uploads’.

define( 'UPLOADS', '/wp-content/uploads' );

Theres a catch though, when UPLOADS is actually used, its added to the end of ABSPATH. Defining ABSPATH one fo the first things WordPress does, its a constant which houses the WordPress root. By tying UPLOADS to ABSPATH, it means we can’t move the uploads directory outside of the WordPress folder structure.

A patch…

As a result of this, I decided to write my first ever patch for the WordPress core. The initial patch creates WP_UPLOADS_DIR and WP_UPLOADS_URL, so that the uploads can be defined via wp-config.php just like wp-content and the plugins directory. It defines those constants in the same way also, in default-constants.php – I then simply modified wp_upload_dir() to use these constants rather than hardcoding a definition each time the function is run.

It seems to be a simple solution and would be a natural extension of the method for moving wp-content and plugins.

The debate…

Reaction to my humble patch was not enthusiastic as you can see by reading the comments on the ticket #18489. After som protracted debate with Nacin and some others on the #wordpress-dev IRC channel, I identified what seems to be the primary concern – that developers might mistakenly begin to use the said constant within plugins instead of using wp_upload_dir() as they should, and that its availability would create confusion since in many cases it would not have the correct path (wp_upload_dir has many condition related to multisite as well as the font-end option that overwrite the default, and that would also overwrite the new constants.)

A possible solution…

As a result of that debate in IRC, I have modified the patch so that it does not  define the constants by default, but stead works the same way the little-known UPLOADS constant does – simply allow wp_uploads_dir() to check if they have been defined – if they have, then it will use them, otherwise it will use use WP_CONTENT_DIR . ‘/uploads’;