The problems of get_posts() and custom post_type’s

Allright, Generally i’d not complain, I’d just make up a new Trac ticket and patch it.. But i’m seriously sick of this defect of WP_Query, A number of times i’ve just given up attempting to achieve my goal and doing it some other method which wouldnt involve hacking up everything..

The problem?

Add a new record to the WP_Posts table, with a custom post_type, now try to retrieve that post. Ah, I hear you say “Thats Easy! Just pass post_type to get_posts()” WRONG!,
Well, yes, In an ideal world, that would be the case, But no, not in this case.

First, Lets add an actual record:

<br />
$url = 'http://dd32.id.au/';<br />
$content = 'DD32 is awesome!';<br />
$datas = array('post_type' => 'custom_type', 'post_status' => 'custom_status', 'post_title' => $url, 'post_name' => $url, 'guid' => md5($url), 'post_content' => $content);<br />
wp_insert_post($datas);<br />

What have i done? Just inserted a stock standard post of type ‘custom_type’with a non-standard status. Nothing odd there.

Now, Lets retrieve that post.

First thing, Lets check that get_posts() can handle a custom post_type:

<br />
var_dump( get_posts( array('post_type' => 'custom_type') ) );<br />
---<br />
array<br />
empty<br />

Allright, That didnt work, Better check the query used:

SELECT SQL_CALC_FOUND_ROWS  wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'custom_type' AND (wp_posts.post_status = 'publish')  ORDER BY wp_posts.post_date DESC LIMIT 0, 5

Ah, It doenst like our post_status, Not a probblem, Letslet it load all status types:

<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any') ) );<br />
---<br />
array<br />
0 =><br />
object(stdClass)[132]<br />
public 'ID' => string '571' (length=3)<br />
public 'post_author' => string '2' (length=1)<br />
public 'post_date' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_date_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content' => string 'DD32 is awesome!' (length=16)<br />
public 'post_title' => string 'http://dd32.id.au/' (length=18)<br />
public 'post_category' => string '0' (length=1)<br />
public 'post_excerpt' => string '' (length=0)<br />
public 'post_status' => string 'custom_status' (length=13)<br />
public 'comment_status' => string 'open' (length=4)<br />
public 'ping_status' => string 'open' (length=4)<br />
public 'post_password' => string '' (length=0)<br />
public 'post_name' => string 'httpdd32idau' (length=12)<br />
public 'to_ping' => string '' (length=0)<br />
public 'pinged' => string '' (length=0)<br />
public 'post_modified' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_modified_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content_filtered' => string '' (length=0)<br />
public 'post_parent' => string '0' (length=1)<br />
public 'guid' => string '9b159fde538e1d5b84949ae427f50168' (length=32)<br />
public 'menu_order' => string '0' (length=1)<br />
public 'post_type' => string 'custom_type' (length=11)<br />
public 'post_mime_type' => string '' (length=0)<br />
public 'comment_count' => string '0' (length=1)<br />

Looks good to me, Everything seems to have been set correctly.

However, hang on, What happens when i only want to retrieve a specific item? Well, I guess we need to specify some arguements to retrieve a single record:

<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'p' => 571 ) ) );<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'page_id' => 571 ) ) );<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'name' => $url ) ) );<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'pagename' => $url ) ) );<br />

One of those should return something.. Right? Well.. Lets look:

<br />
array<br />
empty<br />
array<br />
empty<br />
array<br />
empty<br />
array<br />
empty<br />

Nope, Not a thing.. What the?

Lets go check those queries again…

<br />
8 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.ID = 571 AND wp_posts.post_type = 'post'  ORDER BY wp_posts.post_date DESC ' (length=135)<br />
1 => float 0.000998020172119<br />
2 => string 'get_posts' (length=9)<br />
9 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.ID = 571 AND wp_posts.post_type = 'page'  ORDER BY wp_posts.post_date DESC ' (length=135)<br />
1 => float 0.00107502937317<br />
2 => string 'get_posts' (length=9)<br />
10 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_name = 'httpdd32idau' AND wp_posts.post_type = 'post'  ORDER BY wp_posts.post_date DESC ' (length=153)<br />
1 => float 0.00149297714233<br />
2 => string 'get_posts' (length=9)<br />
11 =><br />
array<br />
0 => string 'SELECT ID, post_name, post_parent FROM wp_posts WHERE post_name = 'dd32idau' AND (post_type = 'page' OR post_type = 'attachment')' (length=129)<br />
1 => float 0.00108218193054<br />
2 => string 'get_page_by_path' (length=16)<br />
12 =><br />
array<br />
0 => string 'SELECT ID, post_name, post_parent FROM wp_posts WHERE post_name = 'dd32idau' AND (post_type = 'page' OR post_type = 'attachment')' (length=129)<br />
1 => float 0.000935077667236<br />
2 => string 'get_page_by_path' (length=16)<br />
13 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND (wp_posts.ID = '0') AND wp_posts.post_type = 'page'  ORDER BY wp_posts.post_date DESC ' (length=137)<br />
1 => float 0.000837087631226<br />
2 => string 'get_posts' (length=9)<br />

