Is This Post Type in the Theme Post Types?

If you’re in the business of creating WordPress plugins for yourself or for others, then it’s likely that you’ve done work with custom post types.

On top of that, there’s a chance that you’ve needed to introduce some functionality into a custom post type based on what’s selected in the plugin settings (which I discussed all of that fun stuff in a previous post).

And I’ve seen a number of different ways in which this is done: Some of them involve complexity such as reading the select post types into an array, iterating through the list, comparing the current post type, setting a boolean, and so on.

But there is a cleaner way that this can be done. I’m not claiming it’s the best way (perhaps you could share some insight on your opinions on this in the comments), but it’s way that I’ve found useful and that I’ve been using a few times over throughout several projects.

Find the Post Type in the Theme Post Types

For the sake of completeness, let’s define the following example:

  • There is a settings page that lists all of the current theme’s post types
  • Each post type is associated with a checkbox
  • When the user saved the plugin settings, the checkboxes store the name of the custom post type in the array.

In this case, code probably speaks better than anyway else, so take a look at several functions (which can easily be added to your current theme’s functions.php file for demo purposes) to see how this all fits together.

Note that the functions that you’re going to see below assume that you’re familiar with the Settings API. Also note that the DocBlocks aren’t up to par with the WordPress Coding Standards as the primary purpose of all of this is to share the functionality.

If you’re good with that, then you should be good to go.

1. Add the Settings Menu

Though this is optional – that is, you could just add the settings to an existing menu – I think this helps to make the demo a bit clearer as it segments the rest of the functionality from WordPress.

And that’s how we’re going to define our custom menu item (that will appear under the Settings menu):

2. Introduce the Settings

Adding the settings consists of two steps:

  1. Defining the sections, settings, and options using the Settings API
  2. Setup the function for rendering the post types
  3. Rendering the options page

Luckily, the amount of code to do this is relatively short especially if you’re comfortable with, as mentioned, the settings API.

So first, define the section, settings, and options:

Then display the options on the screen:

Then add the pages that renders the actual options:

3. Use the Code on the Front End

At this point, the code can actually be used on the front end. In order to keep this trivial, I’m using the_content filter and this is where the crux of everything comes together: This is how to determine if the current post type is in a list of supported post types.

If so, a message will be appended to the content; otherwise, it will not.

Demo Done

Instead, the idea behind this is to provide a clean and easy way to determine if the current post type exists is a list of select options used elsewhere in the WordPress options.

Obviously, I’ve placed more of an emphasis on what the code does throughout this article rather than pushing comments, documentation, and so on. I’ve done that in plenty of other articles. This is primarily meant to be a quick way to determine if you can find the current post type in the theme post types.

Anyway, I’m sure the code can be modified to be even more efficient and cleaner (though I’m not looking for something so clever that it’s a single line that takes me a number of mental cycles to parse :) but I’m open to whatever other suggests you may have.

Note that, though, the core of the purpose of this – despite all of the code necessary to setup it up – really reduces to this:

in_array( ucwords( get_post_type() ),  get_option( 'acme-post-types' )  );

Anyway, I’m all ears as this is something that I’m encountering more and more.

8 Comments

Three minor suggestions:

Escape $post_type when used in tag attributes with esc_attr( $post_type ) and encode the HTML entities during the display of the post type label esc_html( $post_type_label ).
Use the defined post type label (instead of ucwords of the post type name) by retrieving the complete post type definition during get_post_types() with $output set to objects. This will include label value in every post type object.
Specify a default return value array() during get_option( 'acme-post-types', array() ) to avoid PHP warnings in case acme-post-types hasn’t been set, yet.

