WIKI使用導(dǎo)航
站長百科導(dǎo)航
站長專題
- 網(wǎng)站推廣
- 網(wǎng)站程序
- 網(wǎng)站賺錢
- 虛擬主機(jī)
- cPanel
- 網(wǎng)址導(dǎo)航專題
- 云計算
- 微博營銷
- 虛擬主機(jī)管理系統(tǒng)
- 開放平臺
- WIKI程序與應(yīng)用
- 美國十大主機(jī)
WordPress:Custom Queries
Plugins generally extend the functionality of WordPress by adding Hooks (Actions and Filters) that change the way WordPress behaves. But sometimes a plugin needs to go beyond basic hooks by doing a custom query, and it's not as simple as just adding one filter or action to WordPress. This article describes what custom queries are, and then explains how a plugin author can implement them.
插件一般通過添加Hooks (Actions and Filters)擴(kuò)展WordPress的功能,hooks更改了WordPress的行為方式。但是,有時,插件通過自定義查詢,需要進(jìn)入基本的hooks之外的hooks,而且這個操作并不像將一個filter或者action添加到WordPress那樣簡單。這篇文章描述了自定義查詢是什么,然后解釋了插件作者可以怎樣地執(zhí)行查詢。
A few notes:
一些注意事項(xiàng):
- This article assumes you are already familiar with the basics of WordPress:Writing a Plugin, as well as WordPress:Creating Tables with Plugins (if applicable for your plugin), the WordPress:Plugin API for Actions and Filters, PHP, and the MySQL database query language.
- 這篇文章假定你已經(jīng)熟悉了編寫插件,和使用插件創(chuàng)建表格(如果對你的插件適用),Actions 和Filters的插件API,PHP和MySQL數(shù)據(jù)庫查詢語言的基本知識。
- This article applies only to the viewer-facing blog pages, not the administration screens (although some of what you do may affect administration screens that lists posts as well).
- 這篇文章只適用于訪客界面的博客頁面,而不是管理界面(雖然你執(zhí)行的一些操作也可能影響列有文章的管理界面)。
- All file names mentioned are relative to the root WordPress directory.
- 所有提及的文件名與WordPress根目錄相關(guān)。
Background Information[ ]
背景信息[ ]
Definitions[ ]
定義[ ]
In the context of this article, query refers to the database query that WordPress uses in the Loop to find the list of posts that are to be displayed on the screen ("database query" will be used in this article to refer to generic database queries). By default, the WordPress query searches for posts that belong on the currently-requested page, whether it is a single post, single static page, category archive, date archive, search results, feed, or the main list of blog posts; the query is limited to a certain maximum number of posts (set in the Options admin screens), and the posts are retrieved in reverse-date order (most recent post first). A plugin can use a custom query to override this behavior. Examples: 根據(jù)這篇文章的語境,查詢指的是WordPress在Loop中使用的數(shù)據(jù)庫查詢,查找界面上顯示的文章列表("數(shù)據(jù)庫查詢" 在這篇文章中用作一篇的數(shù)據(jù)庫查詢)。默認(rèn)情況下,WordPress查詢搜索當(dāng)前請求的網(wǎng)頁上的文章,不管是單篇文章,還是單個的靜態(tài)網(wǎng)頁,類別歸檔,日期歸檔,搜索結(jié)果,feed,或者博客文章的主要列表;查詢限制為最多數(shù)目的文章(設(shè)置在選項(xiàng)管理界面),文章以日期相反順序返回(首先是最近的文章)。插件可以使用自定義查詢?nèi)∠@個操作。例如:
- Display posts in a different order, such as alphabetically for a "glossary" category.
- 以不同的順序顯示文章,例如按字母表順序顯示"術(shù)語表"類別。
- Override the default number of posts to be displayed on the page; for example, the glossary plugin might want to have a higher post limit when displaying the glossary category.
- 取消網(wǎng)頁上顯示的文章的默認(rèn)數(shù)目;如,術(shù)語插件顯示術(shù)語類別的時候,可能想要顯示更多的文章。
- Exclude certain posts from certain pages; for example, posts from the glossary category might be excluded from the home page and archive pages, and appear only on their own category page.
- 從某個網(wǎng)頁刪除某篇文章;例如,術(shù)語類別中的文章可能從主頁,歸檔頁面上刪除,只出現(xiàn)在自身的類別頁面上。
- Expand the default WordPress keyword search (which normally just searches in post title and content) to search in other fields, such as the city, state, and country fields of a geographical tagging plugin.
- 擴(kuò)展WordPress默認(rèn)關(guān)鍵詞搜索(一般只在文章標(biāo)題和內(nèi)容中搜索),在其它欄中搜索,如地理標(biāo)題插件中對城市,州,區(qū)的搜索。
- Allow custom URLs such as example.com/blog?geostate=oregon or example.com/blog/geostate/oregon to refer to the archive of posts tagged with the state of Oregon.
- 允許自定義URLs,如example.com/blog?geostate=oregon 或者example.com/blog/geostate/oregon指代已標(biāo)記的文章的歸檔,標(biāo)記為俄勒岡州。
Default WordPress Behavior[ ]
WordPress 默認(rèn)操作[ ]
Before you try to change the default behavior of queries in WordPress, it is important to understand what WordPress does by default. There is an overview of the process WordPress uses to build your blog pages, and what a plugin can do to modify this behavior, in WordPress:Query Overview.
在你嘗試更改WordPress中的查詢的默認(rèn)操作之前,了解WordPress有那些默認(rèn)操作,很重要。在查詢概述中有個概述,關(guān)于WordPress創(chuàng)建你的博客頁面的過程,以及可以使用哪個插件來更改這個操作。
Implementing Custom Queries[ ]
執(zhí)行自定義查詢[ ]
Now we're ready to start actually doing some custom queries! This section of the article will use several examples to demonstrate how query modification can be implemented. We'll start with a simple example, and move on to more complex ones.
現(xiàn)在我們開始真正地進(jìn)行一些自定義查詢了!文章的這個部分,使用幾個例子,解釋了怎樣操作自定義查詢。我們從一個簡單的例子開始,再慢慢的進(jìn)入復(fù)雜的例子。
Display Order and Post Count Limit[ ]
顯示順序和文章數(shù)目限制[ ]
For our first example, let's consider a glossary plugin that will let the site owner put posts in a specific "glossary" category (saved by the plugin in global variable $gloss_category). When someone is viewing the glossary category, we want to see the entries alphabetically rather than by date, and we want to see all the glossary entries, rather than the number chosen by the site owner in the options.
在我們第一個例子中,加入術(shù)語插件能夠使得站點(diǎn)所有者將文章放入特別的"術(shù)語" 類別(有插件在全局變數(shù)$gloss_category保存)。有人瀏覽術(shù)語類別的時候,我們想要根據(jù)字母表順序查看文章而不是根據(jù)日期先后,而且我們希望查看術(shù)語的所有文章,而不是站點(diǎn)所有者從選項(xiàng)中選擇的文章數(shù)目。
So, we need to modify the query in two ways:
因此,我們需要以兩種方式更改查詢:
- Add a filter to the ORDER BY clause of query to change it to alphabetical order if we are viewing the glossary category. The name of the filter is 'posts_orderby', and it filters the text after the words ORDER BY in the SQL statement.
- 如果我們正在閱讀術(shù)語類別,將filter添加到查詢的ORDER BY clause,更改為字母表順序。Filter的名稱是'posts_orderby',在SQL聲明中根據(jù)ORDER BY,過濾文本。
- Add a filter to the LIMIT clause of the query to remove the limit. This filter is called 'post_limits', and it filters the SQL text for limits, including the LIMIT key word.
- 將filter添加到查詢的LIMIT clause,移除限制。這個filter稱為'post_limits',過濾了SQL文本限制,包含LIMIT關(guān)鍵詞。
In both cases, the filter function will only make these modifications if we're viewing the glossary category (function is_category is used for that logic). So, here's what we need to do:
在兩種情況中,只有我們訪問術(shù)語類別的時候,filter函數(shù)才會做出更改(函數(shù) is_category用作那個邏輯)。因此,現(xiàn)在我們需要做的是:
add_filter('posts_orderby', 'gloss_alphabetical' ); add_filter('post_limits', 'gloss_limits' ); function gloss_alphabetical( $orderby ) { global $gloss_category; if( is_category( $gloss_category )) { // alphabetical order by post title return "post_title ASC"; } // not in glossary category, return default order by return $orderby; } function gloss_limits( $limits ) { global $gloss_category; if( is_category( $gloss_category )) { // remove limits return ""; } // not in glossary category, return default limits return $limits; }
add_filter('posts_orderby', 'gloss_alphabetical' ); add_filter('post_limits', 'gloss_limits' ); function gloss_alphabetical( $orderby ) { global $gloss_category; if( is_category( $gloss_category )) { // 根據(jù)文章標(biāo)題的字母順序 返回 "post_title ASC"; } // 不要術(shù)語類別中,返回默認(rèn)順序 返回$orderby; } function gloss_limits( $limits ) { global $gloss_category; if( is_category( $gloss_category )) { // 移除限制 返回 ""; } // 不再術(shù)語類別,返回默認(rèn)限制 返回 $limits; }
Category Exclusion[ ]
刪除類別[ ]
To continue with the glossary plugin, we also want to exclude glossary entries from appearing on certain screens (home, non-category archives) and feeds. To do this, we will add a 'pre_get_posts' action that will detect what type of screen was requested, and depending on the screen, exclude the glossary category. We'll also use the fact that in the query specification (which is stored in $wp_query->query_vars, see above), you can put a "-" sign before a category index number to exclude that category. So, here is the code:
繼續(xù)使用術(shù)語插件,我們也希望從某些界面上刪除術(shù)語文章(主頁,非類別歸檔)和feeds。這樣,我們需要添加'pre_get_posts' action,這個action會查看需要哪種類型的界面,根據(jù)界面,刪除術(shù)語類別。我們也會利用這個事實(shí),在查詢規(guī)范(儲存在$wp_query->query_vars, 請看看上面的),在類別索引數(shù)字執(zhí)行類別的時候,你可以先放置"-"符號。下面是代碼:
add_action('pre_get_posts', 'gloss_remove_glossary_cat' ); function gloss_remove_glossary_cat( $notused ) { global $wp_query; global $gloss_category; // Figure out if we need to exclude glossary - exclude from // archives (except category archives), feeds, and home page if( is_home() || is_feed() || ( is_archive() && !is_category() )) { $wp_query->query_vars['cat'] = '-' . $gloss_category; } }
add_action('pre_get_posts', 'gloss_remove_glossary_cat' ); function gloss_remove_glossary_cat( $notused ) { global $wp_query; global $gloss_category; // 了解我們是否需要刪除術(shù)語-刪除 //歸檔(類別歸檔除外), feeds, 和主頁 if( is_home() || is_feed() || ( is_archive() && !is_category() )) { $wp_query->query_vars['cat'] = '-' . $gloss_category; } }
Keyword Search in Plugin Table[ ]
插件表格中的關(guān)鍵詞搜索[ ]
For our next example, let's consider a geographical tagging plugin that tags each post with one or more cities, states, and countries. The plugin stores them in its own database table; we'll assume the table name is in global variable $geotag_table, and that it has fields geotag_post_id, geotag_city, geotag_state, geotag_country. For this example, the idea is that if someone does a keyword search (which normally searches the post title and post content), we also want to find posts where the keyword appears in the city, state, or country fields of our plugin's table.
在下一個例子中,假定地理標(biāo)簽插件,將每篇文章標(biāo)上一個或者多個城市,州,和區(qū)。插件將其儲存在各自的數(shù)據(jù)庫表格中;我們假定表格名是全局變量$geotag_table,而且擁有欄geotag_post_id, geotag_city, geotag_state, geotag_country。在這個例子中,如果有人進(jìn)行了關(guān)鍵詞搜索(一般搜索文章標(biāo)題和文章內(nèi)容),我們也希望搜索到我們插件表格中的城市,州,區(qū)欄中的關(guān)鍵詞的文章。
So, we are going to need to modify the SQL query used to find posts in several ways (but only if we're on a search screen):
因此,我們需要更改SQL查詢,以不同的方式搜索到文章(我們在搜索界面的時候):
- Join the plugin's table to the post table. This is done with the 'posts_join' filter, which acts on the SQL JOIN clause(s).
- 可以使用在SQL JOIN clause(s)上運(yùn)行的'posts_join' filter,將插件表格加入到文章表格中。
- Expand the WHERE clause of the query to look in the plugin table fields. This is done with the 'posts_where' filter, and we'll use the idea that whatever WordPress did to search the post title field, we'll do the same thing with our custom table fields (rather than trying to duplicate WordPress's rather complex logic). WordPress adds clauses like this: (post_title LIKE 'xyz').
- 可以使用'posts_where' filter,擴(kuò)展查詢的WHERE clause,查看插件表格欄。不管WordPress是否搜索了文章標(biāo)題欄,我們處理自定義表格欄的方式不變(不會試著復(fù)制WordPress相當(dāng)復(fù)雜的邏輯)。WordPress添加clauses,如:(post_title LIKE 'xyz')。
- Add a GROUP BY clause to the query, so that, for instance, if a post is tagged with both Portland, Oregon, and Salem, Oregon, and the viewer searches on "Oregon", we won't end up returning the same post twice. This is done with the 'posts_groupby' filter, which acts on the text after the words GROUP BY in the SQL statement.
- 將GROUP BY clause添加到查詢,這樣,如,如果一篇文章標(biāo)記為波特蘭,俄勒岡州,和塞倫,俄勒岡州,訪客搜索"俄勒岡州",我們不會兩次返回同一篇文章??梢栽赟QL聲明上,GROUP BY文本后的文本上'posts_groupby' filter操作。
With those ideas in mind, here is the code:
了解了這些后,下面有代碼:
add_filter('posts_join', 'geotag_search_join' ); add_filter('posts_where', 'geotag_search_where' ); add_filter('posts_groupby', 'geotag_search_groupby' ); 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; } function geotag_search_where( $where ) { if( is_search() ) { $where = preg_replace( "/\(\s*post_title\s+LIKE\s*(\'[^\']+\')\s*\)/", "(post_title LIKE \\1) OR (geotag_city LIKE \\1) OR (geotag_state LIKE \\1) OR (geotag_country LIKE \\1)", $where ); } return $where; } function geotag_search_groupby( $groupby ) { global $wpdb; if( !is_search() ) { return $groupby; } // we need to group on post ID $mygroupby = "{$wpdb->posts}.ID"; if( preg_match( "/$mygroupby/", $groupby )) { // grouping we need is already there return $groupby; } if( !strlen(trim($groupby))) { // groupby was empty, use ours return $mygroupby; } // wasn't empty, append ours return $groupby . ", " . $mygroupby; }
add_filter('posts_join', 'geotag_search_join' ); add_filter('posts_where', 'geotag_search_where' ); add_filter('posts_groupby', 'geotag_search_groupby' ); 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; } function geotag_search_where( $where ) { if( is_search() ) { $where = preg_replace( "/\(\s*post_title\s+LIKE\s*(\'[^\']+\')\s*\)/", "(post_title LIKE \\1) OR (geotag_city LIKE \\1) OR (geotag_state LIKE \\1) OR (geotag_country LIKE \\1)", $where ); } return $where; } function geotag_search_groupby( $groupby ) { global $wpdb; if( !is_search() ) { return $groupby; } // 我們需要對文章ID進(jìn)行分組 $mygroupby = "{$wpdb->posts}.ID"; if( preg_match( "/$mygroupby/", $groupby )) { // 我們需要的分組已經(jīng)在這里 return $groupby; } if( !strlen(trim($groupby))) { // groupby 是空的,使用我們的 return $mygroupby; } // 不是空的,附加我們的 return $groupby . ", " . $mygroupby; }
Custom Archives[ ]
自定義歸檔[ ]
To continue with the geo-tagging plugin from the last example, let's assume we want the plugin to enable custom permalinks of the form www.example.com/blog?geostate=oregon to tell WordPress to find posts whose state matches "oregon" and display them.
繼續(xù)前一個例子中的geo-tagging插件,加入我們希望插件允許形式為www.example.com/blog?geostate=oregon的自定義permalinks,指示W(wǎng)ordPress查找州名為"俄勒岡州"的文章并且顯示這些文章。
To get this to work, the plugin must do the following:
要實(shí)現(xiàn)這個操作,插件必須執(zhí)行:
- Ensure that when WordPress parses the URL, the state gets saved in the query variables; to do this, we have to add "geostate" to the list of query variables WordPress understands (query_vars filter). Here's how to do that:
- 確定WordPress解析URL的時候,州名在查詢變數(shù)中保存了;要達(dá)到這個目的,我們需要將"geostate"添加到WordPress識別的查詢變數(shù)列表上(query_vars filter)。下面是操作方法:
add_filter('query_vars', 'geotag_queryvars' ); function geotag_queryvars( $qvars ) { $qvars[] = 'geostate'; return $qvars; }
add_filter('query_vars', 'geotag_queryvars' ); function geotag_queryvars( $qvars ) { $qvars[] = 'geostate'; return $qvars; }
- Do the right query when the "geostate" query variable is found; this is similar to the custom queries discussed in the previous examples. The only difference is that instead of testing for is_search or something similar in posts_where and other database query filters, we'll instead test to see whether the "geostate" query variable has been detected. Here is the code to replace the if( is_search() ) statements in the examples above:
- 找到"geostate"查詢變數(shù)的時候,正確地查詢;這與上述例子中討論的自定義查詢相似。唯一的不同在于,我們沒有測試is_search或者posts_where和其它數(shù)據(jù)庫查詢filters中相似的內(nèi)容,而是測試是否查看到"geostate"查詢變數(shù)。下面是替換上面的例子中if( is_search() )聲明的代碼:
global $wp_query; if( isset( $wp_query->query_vars['geostate'] )) { // modify the where/join/groupby similar to above examples }
global $wp_query; if( isset( $wp_query->query_vars['geostate'] )) { // modify the where/join/groupby similar to above examples }
- Probably the plugin also needs to generate these permalinks. For instance, the plugin might have a function called geotags_list_states that would find out which states exist in its geotag table, and make links to them:
- 也許插件也需要創(chuàng)建這些permalinks。例如,插件可能有個稱為geotags_list_states的函數(shù),這個函數(shù)會查找geotag表格中有哪些州,并且給這些州創(chuàng)建鏈接:
function geotags_list_states( $sep = ", " ) { global $geotag_table, $wpdb; // find list of states in DB $qry = "SELECT geotag_state FROM $geotag_table " . " GROUP BY geotag_state ORDER BY geotag_state"; $states = $wpdb->get_results( $qry ); // make list of links $before = '<a href="' . get_bloginfo('home') . '?geostate='; $mid = '">'; $after = "</a> "; $cur_sep = ""; foreach( $states as $row ) { $state = $row->state; echo $cur_sep . $before . rawurlencode($state) . $mid . $state . $after; // after the first time, we need separator $cur_sep = $sep; } }
function geotags_list_states( $sep = ", " ) { global $geotag_table, $wpdb; // 在DB中找到州列表 $qry = "SELECT geotag_state FROM $geotag_table " . " GROUP BY geotag_state ORDER BY geotag_state"; $states = $wpdb->get_results( $qry ); // 創(chuàng)建鏈接列表 $before = '<a href="' . get_bloginfo('home') . '?geostate='; $mid = '">'; $after = "</a> "; $cur_sep = ""; foreach( $states as $row ) { $state = $row->state; echo $cur_sep . $before . rawurlencode($state) . $mid . $state . $after; // 第一次后,我們需要分隔符 $cur_sep = $sep; } }
Permalinks for Custom Archives[ ]
自定義歸檔的Permalinks[ ]
If the blog user has non-default permalinks enabled, we can go one step further in the previous custom archives example, and enable the URL example.com/blog/geostate/oregon to also list all posts tagged with the state of Oregon. To do this, we add to WordPress's "rewrite rules", which basically tell WordPress how to interpret permalink-style URLs. Specifically, we add a rewrite rule that tells WordPress to interpret /geostate/oregon URLs the same as ?geostate=oregon. (See WordPress:Query Overview for more information on the rewrite process.)
如果博客用戶擁有非默認(rèn)的permalinks,我們可以更深入地處理上述自定義歸檔例子,并且使得URLexample.com/blog/geostate/oregon也列出所有標(biāo)記為俄勒岡州的文章。這樣,我們需要添加到WordPress的"rewrite rules",指示W(wǎng)ordPress怎樣解譯permalinks樣式的URLs。我們會添加rewrite規(guī)則,指示W(wǎng)ordPress將/geostate/oregon URLs與?geostate=oregon一樣解譯。(關(guān)于rewrite過程更多的信息,請看看查詢概述。)
In practice, to define a new rewrite rule, there are two steps: (1) "flush" the cached rewrite rules using an init filter, to force WordPress to recalculate the rewrite rules, and (2) use the generate_rewrite_rules action to add a new rule when they are calculated. Here's the "flush" code:
實(shí)際上,定義新的rewrite規(guī)則,有兩個步驟:(1)使用init filter,"flush"緩存的rewrite規(guī)則,迫使WordPress重新考慮rewrite規(guī)則,(2)新規(guī)則得到認(rèn)可后,使用generate_rewrite_rules action添加新規(guī)則。下面是"flush"代碼:
add_action('init', 'geotags_flush_rewrite_rules'); function geotags_flush_rewrite_rules() { global $wp_rewrite; $wp_rewrite->flush_rules(); }
add_action('init', 'geotags_flush_rewrite_rules'); function geotags_flush_rewrite_rules() { global $wp_rewrite; $wp_rewrite->flush_rules(); }
The rule generation is slightly more complex. Basically, the rewrite rules array is an associative array whose keys are regular expressions that match potential permalink URLs, and whose values are the corresponding non-permalink-style URLs they correspond to. So, to define a rewrite rule that matches URLs like /geostate/oregon (with arbitrary states), and tells WordPress it should correspond to ?geostate=oregon, we do the following:
創(chuàng)建規(guī)則要稍微復(fù)雜。一般來說,rewrite規(guī)則數(shù)組是相關(guān)數(shù)組,相關(guān)數(shù)組的keys是匹配潛在的permalink URIs 的規(guī)則表述,相關(guān)數(shù)組的參數(shù)值是相應(yīng)的非permalink樣式的URLs。因此,要定義匹配URLs,如/geostate/oregon(帶有任意的州名)的rewrite 規(guī)則,并且指示W(wǎng)ordPress響應(yīng)?geostate=oregon,我們執(zhí)行以下的操作:
add_action('generate_rewrite_rules', 'geotags_add_rewrite_rules'); function geotags_add_rewrite_rules( $wp_rewrite ) { $new_rules = array( 'geostate/(.+)' => 'index.php?geostate=' . $wp_rewrite->preg_index(1) ); $wp_rewrite->rules = $new_rules + $wp_rewrite->rules; }
add_action('generate_rewrite_rules', 'geotags_add_rewrite_rules'); function geotags_add_rewrite_rules( $wp_rewrite ) { $new_rules = array( 'geostate/(.+)' => 'index.php?geostate=' . $wp_rewrite->preg_index(1) ); $wp_rewrite->rules = $new_rules + $wp_rewrite->rules; }