Enforcing the show_ui argument for post types

Since [34177], the show_ui argument for post types is now enforced to correct unexpected behaviour whereby the post type listing screen and post editing screen for post types with show_ui set to false were still accessible via a manually entered URL.

There’s a small chance this may have an effect on your plugin or website if it’s relying on the fact that these screens were accessible. If this is the case, you should correct the arguments for your post type by setting show_ui to true, and then setting show_in_menu, show_in_nav_menus, and show_in_admin_bar to false, as appropriate.

#4-4, #dev-notes, #post-types

Comments are now turned off on pages by default

In [33041] and [33054] for #31168, we’ve turned comments off on new pages by default.

I know many of you have done the “make a bunch of pages, fill them out, realize comments are turned on, go back into the admin, turn off comments” dance. Now when you make a page, you won’t have to manually turn off comments — it’ll match the expected behavior of being off by default.

In addition to pages, this functionality has been extended to all custom post types. Post registrations that don’t explicitly add support for comments will now default to comments being off on new posts of that type (before, they defaulted to on). Up until now, post type support for comments has only affected admin UI; a developer could omit comment support on registration but still allow comments to be posted. This is a change in behavior, and we will be closely monitoring its effects during beta. Moving to explicit support will allow core behavior to be more predictable and robust in the future, but we will always consider real-world usage.

In trunk, you’ll notice two new things: the get_default_comment_status() function, which accepts the post type and comment type as arguments (both optional), and within it a get_default_comment_status filter, which receives the status, post type, and comment type as arguments. If you’ve been directly checking options such as with get_option( 'default_comment_status' ), you will likely want to replace those calls with get_default_comment_status(). We recommend explicit registration of post type support for comments, but as an example of using the filter, you can restore current behavior using the following:

 * Filter whether comments are open for a given post type.
 * @param string $status       Default status for the given post type,
 *                             either 'open' or 'closed'.
 * @param string $post_type    Post type. Default is `post`.
 * @param string $comment_type Type of comment. Default is `comment`.
 * @return string (Maybe) filtered default status for the given post type.
