Turn Any WordPress Site Into An Issues-Based Magazine

Turn Any WordPress Site Into An Issues-Based Magazine

In offline publishing, regular periodic publishing is the dominant model be it the daily newspaper or the quarterly journal.

Online, however, this approach has barely got a toehold and yet publishing in issues would be beneficial to many sites that are not part of the over-hyped and ultimately destructive “24 hour news cycle”.

Turning your WordPress site into an issues-based online publication is not hard. Let me show you how.

Photo of magazines in a commercial magazine rack
Periodical publishing is the staple of print publishing but is rarely used online

Content is king, as the saying goes, but in this day of “firehose” publishing a considerable amount of content is lost in the sheer volume that consumers have to wade through or quickly gets pushed into obscurity by the relentless pace of publishing.

Perhaps it’s surprising then, that so few sites have adopted a periodical publishing model, particularly when you consider the growing rise in tablet use where digital magazines are readily consumed and especially the continuing popularity of digest email newsletters.

A curated set of content, released on a regular schedule, be it daily, weekly, monthly or quarterly, provides advantages for both the reader and publisher. For publisher it means not having to be a slave to the instant-publish paradigm. There’s a chance to take stock, to focus on quality and to produce content of substance.

For the reader, there’s not the pressure to “keep up” with everything and anything. There’s comfort in the knowledge that someone they trust is curating on their behalf and the opportunity to “curl up” with a good site (a benefit for publishers also).

Does the lack of examples mean that periodical publishing is hard? No. In fact, it’s surprisingly easy.

Keeping It Simple

In designing this solution, I’ve tried to adhere as much as possible to the KISS Principle. In “keeping it simple [stupid]” it not only makes it easier to understand and implement but it should also mean that it will work with any existing WordPress installations with little to no additional customisation.

So, what does periodical publishing mean? Well, these are the criteria we’ll be working with:

  • content is collated into issues
  • only content of the selected issue is displayed
  • visitors can change the issue by visiting the back issues page and selecting a different issue
  • visitors can view the contents for an issue
  • visitors can perform a search on the issue (as well as on the whole site)

The only extension to the content model is a custom taxonomy called Issues, otherwise it uses categories, pages and posts, just like any normal WordPress site and there are no mandatory theme changes required.

The 30,000 Feet Overview

Photo of female Olympic weightlifter
A custom taxonomy does most of the heavy lifting

Most of the heavy lifting is done by a custom taxonomy with other components really just tidying up.

  • The custom taxonomy will collate posts into issues and provide automatic filtering if the taxonomy and a value is provided, so we need to make sure that the current issue is added to the relevant links within the site.
  • The homepage needs a little extra help as obviously there won’t be an issue contained in the link. In this case, we’ll filter the posts based on a custom global option we’ll create to hold the current issue value.
  • To ensure that we don’t navigate outside of the current issue we need to add a check to the post navigation (‘previous post’ and ‘next post’) to ensure that it only links to posts within the same issue.
  • We need to update the custom global option when we want to publish a new issue. To achieve this, we’ll nominate a post category as the “master category” and whenever a new post is published in this category we’ll update the global option with the post’s issue.
  • To make publishing an issue a little easier, when the post in the master category is published we’ll also publish all other posts that are in the same issue and have a status of “pending”. Not having to publish all the posts prior to the master category post keeps them from appearing in the search; by using the “pending” status we also keep from publishing draft posts.
  • We’ll add the ability to set the master category and even override the current issue by adding some fields to the Settings > General page in the admin interface.
  • And finally, we’ll make a couple of shortcodes available. One will display the contents for the current issue – a list of the issues posts grouped by their category; the other will provide a list of “back issues”, basically a formatted list of published posts from the master category.

Rather than dive straight into the code, it’s probably better to set it up, have a play, get a feel for what it does and then step through how it’s done.

How To Set Up Periodical Publishing

You can set up periodical publishing on your WordPress site in four easy steps:

Step 1 – Download and install the plugin

I’ve wrapped up all the code into a plugin, so download and install it into a test WordPress site that contains enough content to create several issues.

Step 2 – Create and Assign Issues

Screengrab of the issues metabox on the post edit page
Assign an issue using the metabox

You’ll find a new menu option of Issues under the Posts menu. Here you can create new Issues and give them a description. Do add a description as you may want to use it in your theme.

Now, go through existing posts (or create new posts) and assign issues using the Issue metabox in the right-hand margin.

Step 3 – Set the master category

Staying within the admin interface, navigate to Settings > General and you’ll find a new section called Magazine Settings. Here you can set the master category and the current (that is latest) issue.

