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->query_vars['post_type']) && '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', '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; '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….
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!