自定义WordPress查询的4种方法如下:
- 通过改变query_posts($args)的参数修改主循环
- 通过WP_Query Class
- 通过filters更改query_posts()产生的SQL语句
- 通过$wpdb自定义SQL语句
目录
方法一:通过改变query_posts($args)的参数修改主循环
参考:Function Reference/query posts
query_posts( $args )是用来修改WordPress主循环(Main Loop),使用时应该谨记这一点,如果你所做的查询只是希望在文章底部显示相关文章或者在widget中显示热门文章等等,不要使用query_posts(),因为这会影响与之相关的全局变量,使得主循环中输出的信息不正确。如果一定要使用,记得在做完自己的查询后调用wp_reset_query()。
通过给query_posts()传参数,可以对主循环做一些简单的定制化,例如
<?php if ( is_home() ) { query_posts( 'cat=-3' ); } ?>
方法二:通过WP_Query Class
WP_Query是一个定义在wp-includes/query.php中的Class,query_posts()就是由WP_Query创建的$wp_query object,当然你可以创建更多的实例,这样就能有效避免对query_posts()进行修改。当然,WP_Query也具备query_posts()的特性,只需创建一个新的实例,就可以像使用query_posts()那样传参数。例如:
<?php $my_query = new WP_Query('category_name=special_cat&posts_per_page=10'); ?> <?php while ($my_query->have_posts()) : $my_query->the_post(); ?> <!-- Do special_cat stuff... --> <?php endwhile; ?>
方法三:通过filters更改query_posts()产生的SQL语句
参考文章:Custom Queries
通过query_posts() 的filters更改其产生的SQL语句,与第一种方法相比,可以做更复杂的更改,例如与其它数据库表进行联合查询、更改select选择的字段等等。并且可以享用query_posts()带来的好处,例如分页。缺点是可能查询出一些没用的数据,占用更多内存,降低执行效率。
可用的filters有:
- posts_join
- posts_groupby
- posts_orderby
- posts_distinct
- posts_fields
- post_limits
- posts_where_paged
- posts_join_paged
- posts_request
》例如联合查询
add_filter('posts_join', 'geotag_search_join' ); function geotag_search_join( $join ) { global $geotag_table, $wpdb; if( is_search() ) { $join .= " LEFT JOIN $geotag_table ON " . $wpdb->posts . ".ID = " . $geotag_table . ".geotag_post_id "; } return $join; }
》例如改变select选择的字段,默认选择wp_posts.*
add_filter('posts_fields','my_posts_field'); function my_posts_field ($fields){ if( is_home() || is_category() ){ $fields .= ", mytable.*"; } return $fields; }
方法四:通过$wpdb自定义SQL语句
参考:Displaying Posts Using a Custom Select Query
这种方法的优势是可定制化最强最灵活,劣势是query_posts()的好处全都没了,比如分页、后台控制首页显示多少文章等等,只有使用query_posts()时分页才会有效。
$wpdb class提供了一系列查询数据库的方法,例如$wpdb->query()允许你抛开所有wordpress的sql语句定义自己的sql。这个类基于ezSQL,语法基本没什么变化,使用很方便,对SQL语句运用自如的人通过该方法可以达到最优化的查询效果。
》代码示例:
<?php $querystr = " SELECT $wpdb->posts.* FROM $wpdb->posts, $wpdb->postmeta WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = 'tag' AND $wpdb->postmeta.meta_value = 'email' AND $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' AND $wpdb->posts.post_date < NOW() ORDER BY $wpdb->posts.post_date DESC "; $pageposts = $wpdb->get_results($querystr, OBJECT); ?>
》通过运行一个自定义的SQL语句获得查询结果,结果保存在$pageposts中。
接下来将结果输出
<?php if ($pageposts) { global $post; foreach ($pageposts as $post){ setup_postdata($post); //main loop... } } else { //未找到文章 } ?>
这里调用了setup_postdata()函数,目的是使你可以正常使用the_title(), the_permalink()等模板标签。
通过上述四种方法,在wordpress里自定义查询就不是什么麻烦事了。
楼主你好
关于使用WP_Query 来生成多个排序字段该如何处理呢?
类似这样的”select *from nf_posts order by menu_order desc,id desc “
文档http://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters
里面这样写的
Multiple ‘orderby’ values using an array
产生的结果是ORDER BY post_title DESC, menu_order ASC
WordPress 4.0后正好支持你要的东西,具体你可以看下这个介绍
https://make.wordpress.org/core/2014/08/29/a-more-powerful-order-by-in-wordpress-4-0/
非常感谢
不过我使用的版本是3.8,而且升级的话可能导致其他问题
看来4.0以下的版本只能通过$wpdb Object这种方式解决了
再次感谢
是的,用$wpdb输出结构时跟WP_Query区别不太大。
另外,如果你的两个字段都是按相同顺序排列,也可以用这种啊
$query = new WP_Query( array ( ‘orderby’ => ‘menu_order title’, ‘order’ => ‘DESC’ ) );
这个貌似一直支持。
hi,solagirl 这种方式我在WP_Query文档里已经看到并测试过
下面是生成的Sql,可以看到第一个默认是ASC的,但我想要的是DESC
所以你说的”两个字段都是按相同顺序排列“是错误的,因为最后一个是按照order来排序的,其他是没有的在Mysql里默认是ASC
SELECT SQL_CALC_FOUND_ROWS Htl_posts.ID,menu_order FROM Htl_posts WHERE 1=1
AND Htl_posts.post_type = ‘product’
AND (Htl_posts.post_status = ‘publish’ OR Htl_posts.post_status = ‘private’)
ORDER BY Htl_posts.menu_order,Htl_posts.post_title DESC
LIMIT 0, 10
还是非常感谢楼主!
多谢指正,学习了
需要查看的就是这篇日志啦,记录下~