I have the following code:
<?php $pages = get_pages('exclude=10'); ?>
<?php foreach ( $pages as $page ) : ?>
<?php echo $page->post_title; ?>
<?php endforeach; ?>
I would like to exclude page id 10, but I would still like to include its subpages.
However if I try to include them with the include parameter, they still don’t show up.
There are several default ways wp query to get child pages of current page. but I will prefer this. You can use WordPress get_results() function and write an SQL query like this
global $wpdb;
$child_pages = $wpdb->get_results("
SELECT * FROM {$wpdb->posts} AS p
WHERE p.post_type LIKE 'page'
AND p.post_parent LIKE 0
AND p.id NOT IN (
SELECT post_parent
FROM {$wpdb->posts} AS p
WHERE p.post_type = 'page'
AND p.post_parent != '0'
GROUP BY post_parent
)
");
I am currently running the following query on my WordPress website:
PHP:
function get_details($key, $post_id) {
global $wpdb;
$values = $wpdb->get_results( "SELECT meta_value FROM {$wpdb->prefix}new_post_meta WHERE meta_key = '{$key}' AND post_id = '{$post_id}' LIMIT 1" );
return $values[0]->meta_value;
}
ON PAGE:
<?php echo get_details('facebook_url', $post_id); ?>
It is a new custom table which works in the same way as the WP posts meta.
This is run 20 + times on the page so I was wondering if there's a better way to do this?
Currently running the query direct in the database it takes 0.5128 sec and the database table is 36MB in size.
The query is really slowing the site down.
Thanks to shadow for stating the obvious but it worked:
public function get_meta_data() {
$meta_keys = array(
//META KEYS GO HERE IN ARRAY
);
$mks = implode("', '", $meta_keys);
//Get Results
global $wpdb;
$results = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->prefix}resorts_meta WHERE meta_key IN ('{$mks}') AND post_id = '{$this->id}'", OBJECT_K );
foreach($results as $key => $value) {
$this->$key = $value->meta_value;
}
return "SELECT meta_key, meta_value FROM {$wpdb->prefix}new_post_meta WHERE meta_key IN ('{$mks}') AND post_id = '{$this->id}'";
I then created a function to display the results in $this->variables like so:
public function get_meta( $key ) {
return $this->$key;
}
And then stored get_meta_data in the construct function.
Thanks Shadow.
I am trying to build a search system. I used a mySQL system but I have little experience and I do not quite get it.
I want to search by the field in the database called post_title and then get the URL, date
I would also like to be able to search by tags. For that we need to join the table wp_term_relationships which will give us a column with post id's in it and a column with tag id's. From that we can then work out which tags apply.
My attempt failed miserably with FATAL ERROR
<?php
$proto = $_GET['proto'];
$terms = $_GET['f'];
if($proto == 'inline'){
$searchpattern = mysql_real_escape_string(strtoupper($terms));
$list = mysql_query("SELECT id,
post_title, post_date
FROM wp_posts
WHERE post_title LIKE '%$searchpattern%'
)
ORDER BY post_date;");
while ($row = mysql_fetch_array($list)) {
$title = $row['post_title'];
$date = $row['post_date'];
$url = $row['guid'];
$date = date($date, 'd M Y');
$return .= '<li>
'.$firstname.' '.$lastname.'<br /><span style="font-size:10px; color:#555;">'.$email.'</span>
</li>
<div class="title"><b>SEARCH RESULTS</b></div>
<img src=""/>'. $title .' - <span>'. $date .'</span>';
}
}
?>
$list = mysql_query("SELECT id, post_title, post_date
FROM wp_posts
WHERE post_title LIKE '%$searchpattern%') ORDER BY post_date;");
You have unexpected ")" before the "ORDER" operator.
You have an open bracket before the ORDER BY. Maybe that's what causing the problem
I have been presented with this code. The code displays the title headings of the latest 10 WordPress posts from the database. What I need to do is to eliminate a particular category from this. Can anyone help?
<?php require_once 'news/wp-config.php';
$howMany = 0;
$query ="SELECT `ID`, `post_title`,'post_category', `guid`,SUBSTRING_INDEX(`post_content`, ' ', 100) AS `post_excerpt` FROM $wpdb->posts WHERE `post_status`= \"publish\" AND `post_type` = \"post\" ";
$posts = $wpdb->get_results($query);
$posts = array_reverse($posts);
foreach($posts as $post)
{
if($howmany<10)
{
$link = $post->guid;
echo "<li><a target='_blank' href='$link'>$post->post_title</a></li>";
$howmany++;
}
}
?>
Or, you could use a second loop, something like this :
<div>
<h3>Fresh Posts</h3>
<ul>
<?php
$my_query = new WP_Query("cat=-3&order=DESC&posts_per_page=10");
echo "<pre>"; print_r($my_query->query_vars); echo "</pre>"; // shows the variables used to parse the query
echo "<code style='width: 175px;'>"; print_r($my_query->request); echo "</code>"; // shows the parsed query
while ($my_query->have_posts()) : $my_query->the_post(); //standard loop stuff
$do_not_duplicate[] = $post->ID;?>
<li id="post-<?php the_ID(); ?>"><?php the_title(); ?></li>
<?php endwhile; ?>
</ul>
</div>
once again WP 2.8.x. Lots of good info here : WordPress loop documentation
Determine the category you don't need and add an extra AND to your WHERE clause:
AND post_category != 3
You can do it either of 2 places. The most efficient is to do it in the query:
$query ="SELECT ID, post_title, post_category, guid, SUBSTRING_INDEX(post_content, ' ', 100) AS `post_excerpt`
FROM $wpdb->posts
WHERE post_status= 'publish'
AND post_type = 'post'
AND post_category!= 'unwanted string' ";
The other place to do it, if for some reason you need all the results, but you want to use the unwanted category somewhere else, is when you retrieve the results:
if($howmany<10 && post['post_category']!='unwanted string') {
'Noticeboard' is the name of the category i want to eliminate. but if i write that, it dispalys a parse error.
Because you must insert the category ID in the query, not the category name.
To get that, just watch in the database wp_categories table.
Some links about wordpress database:
http://blog.kapish.co.in/2008/01/18/wordpress-database-schema/
http://wpbits.wordpress.com/2007/08/08/a-look-inside-the-wordpress-database/
Anyway, I think it's more hard than this. Look at post2cat table.
So, you have to do a subquery.
I am not sure which WP version you are using, so this 'answer' has a few caveats.
Caveat 1 : This is not a complete answer, more like a pointer
Caveat 2 : The query below works with WP 2.8.x so YMMV
The query below shows how to link posts back to their categories. You can use the NOT IN mySQL operator to exclude the category you do not want by its ID
SELECT
wp_posts.*
FROM
wp_posts
INNER JOIN
wp_term_relationships
ON
(wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN
wp_term_taxonomy
ON
(wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
WHERE
wp_term_taxonomy.taxonomy = 'category'
AND
wp_term_taxonomy.term_id NOT IN ('3')
AND
wp_posts.post_type = 'post'
AND
(wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future')
GROUP BY
wp_posts.ID
ORDER BY
wp_posts.post_date
DESC
The line breaks and indenting are idiosyncratic, but (hopefully) make it easier for you to see what is going on with this query.
I hope this helps.
I'm wanting to order Wordpress posts by the most recent comment. To the best of my knowledge this isn't possible using the WP_Query object, and would require a custom $wpdb query, which I can easily write. However, I then don't know how to setup the loop to run off this object.
Can anyone help?
Assign
select wp_posts.*, max(comment_date) as max_comment_date
from $wpdb->posts wp_posts
right join $wpdb->comments
on id = comment_post_id
group by ID
order by max_comment_date desc
limit 10
to some variable $query. You can fiddle around with the 10 or the query itself. (I'm no SQL optimization ninja.) Then your code will look something like
<?php
$results = $wpdb->get_results($query) or die('!');
foreach ($results as $result):
?>
[insert template here]
<?php endforeach ?>
This pattern is covered in more depth by the Codex.
I used a simpler, portion of a native WP in function. hope it helps and some one can continue to develop. Here is a simplified version that shows the title & excerpt of the post along with the comment content & author from the latest commented posts using get_comments.
$args = array(
'status' => 'approve',
'number' => 6,
'order' => 'DESC'
);
$comments = get_comments($args);
foreach($comments as $comment) : $count++;
$post_args = array(
'post_type' => 'post',
'p' => $comment->comment_post_ID,
'posts_per_page' => 1
);
$posts = get_posts($post_args);
foreach($posts as $post) : setup_postdata($post);
the_title();
the_excerpt();
endforeach;
echo $comment->comment_content;
echo $comment->comment_author;
endforeach;
OK guys,
A lot of great answers here, but obviously nobody's taken the time to test them.
Hao Lian gets the credit for the first best original answer, but unfortunately his code doesn't show posts without comments.
Captain Keytar is on the right track, but his code will display every single post and attachment as a separate result.
Here is a modified version of Captain Keytar but it limits the results to the type 'post'.. that has been published (to avoid getting drafts!!)
select wp_posts.*,
coalesce(
(
select max(comment_date)
from $wpdb->comments wpc
where wpc.comment_post_id = wp_posts.id
),
wp_posts.post_date
) as mcomment_date
from $wpdb->posts wp_posts
where post_type = 'post'
and post_status = 'publish'
order by mcomment_date desc
limit 10
This is an old question, but I had the same issue and found a much cleaner way to do this, so I'm posting it here in case it helps anyone.
If you use the posts_clauses filter you can then just modify the main query and still use The Loop and all the regular loop functions.
function intercept_query_clauses( $pieces ) {
global $wpdb;
$pieces['fields'] = "wp_posts.*,
(
select max(comment_date)
from " . $wpdb->comments ." wpc
where wpc.comment_post_id = wp_posts.id AND wpc.comment_approved = 1
) as mcomment_date";
$pieces['orderby'] = "mcomment_date desc";
return $pieces;
}
add_filter( 'posts_clauses', 'intercept_query_clauses', 20, 1 );
Note that I changed the sql slightly for my own purposes, but the general concept is the same.
As an addendum to Hao Lian's answer, if you use the following query:
select wp_posts.*,
coalesce(
(
select max(comment_date)
from $wpdb->comments wpc
where wpc.comment_post_id = wp_posts.id
),
wp_posts.post_date
) as mcomment_date
from $wpdb->posts wp_posts
order by mcomment_date desc
limit 10
This mixes in posts that don't have comments yet, and sorts them by post_date and max(comment_date).
Code suggested by Hao Lian works perfect except for the fact that we should add the following WHERE clause to avoid pulling POST with comment_count = 0, this situation is caused by spam comments.
The WHERE clause to add is as follows:
WHERE comment_approved = '1' AND comment_type = '' AND post_password = ''
Complete code after adding the where clause shoud look like following:
select wp_posts.*, max(comment_date) as comment_date
from wp_posts
right join wp_comments on id = comment_post_id
WHERE comment_approved = '1' AND comment_type = '' AND post_password = ''
group by ID
order by comment_date desc
limit 6
This can be done by combining WP_Comment_Query with WP_Query, like this:
// For performance, limit the number of queried comments,
// but make it be something big enough to account for "duplicate" posts.
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( array( 'number' => '100' ) );
if ( $comments ) {
foreach ( $comments as $comment ) {
// You'll want to convert the dates from string to integer so you can sort them out later
$comment_utf = strtotime($comment->comment_date);
// Build an array of post IDs with the date of the last published comment
$latest_comments[$comment->comment_post_ID] = $comment_utf;
}}
// Sort the array by date
arsort($latest_comments); foreach ($latest_comments as $key => $value) { $posts_ordered[] = $key; }
// The nice thing is that WP_Query will remove duplicates by default
$args = array ( 'posts_per_page' => '10', 'post__in' => $posts_ordered, 'orderby' => 'post__in');
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
// Do your stuff (add the template or whatever)
// If you want to add the comment itself, use this:
$comments = get_comments(array('number' => '1', 'post_id' => $post->ID));
foreach($comments as $comment) :
echo $comment->comment_content;
endforeach;
// That's about it
}}
wp_reset_postdata();
I'm thinking that adding in the max function will screw up your results. MySQL isn't going to pull the max from each one. It's going to pull the max from the full set. This is the query that'll get you your results:
select wp_posts.*, comment_date
from $wpdb->posts wp_posts
right join $wpdb->comments
on id = comment_post_id
group by ID
order by comment_date desc
limit 10
After that, if you want to follow WP convention, use this, and then you can use the functions that most of your templates are using (based on the loop):
$results = $wpdb->get_results($query) or die('!');
foreach ($results as $post):
setup_postdata($post);
Get 3 newest comments for custom post type 'question' regardless of approvement:
global $wpdb;
$results = $wpdb->get_results(
"
SELECT wp_posts.ID, MAX(comment_date) AS max_comment_date
FROM wp_posts
RIGHT JOIN wp_comments
ON id = comment_post_id
WHERE wp_posts.post_type = 'question'
AND wp_posts.post_status = 'publish'
GROUP BY ID
ORDER BY max_comment_date DESC
LIMIT 3
"
);
foreach ($results as $result) {
$posts_arr[] = $result->ID;
}
$args = array(
'post_type' => 'question',
'post__in' => $posts_arr,
'orderby' => 'post__in',
);
$the_query = new WP_Query( $args );
Using Lucian's BEAUTIFUL solution, I needed to alter/filter the existing WP_Query to sort posts by the latest comment. Here's the code, tested & works perfectly:
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( array( 'number' => '100' ) );
if ( $comments ) {
foreach ( $comments as $comment ) {
$comment_utf = strtotime($comment->comment_date);
$latest_comments[$comment->comment_post_ID] = $comment_utf;
}
// Sort the array by date
arsort( $latest_comments );
foreach( $latest_comments as $key => $value ) {
$posts_ordered[] = $key;
}
$query->set( 'post__in', $posts_ordered );
$query->set( 'orderby', 'post__in' );
}