Well, Let me first say, No idea why the last case has caused 3 queries (which are near unique), But thats not the interesting part.. Notice the post_type? Its no longer set to our requested ‘custom_type‘ oops, Lets go back and check that code, Wait! I did specify it!.

Eugh. Thank you WP_Query, Of course you know better than I do, Sorry i questioned your judgement and requested something else!

Time to hook in and tell WP_Query I know best..

<br />
function stupid_post_type_custom_type($query) {<br />
if ( isset($query-&gt;query_vars['post_type']) &amp;&amp; 'custom_type' == $query-&gt;query_vars['post_type'] )<br />
$query-&gt;is_page = $query-&gt;is_single = $query-&gt;is_attchment = false;<br />
}<br />
$url = 'http://dd32.id.au/';</p>
<p>add_action('parse_query', 'stupid_post_type_custom_type', 10, 1);<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'p' => 571 ) ) );<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'page_id' => 571 ) ) );<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'name' => $url ) ) );<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'pagename' => $url ) ) );<br />
remove_action('parse_query', 'stupid_post_type_custom_type', 10, 1);<br />

WooHoo!

<br />
array<br />
0 =><br />
object(stdClass)[131]<br />
public 'ID' => string '571' (length=3)<br />
public 'post_author' => string '2' (length=1)<br />
public 'post_date' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_date_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content' => string 'DD32 is awesome!' (length=16)<br />
public 'post_title' => string 'http://dd32.id.au/' (length=18)<br />
public 'post_category' => string '0' (length=1)<br />
public 'post_excerpt' => string '' (length=0)<br />
public 'post_status' => string 'custom_status' (length=13)<br />
public 'comment_status' => string 'open' (length=4)<br />
public 'ping_status' => string 'open' (length=4)<br />
public 'post_password' => string '' (length=0)<br />
public 'post_name' => string 'httpdd32idau' (length=12)<br />
public 'to_ping' => string '' (length=0)<br />
public 'pinged' => string '' (length=0)<br />
public 'post_modified' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_modified_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content_filtered' => string '' (length=0)<br />
public 'post_parent' => string '0' (length=1)<br />
public 'guid' => string '9b159fde538e1d5b84949ae427f50168' (length=32)<br />
public 'menu_order' => string '0' (length=1)<br />
public 'post_type' => string 'custom_type' (length=11)<br />
public 'post_mime_type' => string '' (length=0)<br />
public 'comment_count' => string '0' (length=1)<br />
array<br />
0 =><br />
object(stdClass)[133]<br />
public 'ID' => string '571' (length=3)<br />
public 'post_author' => string '2' (length=1)<br />
public 'post_date' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_date_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content' => string 'DD32 is awesome!' (length=16)<br />
public 'post_title' => string 'http://dd32.id.au/' (length=18)<br />
public 'post_category' => string '0' (length=1)<br />
public 'post_excerpt' => string '' (length=0)<br />
public 'post_status' => string 'custom_status' (length=13)<br />
public 'comment_status' => string 'open' (length=4)<br />
public 'ping_status' => string 'open' (length=4)<br />
public 'post_password' => string '' (length=0)<br />
public 'post_name' => string 'httpdd32idau' (length=12)<br />
public 'to_ping' => string '' (length=0)<br />
public 'pinged' => string '' (length=0)<br />
public 'post_modified' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_modified_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content_filtered' => string '' (length=0)<br />
public 'post_parent' => string '0' (length=1)<br />
public 'guid' => string '9b159fde538e1d5b84949ae427f50168' (length=32)<br />
public 'menu_order' => string '0' (length=1)<br />
public 'post_type' => string 'custom_type' (length=11)<br />
public 'post_mime_type' => string '' (length=0)<br />
public 'comment_count' => string '0' (length=1)<br />
array<br />
0 =><br />
object(stdClass)[133]<br />
public 'ID' => string '571' (length=3)<br />
public 'post_author' => string '2' (length=1)<br />
public 'post_date' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_date_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content' => string 'DD32 is awesome!' (length=16)<br />
public 'post_title' => string 'http://dd32.id.au/' (length=18)<br />
public 'post_category' => string '0' (length=1)<br />
public 'post_excerpt' => string '' (length=0)<br />
public 'post_status' => string 'custom_status' (length=13)<br />
public 'comment_status' => string 'open' (length=4)<br />
public 'ping_status' => string 'open' (length=4)<br />
public 'post_password' => string '' (length=0)<br />
public 'post_name' => string 'httpdd32idau' (length=12)<br />
public 'to_ping' => string '' (length=0)<br />
public 'pinged' => string '' (length=0)<br />
public 'post_modified' => string '2008-11-12 16:47:06' (length=19)<br />
public 'post_modified_gmt' => string '2008-11-12 05:47:06' (length=19)<br />
public 'post_content_filtered' => string '' (length=0)<br />
public 'post_parent' => string '0' (length=1)<br />
public 'guid' => string '9b159fde538e1d5b84949ae427f50168' (length=32)<br />
public 'menu_order' => string '0' (length=1)<br />
public 'post_type' => string 'custom_type' (length=11)<br />
public 'post_mime_type' => string '' (length=0)<br />
public 'comment_count' => string '0' (length=1)<br />
array<br />
empty<br />

