WP_Query: Get Posts by Relative Date

Someone asked me today how to use WP_Query to get posts by a relative date. The codex provides an example on how to achieve this. Heres what is shown on the codex.


<?php /** NOTE: This is the example from the Codex, which think is BAD. **/
// Create a new filtering function that will add our where clause to the query
function filter_where( $where = '' ) {
// posts in the last 30 days (hardcoded)
$where .= " AND post_date > '" . date('Y-m-d', strtotime('-30 days')) . "'";
return $where;
}
//Requires immediate additiona and removal of the filter for intended use.
add_filter( 'posts_where', 'filter_where' );
$query = new WP_Query( $query_string );
remove_filter( 'posts_where', 'filter_where' );

I feel that its sloppy and not very flexible. Having to add the filter and remove it each time you want to do this is ugly. I solved this some time ago and had to dig through some old code to find it.


<?php
/**
* Allows WP_Query to use a 'since' argument to query for
* relative date queries.
*
* Usage: Query posts from last 30 days
* $query = new WP_Query('since' => '-30 days');
*
* @uses strtotime()
* @author Eddie Moya
**/
function filter_where_add_since( $where = '', $query) {
if( isset($query->query_vars['since']) ){
$where .= " AND post_date > '" . date('Y-m-d', strtotime($query->query_vars['since'])) . "'";
}
return $where;
}
add_filter( 'posts_where', 'filter_where_add_since', 10, 2 );

Ultimately what I have done is the same solution, using the same filter, and utilizing strtotime() to get the relative date. However  i’ve wrapped it into a simple “since” parameter that can be used on any query. Just a little nicer and simpler to use.

This technique can easily be adapted to other custom parameters which result in modifications to the where or join filters.


Media Categories 1.5 Beta and WordPress 3.5

This week WordPress 3.5 was released, and the core team has made a some great improvements to the way media is handled in the UI. I managed to get my name in the credits for a measly few lines I contributed in a couple of patches – nonetheless I’m proud to be a part of it.

The reason I created the Media Categories plugin is because of how neglected the interface for media was. Especially with regard for anyone wanting to add support for taxonomy. In 3.5 media still comes without any taxonomy enabled out of the box (as it should be) – but for those who those who do the custom work of enabling one, the interface is now much improved.

What Changed?

In the past, if you simply enabled any taxonomy for media, the editor would get a simple text field into which users would need to manually enter the slugs from memory. The interface for media was unique from that of any other post type. What they’ve done in WordPress 3.5 is simply make the Media interface behave more like every other post type.

So now when a taxonomy is added to media, you automatically get a built-in metabox, you get a column on the Media Library listing the taxonomy terms applied to each item, and you get a taxonomy page specifically for media. They have also greatly improved the modal window for managing media – even adding the ability to edit the details (title, caption, description) right there in the modal.

So what good is the Media Categories plugin now?

On the surface it seems as though my plugin is mostly useless now. It could be stripped down to a few lines to just enable the taxonomy and be done. Thats not the case. First of all, 3.5 still doesn’t support filtering by taxonomy in the “Gallery” shortcode. Also, since a couple of weeks before WordPress 3.5 was released, I have been working to fill in the gaps where I see some room for improvement.

Whats new in Media Categories 1.5?

The new Media modal window has at once, made it easier for me to allow users to edit the taxonomy of an image from the modal screen, while also making the default behavior problematic enough that it merited an overhaul of my plugin to address this problem.

I’ve added a collapsible version of the metabox, along with the filterable search box to the modal media editor.

I’m not releasing it yet, because I’ve run up against a quirk in how the new modal saves data – it causes the collapsable section to immediately collapse when the auto-save kicks in. Getting the auto-save to work at all with checkboxes was a challenge.

When will Media Categories be released?

Once this auto-collapsing behavior is solved, I’ll probably be satisfied enough to release 1.5. However I do still need to test in 3.4.x and 3.3.x to make sure the plugin still works correctly in those versions. I have a vested interest in making it backward compatible because I use this plugin at work, and many of our sites are on several out dated version of WordPress (shh).

I will continue to work on it, and work with the core team to make this happen as soon as possible. However if you would like to take a look at this new version feel free to download it from the master branch on GitHub.

Update: Media Categories 1.5 Beta 2


Media Categories 1.3.1 & a Trac Ticket with Patch

I didn’t have a chance to post about this, but last week I quietly released Media Categories 1.3.1, to workaround a problem which was reported to me on the support forums in the WordPress Plugin directory.

A user of the Media Categories plugin explained that some under certain circumstances, categorized media would not save properly. Here are the steps to reproduce the problem:

  1. Create two categories with the same name, but different slugs.
  2. Open up an attachment while Media Categories 1.3 or below are turned on. (download that version here)
  3. Select the two same-name categories, and click save. WordPress will take you back to the Media Library.
  4. Open the same attachment again, and click save, without having changed anything.
  5. Open that attachment once more. You will find that one of the categories that had a duplicate name, is no longer selected.

The first thing I did was turn off the styling on my plugin, which hides a text field that WordPress creates when an attachment has taxonomy support and watched what it did as I went through each of the steps above. This field will take term ID’s, slugs, and names – it can take any number of terms, each separated by commas – but requires the user to manually enter them from memory, which I why I built my plugin.

Once the user has selected and saved their terms, upon re-opening the attachment, that field will always be populated by the categories name. When names are used in that field, WordPress simply tried search for that category by name,  which as we know can be non-unique. This results in WordPress chosing the first term with that name it comes across, for both instances of the name – resulting in the later on being lost. The next time you open that attachment, there’s only one instance because both were saved as the same term.

I figure this has gone unnoticed because WordPress does not natively support taxonomy for attachments, and few people use plugins that turn on that support. It’s easy to see how the original developer of the built-in text field would have thought that using the term name would be easier for end-users to deal with – however it clearly causes problems when in use.

I opened a ticket in WordPress Trac, and submitted a very modest patch that changes one line in core so that is spits out the slug instead of the name. However who knows when that ticket will be  dealt with, and we are very close to WordPress 3.4 being released, so I don’t have much hope of it being part of that release.

With that in mind I developed a fairly simple workaround which accomplishes the same goal, but by effectively re-doing what WordPress does when saving an attachment. I released it last week over the holiday weekend as Media Categories 1.3.1, and I suggest anyone using this plugin upgrade, or risk losing some of their saved data.

Thanks for reading, and thanks for the bug reports.

Update:  My patch was accepted and will be released in WordPress 3.5. As small and simple as it might be, and even though I’ve been working with WordPress professionally for over 3 years – this is the first time one of my contributions to core has been committed. Yay me.


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’;