Include drafts in internal link dialog

Ok, so I’m doing a new project and we’re going to be using WordPress as a magazine CMS. In some cases we’ll have a cluster of articles about a topic and it will be natural to link from one article to another. So, here we are in final edit in WP.
We want to add a link from one draft article to another draft article in the cluster, but the target article hasn’t been published, so WP doesn’t show it in the Link to Existing Content box. Sure, I can get the shortlink for the draft of the article I want to link to, but then I need to open that tab, get the shortlink (or the draft’s slug), move back to the post that I want to link from, add the link. Doing this occasionally is fine but as a constant task it’s crappy workflow.

Now, we can simply publish and then hurriedly go through the articles and link things, but that’s suboptimal. I can’t imagine all of the magazines and other sites that do periodical publishing with WP do that though. I’ll play with Editflow to see if it has a way to deal with this, but does anyone know of a way to link from one draft to another and have the link be correct when they’re both published?

And yes, I know I can link things up after publishing. See ‘crappy workflow’.

Solutions Collecting From Web of "Include drafts in internal link dialog"

This is very similar to this question.

We have to hook into check_ajax_referer to address the internal linking feature only. Then we register an action for pre_get_posts to extend the search to drafts and pending posts.

We will still get no pretty permalinks, because they are excluded in get_permalink. So we register a filter for that too and ask WordPress again for a permalink, but with a faked post status.

As code:

add_action( 'check_ajax_referer', 'internal_links_for_drafts' );

/**
 * Extend search for internal links to 'draft' and 'pending' statuses.
 *
 * @wp-hook check_ajax_referer
 * @wp-hook pre_get_posts
 * @param string|WP_Query $var
 * @return boolean|void
 */
function internal_links_for_drafts( $var )
{
    if ( 'check_ajax_referer' === current_filter() && 'internal-linking' === $var )
        return add_action( 'pre_get_posts', __FUNCTION__ );

    // now we are in the 'pre_get_posts' action.
    $var->set( 'post_status', array( 'publish', 'pending', 'draft' ) );
    remove_action( 'pre_get_posts', __FUNCTION__ );
    add_filter( 'post_link', 'draft_permalink', 10, 2 );
}
/**
 * Get permalink for drafts and pending posts.
 *
 * Dangerous, because their title can still change.
 *
 * @param  string $permalink
 * @param  object $post
 * @return string
 */
function draft_permalink( $permalink, $post )
{
    remove_filter( current_filter(), __FUNCTION__ );

    // swap status temporary
    $original_status   = $post->post_status;
    $post->post_status = 'publish';
    $url               = get_permalink( $post );
    $post->post_status = $original_status;

    return $url;
}