Posts in the master category act as an issue. When you publish a post in this category it not only updates the current issue value with post’s issue but also publishes all other posts in the same issue that have a status of pending.

The master category is also used by the [backissues] shortcode.

Screen grab of the customised settings page
Set the current issue and the master category in Settings > General

You can also set the current issue. This should be a drop-down box consisting of the Issues that you created in Step 2. When you implement issue-based publishing on an existing site, you’ll likely want to manually set the current issue.

Step 4 – Create the Back Issues and Contents Pages

Create two new pages for Back Issues and Contents, including the [backissues] and [contents] shortcodes as appropriate in the page body.

Add the new pages to a menu on your site.

This should be enough to have turned your site into an issues-based magazine. Navigate to your site and you should be greeted with a homepage only containing posts that are assigned the current issue.

Roll over any category link you’ll notice that issue has been appended to the querystring, ensuring that issue is carried across to archive listings. Individual post links don’t need the amended querystring as the current issue can be determined from the post itself.

Click around the site, you’ll find that you remain within an issue at all times unless you perform a search or select a back issue. Selecting a post from a search effectively selects a new issue and again you will remain within that issue unless you search again.

If your site uses post navigation (previous post and next post) you’ll see that this also remains within the issue. This is not a function of the custom taxonomy but due to a filter on the post navigation that will delete any link that is to a post that is not part of the current issue.

You can also try publishing a new post in the master category. Make sure you have some posts in the same issue set to “pending” before you publish in the master category and you will see all the posts get set to published as well as the global current issue option get updated.

So, How Does It All Work?

There are a number of components but by far the most important is the custom Issues taxonomy.

The Heart of the Solution: Custom Issues Taxonomy

The custom Issues taxonomy allows posts to be assigned to a particular issue and this allows control over how and when they are displayed.

Custom taxonomies can be created either using code or by using any number of plugins including WPMUDev’s custom type, custom field and custom taxonomy plugin, CustomPress (USD$19).

The plugin creates a new taxonomy which adds:

  • a new Issues menu option under Posts in the admin interface where the Issues taxonomy can be managed
  • an Issues metabox to the post edit screen where Issues taxonomy terms (eg. “one”,”two”) can be assigned to a post much like tags
  • an Issues column to the post listing screen allowing for the list of posts to be filtered on an Issue term

The most important part of creating the taxonomy is setting the query_var argument to true. This simple assignment provides the automatic filtering of posts if the taxonomy term and a value is included in the URL.

For example, if we have the URL magazine.com?issue=two, WordPress will recognise that a taxonomy (issue) is being used and will use the term (two) when querying posts effectively only selecting those posts that have been assigned the specified term.

This is, quite frankly, brilliant for periodical publishing. And to top it off, the filtering only occurs in The Loop and so has no impact on menus or widget output.

Of course, that does mean that we need to add the taxonomy to relevant links in the site.

Adding Issue to Page and Category Links

Actually all we need to do is add the issue argument to links to pages and category links. Posts we don’t need to worry about as we don’t need to filter and we can always pick up the current issue from the post itself.

To amend the querystring, we hook into the built-in filters that are fired when generating page and category links and add issue to the query arguments.

1
2
3
4
5
6
7
8
9
function mag_add_issue_to_link ( $url ) {

return add_query_arg( 'issue' , mag_get_current_issue() , $url );

}

// ensure issue is added to page links, category links and search links
add_filter( 'page_link', 'mag_add_issue_to_link' );
add_filter( 'category_link', 'mag_add_issue_to_link' );

The mag_get_current_issue() function determines the most appropriate term for the Issue taxonomy. It does this in the following order of preference:

  1. If a post is being displayed then get the term assigned to the post
  2. If the query-string contains issue then use the value
  3. Get the value of the global option “current_issue”

Special Treatment for the Home Page

Obviously, if a visitor types in your site’s home page then there is no issue information for the page to work with. To give the home page a helping hand, we manually filter the post selection by hooking into the pre_get_posts action that gets called before a posts query is executed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function mag_front_page_filter( $query ) {

if ( $query->is_home() && $query->is_main_query() ) {
if ( !get_query_var( 'issue' )){
$tax_query = array(
array(
'taxonomy' => 'issue' ,
'field' => 'slug',
'terms' => mag_get_current_issue(),
)
);
$query->set( 'tax_query' , $tax_query);
}
}
}

// register the filter
add_action( 'pre_get_posts', 'mag_front_page_filter' );

