$wp_query
<?php
/**
* Loads the WordPress environment and template.
*
* @package WordPress
*/
if ( !isset($wp_did_header) ) {
$wp_did_header = true;
// Load the WordPress library.
require_once( dirname(__FILE__) . '/wp-load.php' );
// Set up the WordPress query.
wp();
// Load the theme template.
require_once( ABSPATH . WPINC . '/template-loader.php' );
}
wp-blog-header.php
if (have_posts()) : while (have_posts()) : the_post();
// Do stuff
endwhile; endif;
Always use the main query!
// Don't do this in place of the main query
$query = new WP_Query( array(
'post_type' => 'post',
'category__not_in' => array(42)
));
if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post();
// Posts, excluding category 42
endwhile; endif; wp_reset_postdata();
Do not use WP_Query in place of the main query!
The main query runs regardless, so you're just making WordPress do extra laps to the database.
category.php
if (have_posts()) : while (have_posts()) : the_post();
// Posts, excluding category 42
endwhile; endif;
function exclude_category($query) {
if (!is_admin() && $query->is_main_query() && is_archive()) {
$query->set('category__not_in', '42');
}
}
add_action('pre_get_posts', 'exclude_category');
functions.php
archive.php
pre_get_posts runs before the main query, resulting in no performance hit
Use WP_Query for secondary loops only.
Always use the wpdb class for the best efficiency and security if you need custom SQL queries.
global $wpdb;
// Echo the title of the most commented post
$posts = $wpdb->get_row("SELECT ID, post_title
FROM " . $wpdb->prefix . "posts
WHERE post_status = 'publish'
AND post_type = 'post'
ORDER BY comment_count DESC
LIMIT 0,1");
echo $posts->post_title;
WordPress doesn't cache wpdb, so you should use the Transients API
$data = get_transient('name_your_transient');
if ($data === false) {
// If transient doesn't exist or has expired, query data and set transient
$data = 'Expensive query';
set_transient('name_your_transient', $data, EXPIRATION_TIME);
}
echo $data;