Wait!, Why is that last case still returning nothing?

Query time again..

<br />
8 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.ID = 571 AND wp_posts.post_type = 'custom_type'  ORDER BY wp_posts.post_date DESC ' (length=142)<br />
1 => float 0.00179696083069<br />
2 => string 'get_posts' (length=9)</p>
<p>11 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.ID = 571 AND wp_posts.post_type = 'custom_type'  ORDER BY wp_posts.post_date DESC ' (length=142)<br />
1 => float 0.000961065292358<br />
2 => string 'get_posts' (length=9)<br />
12 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_name = 'httpdd32idau' AND wp_posts.post_type = 'custom_type'  ORDER BY wp_posts.post_date DESC ' (length=160)<br />
1 => float 0.00102686882019<br />
2 => string 'get_posts' (length=9)<br />
13 =><br />
array<br />
0 => string 'SELECT ID, post_name, post_parent FROM wp_posts WHERE post_name = 'dd32idau' AND (post_type = 'page' OR post_type = 'attachment')' (length=129)<br />
1 => float 0.00131893157959<br />
2 => string 'get_page_by_path' (length=16)<br />
14 =><br />
array<br />
0 => string 'SELECT ID, post_name, post_parent FROM wp_posts WHERE post_name = 'dd32idau' AND (post_type = 'page' OR post_type = 'attachment')' (length=129)<br />
1 => float 0.00103116035461<br />
2 => string 'get_page_by_path' (length=16)<br />
15 =><br />
array<br />
0 => string ' SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND (wp_posts.ID = '0') AND wp_posts.post_type = 'custom_type'  ORDER BY wp_posts.post_date DESC ' (length=144)<br />
1 => float 0.00140690803528<br />
2 => string 'get_posts' (length=9)<br />

Ok, Seems using ‘pagename’query parameter just isnt going to work, It’s been hard coded to work off ‘page’or ‘attachment’regardless, And when it finally does fall through to using custom_type.. It’s forgotten it was using pagename, and instead, is trying to use an ID..

Moral of the story? the parse_query hook is your friend; But make sure to only modify those queries which you’re using, and not all the core WP_Query queries too..

The working code:

<br />
function stupid_post_type_custom_type($query) {<br />
if ( isset($query->query_vars['post_type']) &amp;amp;&amp;amp; 'custom_type' == $query->query_vars['post_type'] )<br />
$query->is_page = $query->is_single = $query->is_attchment = false;<br />
}<br />
$url = 'http://dd32.id.au/';</p>
<p>add_action('parse_query', 'stupid_post_type_custom_type', 10, 1);<br />
var_dump( get_posts( array('post_type' => 'custom_type', 'post_status' => 'any', 'name' => $url ) ) );<br />
remove_action('parse_query', 'stupid_post_type_custom_type', 10, 1);<br />

EDIT: ARGH. Ok, WP/the Syntax Highlighter plugin have had a war, They dont like the idea of not touching stuff within the sourcecode shortcode.. I’m pretty sure i had a Trac ticket for that….

One thought on “The problems of get_posts() and custom post_type’s

  1. Boy … “God Sent” is what you are. Truly.
    I just read your “Hide Category” in [wp-hackers] and really liked your writing style. (“Experts” very often become cryptic … not suggesting malice, just that they rush and write for others like them.) So I came by to snoop your blog, and found this.
    Made my day!

    I’ve been hacking WP for a while; nothing substantial, just figuring it out … I’m working towards a frighteningly complex project.
    Thing is, I never feel I know what I’m doing … it’s not a regular programming environment and I always feel I’m blind.

    What you’d shown on this page?
    Just what I was looking for!
    I’m working up an OS proposal for SourceForge … a user generated news site (“yet another”? *grin*) so might be in touch.

    thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

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>