Hi Tom, I really appreciate all your posts as I’m learning WordPress and specifically using the Genesis framework. Even though I’m new here I’m not new to development in general so I have some theme and plugin goals already on my list to do :-)) I’m thinking I can apply this logic in your article to post_formats vs post_types. I want to restrict a feature from being part of a blog post if it’s not the regular blog post_format, take out the ability on links, quotes, blocks, etc.

    Hey Ginger – welcome to the WordPress community. I always dig hearing from others who have just jumped into development :).

    To me, your logic seems sound:

    I want to restrict a feature from being part of a blog post if it’s not the regular blog post_format, take out the ability on links, quotes, blocks, etc.

    That is, if the user isn’t working with the ‘Standard’ post format, then remove the options from the editor; however, note that those who are more than capable with HTML will always be able to write the markup necessary for it.

    To really restrict it, you’d need to do something like:

    • Look to see what format the post is
    • If the post is of a limited formatted, then strip all of the markup
    • Return that to the browser (or serialize that to the database)

    Just some quick thoughts – I hope this helps!

      Thanks Tom. My idea is for a popular plugin (don’ want to say else you might get false search hits :-) that shows on the blog post entry….it already gives the options to show on the single post or the archive page. I want to extend it further and tell it not to show on the other post_formats.

Hey Tom, I’ve used something similar on a few occasions. Looking at the code, I have a few suggestions:

The fourth argument in add_settings_field() has a typo, which prevents it from throwing an error since the settings callback doesn’t exist. It’s currently being rendered in the section callback. Typically, if I don’t need to display a section description, I’ll use __return_null for the section callback.

The $current_value variable should default to a string rather than an empty array.

Square brackets aren’t necessary in the label for or input id attributes. They don’t do anything and are used in jQuery/CSS as attribute selectors, so might make it more difficult to use the id as a selector. The id just has to be unique, which the prefix helps accomplish, so dashes or underscores are fine as separators.

In most cases, post type labels shouldn’t be used for keys or comparisons. They can be localized, so the value may change and when they are localized, you can’t use the API methods anymore because you no longer have a reference to the post type. I’d recommend working exclusively with the post type name and only use the labels when displaying something to the user.

I also tend to prefer sprintf() instead of concatenating long strings like the one in the foreach loop in acme_display_post_types(). It makes things a little more concise and easier to read.

Hopefully that’s all clear and useful, but let me know if I need to clarify anything.

    Thanks, Brady – this is really helpful. A couple of comments to clarify your points (though I just finished updating the code to almost all of ‘em :).

    The fourth argument in add_settings_field() has a typo, which prevents it from throwing an error since the settings callback doesn’t exist. It’s currently being rendered in the section callback. Typically, if I don’t need to display a section description, I’ll use __return_null for the section callback.

    This is a bad habit I have of doing – or rather, not doing – since before the 3.4 release. It’s something that I think makes the code so much cleaner and better, but old habits die hard.

    The $current_value variable should default to a string rather than an empty array.

    Nice catch. This is why I like code reviews so much.

    Square brackets aren’t necessary in the label for or input id attributes. They don’t do anything and are used in jQuery/CSS as attribute selectors, so might make it more difficult to use the id as a selector. The id just has to be unique, which the prefix helps accomplish, so dashes or underscores are fine as separators.

    Yeah – this is more or a less a consistency thing I do between id and name attributes when working with the Settings API – I know that it makes it more difficult to style, but I’m not actually looking to style elements if I’m using the API. After all, I want it to look WordPress native :).

    That said, the only reason I ever really use id attributes when working with labels and checkboxes is so that it relates the two. That way, a user can click on the label and simultaneously toggle the checkbox without actually having to just click on the checkbox.

    I also tend to prefer sprintf() instead of concatenating long strings like the one in the foreach loop in acme_display_post_types(). It makes things a little more concise and easier to read.

    Yes – in theme and plugin development, I tend to use this, as well but in an attempt to make the code easier to read (though I know this is subjective), I just went with string concatenation. Roughly two weeks or so ago, there was a conversation around the arguments that go into sprintf after the actual strings and the confusion it causes some when reading the code.

    :shrugs:

    This is one of those issues I think has it’s advantages, but I just opted against it for the purposes of avoiding that in this example.

    At any rate, thanks again for your comments – always enjoy the reviews you leave and everything’s spot on!

Leave a Reply

Name and email address are required. Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>