This action gets called for every post query so the most important aspect is to ensure that only the main query on the home page is affected. We still check to see if issue is in the query string (if it is then filtering is going happen anyway) and if it isn’t we set up our own taxonomy filter by adding a tax_query argument to the query.

Keeping Post Navigation On Issue

The post navigation links are not generated within The Loop, so the next and previous post links are not filtered. If we left these unchecked then eventually links to posts outside of the issue will appear.

We can prevent this from happening by using the next_post_link and previous_post_link filters to only return a link if the post being linked to is in the current issue.

1
2
3
4
5
6
7
8
9
10
function mag_check_post_navigation ( $output, $format, $link, $post ) {

// if this post is not the current issue then return blank
if ( !has_term( mag_get_current_issue() , 'issue' , $post) ) return '';
return $output;
}

// add the check to the next and previous post links - make sure 4 parameters are passed so we get $post
add_filter( 'next_post_link' , 'mag_check_post_navigation', 10, 4);
add_filter( 'previous_post_link' , 'mag_check_post_navigation', 10, 4);

Publishing An Issue

The master category controls the publishing of an issue.

I imagine that the master category may be something like Editorials as in most periodicals there’s usually some sort of “welcome” post. So, when a new post in the master category is published this will make live the issue the post is assigned to as well as publish all the other posts in the issue that are in a pending status.

This is all achieved by hooking into the publish_post action.

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
36
37
38
39
40
41
42
function mag_check_for_new_issue_on_publish( $post_id ){

// check that this is a real publish and not an update
if( ( $_POST['post_status'] == 'publish' ) && ( $_POST['original_post_status'] != 'publish' ) ) {
// is the post in the master category?
if ( in_category( get_option( 'mag_master_category' ) , $post_id ) ) {
// get the issue and assign this to global option current_issue
$terms = get_the_terms ( $post_id , 'issue' );
if ($terms) {
update_option ( 'mag_current_issue' , $terms[0]->slug );
}
// publish all posts that are in the same issue
$args = array(
'posts_per_page' => -1,
'post_status' => 'pending',
'tax_query' => array(
array(
'taxonomy' => 'issue',
'field' => 'slug',
'terms' => $terms[0]->slug,
)
)
);
remove_action( 'publish_post' , 'mag_check_for_new_issue_on_publish' );

// get list of posts
$issue_pending_posts = get_posts( $args );

// loop through and set each post_status to publish
foreach( $issue_pending_posts as $pending_post ) {

$pending_post->post_status = 'publish';
wp_update_post( $pending_post );

}
add_action( 'publish_post' , 'mag_check_for_new_issue_on_publish' );
}
}
}

// register the action
add_action( 'publish_post' , 'mag_check_for_new_issue_on_publish' );

The function, which is called after the post is published, first checks to see if this is a first-time publish and not an update. We’ll only activate this code on a first-time publish. We also only want to keep processing if the post being published is in the master category.

If this is a first-time publish of a master category post then we first update the global current issue option with the issue assigned to the post. The first issue is always used, so if multiple issues have been assigned the others will be ignored.

We then get a list of the posts in the new current issue and set the publishing status to publish. You’ll notice that when setting up the arguments for the call to get_posts, posts_per_page is set to -1 to override any built-in limit. You’ll also notice that before looping through the posts, the custom action is removed. This is stop the custom function getting called again as a result of the call to wp_update_post and helps prevent endless loops.

The action is restored after all posts have been processed.

Making Short Work With Shortcodes

Three shortcodes are included in the plugin:

  1. [backissues] displays all the posts from the master category in an unordered list.
  2. [contents] displays posts for the current issue within unordered lists within an unordered list of category headings
  3. [display_issue] displays a <div> containing the current issue term (e.g. “two”) and the issue description

The plugin enables shortcodes to be used in widgets which may be useful for the [display_issue] shortcode.

I’m not going to step through the shortcode code or the settings code here as it’s not strictly related to the topic here. However, you can learn more about the Shortcode API and the Settings api in the WordPress Codex.

Extending The Solution

Whilst this solution will enable issues-based publishing on any WordPress website it is just a basic framework and you’ll likely want to extend it to meet your needs or better integrate it with your theme.

Some prime areas would be:

  • Extend the search to enable “this issue only” and “entire site”
  • Restrict comments to an issue or at least display the issue term
  • Provide better access to the contents, especially on tablets
  • Changing the home page to be an issue “cover”

I’m sure there are others but hopefully this is a good enough start to encourage you to look seriously at issue-based publishing.

If you do use this code then let me know how you go. I’d also be interested in hearing what you think of issue-based publishing especially if you are already using this approach.

Photo credits: Ken Hawkins, Simon Q