Can we have a post without a slug?

When I insert a post I’ve found that there is a slow call to wp_unique_post_slug from within insert_post (In the database I’m using to test there is 155,000 posts – live would have considerably more). As I don’t believe a slug is important for what I’m doing (a person who is browsing our site will probably never see a single page view for this post type), is there anything I can do that can either speed up the call or (better yet) eliminate it.

Looking at the code for insert_post, I couldn’t see a way of doing it without modifying core (which is something I’d rather not do). The code I’m using is:

Read More
$post = array(
    'post_title' => 'post_title',
    'post_type' => 'character',
    'post_status' => 'publish'
);
$post_id = wp_insert_post( $post );

Edit:

As it appears people are missing the information that I have written in this question. Here is the issue as clear as I can make it.

The Problem:

Slow performance. I have tracked this down to the function wp_unique_post_slug called from within wp_insert_post

The code that calls wp_insert_post:

$post = array(
    'post_title' => 'post_title',
    'post_type' => 'character',
    'post_status' => 'publish'
);

$post_id = wp_insert_post( $post );

(yes they are all strings and not variables being assigned to $post)

Other information:

The post status needs to be ‘publish’ as these posts are presented to the user (although not in the standard WordPress manner).

I could fix it by editing core, but this is a BAD idea for a number of reasons.

A slug is not important as the user shouldn’t be going to a single page view of this content type.

Related posts

2 comments

  1. I know this is really old question, but today I was dealing with something similar, and I have found a solution – if wp_unique_post_slug() calling is performance bottleneck, and post_name value is not important, then set post_name manualy to some random value.

    My wp_insert_post post action was taking too long lately (20-30s). It saves custom post type order not visible to visitors, with post_title = "Order" (post title does not matter). That resulted in thousands of posts with title “Order”, and WP was automatically generating post names (post_name) as “order-1”, “order-2”, “order-3”, … “order-6152” …

    And with every wp_insert_post WP searched for free post name starting from “order” and incrementing suffixed number – and every step was one DB query. So in my case WP did more than 6,000 DB queries before inserting one post to database.

    Setting random post_name in wp_insert_post() call disables wp_unique_post_slug() call.

  2. Source inspection -> Abort cases

    When you look at the source of wp_unique_post_slug(), then you’ll see that the first two lines are

    if ( 
        in_array( $post_status, 
            array( 'draft', 'pending', 'auto-draft' )
        )
        OR
        ( 
            'inherit' == $post_status 
            AND 'revision' == $post_type 
        )
    )
        return $slug;
    

    Which means that there’s nothing calculated, queried or processed if

    • The post status is draft, pending or auto-draft

    OR

    • The post status is inherit and the Post Type a revision

    As you can see from the source of wp_insert_post() where wp_unique_post_slug() is called, it passes the status exactly as you did.

    $post_name = wp_unique_post_slug(
        $post_name,
        $post_ID,
        $post_status,
        $post_type,
        $post_parent
    );
    

    Possible solution

    In case a post type isn’t public, but only visible from the admin UI, then you just have to ignore the post status, set it to draft, pending, whatever (when inserting the post) and you’re fine and nothing will be processed.

    Every other attempt will fail as $wpdb->get_var() has no filter.

    MAYBE… solution

    You can still use a drop in. A replacement for the $wpdb class/object. Just copy the contents of ~/wp-includes/wp-db.php into a new file named db.php and place it into your ~/wp-content (or whatever you named it) folder.

    Then modify $wpdb->get_var() to abort in case it is called from the context of wp_unique_post_slug(). Then it depends on your creativity and skills if it’s faster to abort that.

    Keep in mind that you’ll have to update that file every time there is a core update.

    Notes:

    • If you leave the post_status argument empty, it automatically assigns draft.
    • For post post types, when no category is assigned, it automatically gets assigned the default category. But only if the post status isn’t auto-draft.
    • If post_date_gmt is empty and you’re adding a draft, then the value will automatically be set to '0000-00-00 00:00:00'.
    • If the post_name (title) is empty and the status is draft, auto-draft or pending, then the title will not get sanitized.
    • Don’t set a publish date for now or earlier, as the status will get converted to “future” (in case the status still is “publish”).

Comments are closed.