function wpdocs_open_comments_for_myposttype( $status, $post_type, $comment_type ) {
    if ( 'myposttype' !== $post_type ) {
        return $status;

    // You could be more specific here for different comment types if desired
    return 'open';
add_filter( 'get_default_comment_status', 'wpdocs_open_comments_for_myposttype', 10, 3 );

#4-3, #comments, #dev-notes, #post-types

Potential roadmap for taxonomy meta and post relationships

In the days before the WordPress Community Summit in October, a number of contributing developers huddled together to discuss a number of long-term architecture ideas. Among them were taxonomy meta and post relationships. (Ah, I see I now have your attention!) This post is more or less a proposed roadmap. It’s an ambitious plan that is designed to take place over perhaps five or more releases.

(During WordCamp San Francisco’s keynote, @matt talked a little about a new aim to build teams of contributors and reviewers around individual core components. There will be a lot more on that in the coming days and weeks. For now, here’s a post that covers two components, post types and taxonomy.)

The discussion included all core committers at the time — @ryan, @markjaquith, @westi, @azaozz, @nacin, @dd32, @koopersmith, and @duck_ — and a number of contributing developers, including @aaroncampbell, @dh-shredder, @helen, and @scribu.

At the moment, terms are represented in WordPress using two different IDs: a term ID, and a term taxonomy ID. A term ID (and name and slug) can actually appear in multiple taxonomies, so to identify a particular term, you must have either the term ID and the corresponding taxonomy, or just the term taxonomy ID. This dates back to the original taxonomy schema in WordPress 2.3. At the time, the concept of “shared terms” seemed like it could be an important abstraction. Hindsight is 20/20, and shared terms are the bane of taxonomies in WordPress.

So when we talk about term meta, we’re actually talking about term taxonomy meta — meta associated with a term taxonomy ID, not a term ID. The problem is, the public ID used in the API and elsewhere is the term ID (and, by necessity, a taxonomy is also passed). This confusion — and the need for there to be only one object identifier in our metadata API (term taxonomy ID, not two, as in term ID and taxonomy) — has long forced us to table the discussion of term metadata.

(There are separate conceptual issues here — at what point does a term with metadata simply become a post-like object that can relate to other posts? And given post relationships, could terms and posts actually converge in their underlying schema? I’m not actually going to answer those questions in this post. Purely talking schema and architecture at this point.)

At WordCamp San Francisco last year, four of us — me, Gary Pendergast (@pento), @scribu, and @koopersmith — came up with a rather crazy way to make major changes to our table schema while still being backwards compatible. In fact, we came up with two ways to do it. This was the plan everyone heard and discussed at the summit.

It was clear that shared terms had to go. The first step is removing a UNIQUE index on the slug field in the wp_terms table. (This is dependent on #17689.) Then, we stop creating new shared terms. Step three, on an upgrade routine, we actively look for any existing shared terms and split them.

These three initial steps must happen over two to three major releases, as we’re talking about a bug fix, a schema change, an API change, and an upgrade routine — in that order.

Then comes the fun part, in yet another major release. With shared terms split, term ID and term taxonomy ID will be identical  on every install.  If we moved the slug and name fields from wp_terms to wp_term_taxonomy, we could actually drop wp_terms.

How can we remove an entire table but still be backwards compatible? We came up with two solutions:

  1. Because all fields in wp_terms will exist in wp_term_taxonomy, wp_terms can be recreated as a MySQL view to be a read-only mirror of term data, thus being compatible with all existing queries.
  2. Because all fields in wp_terms will exist in wp_term_taxonomy, and because table aliases like `t`and `tt` are always used when joining these two tables, $wpdb->terms can simply be set to $wpdb->term_taxonomy. A query that previously joined wp_terms with wp_term_taxonomy would just join itself.

In all: Using the second approach (yes, it works), it took about 20 lines of code to make WordPress run without a wp_terms table. Wow, right?

So by this point, we would finally have a sane taxonomy schema. Less joins, a cleaner API (probably helped by a new WP_Term object to model WP_Post and WP_User), no more shared terms headaches, and a single, sane ID for a single taxonomy’s term.

Once that is all finished, we can finally have term meta. Maybe. (Kidding. (Kind of.))

Where do post relationships come in? The existing Posts 2 Posts plugin by @scribu is fantastic and serves the niche well. But we’re not really comfortable making any architecture or API changes along these lines while our taxonomy schema is still in a far from ideal state.

The post relationships plugin supports posts to posts, and posts to users. Core taxonomy relationships supports posts to terms, but it can also be rigged to relate users to terms. (It also supported links to terms, yet another object type.) We didn’t fully iron out this idea yet, but one idea is to convert the current wp_term_relationships table to a more generic object relationships table, which can support posts to posts, posts to users, terms to users, and of course posts to terms (and, really, any arbitrary relationship).

A disclaimer: This post doesn’t promise anything. Do not rely on the contents of this post for future projects.  It will take us some time to lay out the proper groundwork and make sure we get this right. Do not expect this to happen in WordPress 3.7, or even 3.8. (Actually, do not expect this to happen at all.)

That said, I’m really glad to get this information out there and I’m excited to hear any feedback you may have. We are always thinking toward the future, and a lot of contributing developers have mile-long roadmaps in their heads — it’s long past time to get those on paper.

#post-types, #roadmaps, #taxonomy

CPT enhancements

I’m trying to put together a small but well-defined set of enhancements that custom post types deserve consideration in 3.1.

What I have so far is this:

  • Opt-in archive/index pages for custom post types
  • Opt-in default meta capability handling for custom post types
  • Improve the custom post status API, and make them type-specific

Beyond that, I’m also thinking about opt-in ways to get more than the default post types displayed on other views. As it is now, we currently also allow searching for pages for example, so we would more or less be extending that. You may want to allow a post type to show up on the category or tag pages, for example. The API ideally wouldn’t be more complicated than, say, register_taxonomy_for_object_type.

What are your thoughts? Let me know your pet bugs, peeves, and workarounds. (Just keep in mind we’re aiming for small, defined scope here. KISS.)