Улучшаем страницу с результатами поиска в wordpress
Получает элементы (термины) указанной таксономии по указанным параметрам.
До версии WP 4.5 первый параметр get_terms() был названием таксономии или списком таких названий:
$terms = get_terms("post_tag", array("hide_empty" => false,));
С версии WP 4.5 название таксономии нужно указывать в элементе массива taxonomy в параметре $args , а не во втором параметре, как это было раньше:
$args = array("taxonomy" => "post_tag", "hide_empty" => false,); $terms = get_terms($args);
Обратная совместимость работает (функция понимает устарелый вызов).
✈ 1 раз = 0.015166с = тормоз | 50000 раз = 33.29с = очень медленно | PHP 7.1.11, WP 4.9.5
Хуки из функции
Возвращает
Массив/WP_Error/строка.
- Массив объектов WP_Term - при успешном получении.
- array() (пустой массив) - если термины не найдены.
- WP_Error - если любой из указанных таксономий не существует.
- Количество найденных терминов (в виде строки) - если fields = count .
Шаблон использования
$terms = get_terms(array("taxonomy" => array("post_tag", "my_tax"), // название таксономии с WP 4.5 "orderby" => "id", "order" => "ASC", "hide_empty" => true, "object_ids" => null, "include" => array(), "exclude" => array(), "exclude_tree" => array(), "number" => "", "fields" => "all", "count" => false, "slug" => "", "parent" => "", "hierarchical" => true, "child_of" => 0, "get" => "", // ставим all чтобы получить все термины "name__like" => "", "pad_counts" => false, "offset" => "", "search" => "", "cache_domain" => "core", "name" => "", // str/arr поле name для получения термина по нему. C 4.2. "childless" => false, // true не получит (пропустит) термины у которых есть дочерние термины. C 4.2. "update_term_meta_cache" => true, // подгружать метаданные в кэш "meta_query" => "",)); foreach($terms as $term){ print_r($term); }Использование
get_terms($args, $deprecated); $args(строка/массив)Аргументы, в соответствии с которыми будет получен результат.
Среди них обязательным является аргумент $args["taxonomy"] в котором указывается название таксономии или несколько названий таксономий в массиве.
$deprecated(строка/массив)
До версии 4.5 в этом аргументе указывались параметры $args, а первом параметре $args указывались называния таксономий. С версии 4.5 названия таксономий указываются в аргументе $args["taxonomy"] .
По умолчанию: массив аргументов по умолчанию
Аргументы параметра $args
taxonomy(строка/массив) (обязательный) Название таксономии с которой работать. Можно указать несколько названий в виде массива. С версии WP 4.5, до этого названия таксономий указывались в первом параметре самой функции. number(число) Максимальное количество элементов, которые будут получены. Лимит.По умолчанию: все . object_ids(число/массив)
Укажите тут число или массив чисел, чтобы получить термины, у которых поле object_id таблицы wp_term_relationships совпадет с указанными значениями.
Обычно в поле object_id находятся ID записей к которым прикреплен термин.
Include(строка/массив)
Массив из ID терминов, которые нужно включить в выборку. Если указать этот параметр, то многие другие станут бесполезными. Парсится через wp_parse_id_list() .
По умолчанию: ""
exclude(строка/массив)
Массив ID терминов, которые нужно исключить. Также можно указать строку в виде разделенных запятыми ID. Парсится через wp_parse_id_list() .
По умолчанию: ""
exclude_tree(строка/массив)
Массив ID родительских терминов, которые нужно исключить. Исключена будет вся ветка. Парсится через wp_parse_id_list() .
По умолчанию: ""
offset(число)
Верхний отступ в запросе. Сколько первых элементов пропустить. Указывать нужно число. По умолчанию без отступов.
orderby(строка)
Поле по которому сортировать результат. Может быть:
- id или term_id - по ID.
- name - по названию. По умолчанию.
- count - по полю count в term_taxonomy - по количеству записей.
- slug - по альтернативному названию.
- description - по описанию.
- term_group - по группе.
- include - по порядку указанному в параметре $include
- slug__in - с версии 4.9. В порядке указанном в параметре $slug.
- meta_value - по значению произвольного поля
- meta_value_num - по значению произвольного поля, значение будет интерпретироваться как число, а не строка.
- ключ "meta_query" - в параметре $meta_query мы можем указать параметры запроса по метаполям, и там же указать ключ для конкретного запроса. Этот ключ можно использовать как ключ для сортировки по соответствующему метаполю.
- none - не сортировать
parent - по полю parent.
По умолчанию: "id"
order(строка)Направление сортировки, указанной в параметре "orderby":
- ASC - по порядку, от меньшего к большему (1, 2, 3; a, b, c);
- DESC - в обратном порядке, от большего к меньшему (3, 2, 1; c, b, a).
По умолчанию: "ASC"
Hide_empty(логический)
Скрывать ли термины в которых нет записей. 1(true) - скрывать пустые, 0(false) - показывать пустые.
По умолчанию: true
fields(строка)
Какие поля возвращать в результирующем массиве. Может быть:
- all - Вернуть массив объектов (все данные) - по умолчанию;
- ids - вернуть массив чисел;
- names - вернуть массив строк.
- count - (3.2+) возвращает количество найденных терминов.
- id=>parent - вернуть массив, где ключ = ID термина, а значение = ID родительского термина.
- id=>slug - вернуть массив, где ключ = ID термина, а значение = слаг (название для УРЛ) термина.
- id=>name - вернуть массив, где ключ = ID термина, а значение = название (имя) термина.
По умолчанию: "all"
count(логический) true - вернет количество терминов. В этом случае, перебивает параметр fields .false - вернет массив объектов терминов. name(строка/массив) Укажите тут строку или массив строк, чтобы получить термины с указанными названиями.
По умолчанию: "" slug(строка/массив) Укажите тут строку или массив строк, чтобы получить термины с указанными ярлыками (слагами).
По умолчанию: "" hierarchical(логический)
Включать ли в результат термины, которые имеют не пустые дочерние термины (в которых есть записи). Т.е. в массив будут включены пустые термины, если у их дочерних терминах есть записи, даже если аргумент " hide_empty " равен true .
- true - да, включить;
- false - нет, не включать.
По умолчанию: true
Search(строка)
Поиск по названиям термина и его ярлыку. Получит термины в названиях которых есть вхождение указанной тут строки. Т.е. запрос выглядит так: LIKE "%search_string%" .
По умолчанию: ""
name__like(строка)
Показать термины, в названии которых есть указанная строка. Поиск по строке.
По умолчанию: ""
description__like (строка)
Показать термины, в описании которых есть указанная строка. Поиск по строке.
По умолчанию: ""
pad_counts(логический)
Если передать true, то число которое показывает количество записей в родительских категориях будет суммой своих записей и записей из дочерних категорий. По умолчанию подсчитываются только свои записи.
pad_counts зависит от параметра parent потому что подсчет записей идет на уровне PHP и если например указать parent=0 , то будут получены только верхние термины и pad_counts не сможет правильно посчитать кол-во записей в дочерних терминах. Чтобы обойти это ограничение, нужно получить все термины, не указывая parent , а потом в PHP удалить ненужные... Вот пример такого кода:
$terms = get_terms(array("hide_empty" => 0, "orderby" => "name", "order" => "ASC", "taxonomy" => "category", "pad_counts" => 1)); // оставим только термины с parent=0 $terms = wp_list_filter($terms, array("parent"=>0));
По умолчанию: false
get(строка)Если указать "all" то будут жёстко отключены параметры: childless , child_of , hide_empty , hierarchical и pad_counts . "Жёстко" - значит перебьет текущие установки для этих параметров. "Отключены" - значит им будет установлен параметр false или 0.
Обычно используется для удобства, когда нужно получить термины на низком уровне, не для вывода, а для дальнейшей работы с ними, чтобы не следить за значениями упомянутых параметров...
// фрагмент кода if ("all" == $args["get"]) { $args["childless"] = false; $args["child_of"] = 0; $args["hide_empty"] = 0; $args["hierarchical"] = false; $args["pad_counts"] = false; }
По умолчанию: ""
child_of(число)ID родительского термина. Вывести элементы таксономии, которые являются дочерними разделами указанного элемента. Будут получены все уровни вложенности, все дерево.
Если указаны несколько таксономий, параметр будет проигнорирован.
По умолчанию: 0
Parent(число)
ID родительского термина, чтобы получить только прямых потомков.
Будет получен только первый уровень вложенности, а не все дерево как в параметре child_of . Если указать 0, то будут выведены термины верхнего уровня.
По умолчанию: ""
Term_taxonomy_id(число/массив)
Укажите тут число или массив чисел, чтобы получить термины, у которых поле term_taxonomy_id совпадет с указанными значениями.
По умолчанию: ""
cache_domain(строка)
(3.2+) Позволяет установить уникальные ключ кэша, который будет использоваться в get_terms() при объектном кэшировании (object cache). Например, если вы используется один из фильтров get_terms(), чтобы изменить запрос (например "terms_clausses"), установив "cache_domain" в уникальное значение, позволить не перезаписывать сохраненный кэш для одинаковых запросов.
По умолчанию: "core"
update_term_meta_cache(логический)
true - загрузить кэш метаданных, чтобы потом их можно было быстро получить. Кэш подгружается для полученных элементов.
По умолчанию: true
meta_query(массив)
Запрос для получения элементов на основе метаданных. Смотрите WP_Meta_Query .
meta_key(строка)
Получит термины у которых есть указанное метаполе. Можно использовать в связке с meta_value .
По умолчанию: ""
meta_value(строка)
Получит термины у которых значение метаполя равно указанному значению. Всегда используется в связке с meta_key .
По умолчанию: ""
suppress_filter(логический)
Подавлять работу фильтров или нет? Если выставить в true, то фильтр get_terms просто не будет работать для текущего запроса терминов.
По умолчанию: false (фильтры работают)
Примеры
#1 Получим массив данных о всех категориях на сайте
Данные в массиве будут отсортированы по количеству записей (orderby=count) в каждой категории. Категории у которых нет записей все равно будут включены в массив (hide_empty=0).
$myterms = get_terms("category", "orderby=count&hide_empty=0");
#1.2 Получим все разделы ссылок:
$mylinks_categories = get_terms("link_category", "orderby=count&hide_empty=0");#2 Выведем на экран список названий всех разделов таксономии "my_taxonomy":
$terms = get_terms("my_taxonomy"); if($terms && ! is_wp_error($terms)){ echo "- ";
foreach($terms as $term){
echo "
- ". $term->name ." "; } echo "
В данном примере каждый $term из цикла foreach($terms as $term) , будет содержать такую информацию:
=> 162 => Здоровье => zdorove => 0 => 170 => articles => => 0 => 2
#3 Вывод рубрик через разделитель
// получаем все термины из таксономии my_term $args = array("hide_empty=0"); $terms = get_terms("my_term", $args); // собираем их и выводим if (!empty($terms) && !is_wp_error($terms)) { $count = count($terms); $i=0; $term_list = "
"; foreach ($terms as $term) { $i++; $term_list .= "name) . "">" . $term->name . ""; if ($count != $i) { $term_list .= " · "; } else { $term_list .= "
"; } } echo $term_list; } /* в итоге получим подобный код: */Код get terms : wp-includes/taxonomy.php VER 5.1.1
false,); /* * Legacy argument format ($taxonomy, $args) takes precedence. * * We detect legacy argument format by checking if * (a) a second non-empty parameter is passed, or * (b) the first parameter shares no keys with the default array (ie, it"s a list of taxonomies) */ $_args = wp_parse_args($args); $key_intersect = array_intersect_key($term_query->query_var_defaults, (array) $_args); $do_legacy_args = $deprecated || empty($key_intersect); if ($do_legacy_args) { $taxonomies = (array) $args; $args = wp_parse_args($deprecated, $defaults); $args["taxonomy"] = $taxonomies; } else { $args = wp_parse_args($args, $defaults); if (isset($args["taxonomy"]) && null !== $args["taxonomy"]) { $args["taxonomy"] = (array) $args["taxonomy"]; } } if (! empty($args["taxonomy"])) { foreach ($args["taxonomy"] as $taxonomy) { if (! taxonomy_exists($taxonomy)) { return new WP_Error("invalid_taxonomy", __("Invalid taxonomy.")); } } } // Don"t pass suppress_filter to WP_Term_Query. $suppress_filter = $args["suppress_filter"]; unset($args["suppress_filter"]); $terms = $term_query->query($args); // Count queries are not filtered, for legacy reasons. if (! is_array($terms)) { return $terms; } if ($suppress_filter) { return $terms; } /** * Filters the found terms. * * @since 2.3.0 * @since 4.6.0 Added the `$term_query` parameter. * * @param array $terms Array of found terms. * @param array $taxonomies An array of taxonomies. * @param array $args An array of get_terms() arguments. * @param WP_Term_Query $term_query The WP_Term_Query object. */ return apply_filters("get_terms", $terms, $term_query->query_vars["taxonomy"], $term_query->query_vars, $term_query); }Well…it isn’t called elasticsearch for nothing! Let’s talk about search operations in the client.
The client gives you full access to every query and parameter exposed by the REST API, following the naming scheme as much as possible. Let’s look at a few examples so you can become familiar with the syntax.
Here is a standard curl for a Match query:
curl -XGET "localhost:9200/my_index/my_type/_search" -d "{ "query" : { "match" : { "testField" : "abc" } } }"
And here is the same query constructed in the client:
$params = [ "index" => "my_index", "type" => "my_type", "body" => [ "query" => [ "match" => [ "testField" => "abc" ] ] ] ]; $results = $client->search($params);
Notice how the structure and layout of the PHP array is identical to that of the JSON request body. This makes it very simple to convert JSON examples into PHP. A quick method to check your PHP array (for more complex examples) is to encode it back to JSON and check by eye:
$params = [ "index" => "my_index", "type" => "my_type", "body" => [ "query" => [ "match" => [ "testField" => "abc" ] ] ] ]; print_r(json_encode($params["body"])); {"query":{"match":{"testField":"abc"}}}
Using Raw JSON
Sometimes it is convenient to use raw JSON for testing purposes, or when migrating from a different system. You can use raw JSON as a string in the body, and the client will detect this automatically:
$json = "{ "query" : { "match" : { "testField" : "abc" } } }"; $params = [ "index" => "my_index", "type" => "my_type", "body" => $json ]; $results = $client->search($params);
Search results follow the same format as Elasticsearch search response, the only difference is that the JSON response is serialized back into PHP arrays. Working with the search results is as simple as iterating over the array values:
$params = [ "index" => "my_index", "type" => "my_type", "body" => [ "query" => [ "match" => [ "testField" => "abc" ] ] ] ]; $results = $client->search($params); $milliseconds = $results["took"]; $maxScore = $results["hits"]["max_score"]; $score = $results["hits"]["hits"]["_score"]; $doc = $results["hits"]["hits"]["_source"];
Bool queries can be easily constructed using the client. For example, this query:
curl -XGET "localhost:9200/my_index/my_type/_search" -d "{ "query" : { "bool" : { "must": [ { "match" : { "testField" : "abc" } }, { "match" : { "testField2" : "xyz" } } ] } } }"
Would be structured like this (Note the position of the square brackets):
$params = [ "index" => "my_index", "type" => "my_type", "body" => [ "query" => [ "bool" => [ "must" => [ [ "match" => [ "testField" => "abc" ] ], [ "match" => [ "testField2" => "xyz" ] ], ] ] ] ] ]; $results = $client->search($params);
Notice that the must clause accepts an array of arrays. This will be serialized into an array of JSON objects internally, so the final resulting output will be identical to the curl example. For more details about arrays vs objects in PHP, see Dealing with JSON Arrays and Objects in PHP .
Let’s construct a slightly more complicated example: a boolean query that contains both a filter and a query. This is a very common activity in elasticsearch queries, so it will be a good demonstration.
The curl version of the query:
curl -XGET "localhost:9200/my_index/my_type/_search" -d "{ "query" : { "bool" : { "filter" : { "term" : { "my_field" : "abc" } }, "should" : { "match" : { "my_other_field" : "xyz" } } } } }"
$params = [ "index" => "my_index", "type" => "my_type", "body" => [ "query" => [ "bool" => [ "filter" => [ "term" => [ "my_field" => "abc" ] ], "should" => [ "match" => [ "my_other_field" => "xyz" ] ] ] ] ] ]; $results = $client->search($params);
The Scrolling functionality of Elasticsearch is used to paginate over many documents in a bulk manner, such as exporting all the documents belonging to a single user. It is more efficient than regular search because it doesn’t need to maintain an expensive priority queue ordering the documents.
Scrolling works by maintaining a "point in time" snapshot of the index which is then used to page over. This window allows consistent paging even if there is background indexing/updating/deleting. First, you execute a search request with scroll enabled. This returns a "page" of documents, and a scroll_id which is used to continue paginating through the hits.
This is an example which can be used as a template for more advanced operations:
$client = ClientBuilder::create()->build(); $params = [ "scroll" => "30s", // how long between scroll requests. should be small! "size" => 50, // how many results *per shard* you want back "index" => "my_index", "body" => [ "query" => [ "match_all" => new \stdClass() ] ] ]; // Execute the search // The response will contain the first batch of documents // and a scroll_id $response = $client->search($params); // Now we loop until the scroll "cursors" are exhausted while (isset($response["hits"]["hits"]) && count($response["hits"]["hits"]) > 0) { // ** // Do your work here, on the $response["hits"]["hits"] array // ** // When done, get the new scroll_id // You must always refresh your _scroll_id! It can change sometimes $scroll_id = $response["_scroll_id"]; // Execute a Scroll request and repeat $response = $client->scroll([ "scroll_id" => $scroll_id, //...using our previously obtained _scroll_id "scroll" => "30s" // and the same timeout window ]); }
By Ibrahim Diallo
Published Jul 2 2014 ~ 16 minutes readSearch is an important feature on a website. When my few readers want to look for a particular passage on my blog, they use the search box. It used to be powered by Google Search, but I have since then changed it to my own home-brewed version not because I can do better but because it was an interesting challenge.
If you are in a hurry and just want your site to be searchable, well do what I did before, use Google.
// In search.php file $term = isset($_GET["query"])?$_GET["query"]: ""; $term = urlencode($term); $website = urlencode("www.yourwebsite.com"); $redirect = "https://www.google.com/search?q=site%3A{$website}+{$term}"; header("Location: $redirect"); exit;
What it does is pretty simple. Get the term passed by the user, and forward it to Google search page. Limit the search result to our current domain using the site: keyword in the search query. All your pages that are indexed by Google will be available through search now. If you do want to handle your search in house however, then keep reading.
Homemade Search Solution
Before we go any further, try using the search box on this blog. It uses the same process that I will describe below. If you feel that this is what you want then please continue reading.
This solution is catered to small websites. I make use of LIKE with wild cards on both ends, meaning your search cannot be indexed. This means the solution will work fine for your blog or personal website that doesn"t contain tons of data. Port it to a bigger website and it might become very slow. MySQL offers Full Text Search which is not what we are doing here.
Note: If you have 5000 blog posts you are still fine. .
We will take the structure of this blog as a reference. Each blog post has:
- A title p_title
- A url p_url
- A summary p_summary
- A post content p_content
- And catergories category.tagname
For every field that matches with our search term, we will give it a score. The score will be based on the importance of the match:
// the exact term matches is found in the title $scoreFullTitle = 6; // match the title in part $scoreTitleKeyword = 5; // the exact term matches is found in the summary $scoreFullSummary = 5; // match the summary in part $scoreSummaryKeyword = 4; // the exact term matches is found in the content $scoreFullDocument = 4; // match the document in part $scoreDocumentKeyword = 3; // matches a category $scoreCategoryKeyword = 2; // matches the url $scoreUrlKeyword = 1;
Before we get started, there are a few words that do not contribute much to a search that should be removed. Example "in","it","a","the","of" ... . We will filter those out and feel free to add any word you think is irrelevant. Another thing is, we want to limit the length of our query. We don"t want a user to write a novel in the search field and crash our MySQL server.
// Remove unnecessary words from the search term and return them as an array function filterSearchKeys($query){ $query = trim(preg_replace("/(\s+)+/", " ", $query)); $words = array(); // expand this list with your words. $list = array("in","it","a","the","of","or","I","you","he","me","us","they","she","to","but","that","this","those","then"); $c = 0; foreach(explode(" ", $query) as $key){ if (in_array($key, $list)){ continue; } $words = $key; if ($c >= 15){ break; } $c++; } return $words; } // limit words number of characters function limitChars($query, $limit = 200){ return substr($query, 0,$limit); }
Our helper functions can now limit character count and filter useless words. The way we will implement our algorithm is by giving a score every time we find a match. We will match words using the if statement and accumulate points as we match more words. At the end we can use that score to sort our results
Note: I will not be showing how to connect to MySQL database. If you are having problems to efficiently connect to the database I recommend reading this .
Let"s give our function a structure first. Note I left placeholders so we can implement sections separately.
Function search($query){ $query = trim($query); if (mb_strlen($query)===0){ // no need for empty search right? return false; } $query = limitChars($query); // Weighing scores $scoreFullTitle = 6; $scoreTitleKeyword = 5; $scoreFullSummary = 5; $scoreSummaryKeyword = 4; $scoreFullDocument = 4; $scoreDocumentKeyword = 3; $scoreCategoryKeyword = 2; $scoreUrlKeyword = 1; $keywords = filterSearchKeys($query); $escQuery = DB::escape($query); // see note above to get db object $titleSQL = array(); $sumSQL = array(); $docSQL = array(); $categorySQL = array(); $urlSQL = array(); /** Matching full occurrences PLACE HOLDER **/ /** Matching Keywords PLACE HOLDER **/ $sql = "SELECT p.p_id,p.p_title,p.p_date_published,p.p_url, p.p_summary,p.p_content,p.thumbnail, ((-- Title score ".implode(" + ", $titleSQL).")+ (-- Summary ".implode(" + ", $sumSQL).")+ (-- document ".implode(" + ", $docSQL).")+ (-- tag/category ".implode(" + ", $categorySQL).")+ (-- url ".implode(" + ", $urlSQL).")) as relevance FROM post p WHERE p.status = "published" HAVING relevance >
In the query, all scores will be summed up as the relevance variable and we can use it to sort the results.
Matching full occurrences
We make sure we have some keywords first then add our query.
If (count($keywords) > 1){ $titleSQL = "if (p_title LIKE "%".$escQuery."%",{$scoreFullTitle},0)"; $sumSQL = "if (p_summary LIKE "%".$escQuery."%",{$scoreFullSummary},0)"; $docSQL = "if (p_content LIKE "%".$escQuery."%",{$scoreFullDocument},0)"; }
Those are the matches with higher score. If the search term matches an article that contains these, they will have higher chances of appearing on top.
Matching keywords occurrences
We loop through all keywords and check if they match any of the fields. For the category match, I used a sub-query since a post can have multiple categories.
Foreach($keywords as $key){ $titleSQL = "if (p_title LIKE "%".DB::escape($key)."%",{$scoreTitleKeyword},0)"; $sumSQL = "if (p_summary LIKE "%".DB::escape($key)."%",{$scoreSummaryKeyword},0)"; $docSQL = "if (p_content LIKE "%".DB::escape($key)."%",{$scoreDocumentKeyword},0)"; $urlSQL = "if (p_url LIKE "%".DB::escape($key)."%",{$scoreUrlKeyword},0)"; $categorySQL = "if ((SELECT count(category.tag_id) FROM category JOIN post_category ON post_category.tag_id = category.tag_id WHERE post_category.post_id = p.post_id AND category.name = "".DB::escape($key)."") > 0,{$scoreCategoryKeyword},0)"; }
Also as pointed by a commenter below, we have to make sure that the these variables are not empty arrays or the query will fail.
// Just incase it"s empty, add 0 if (empty($titleSQL)){ $titleSQL = 0; } if (empty($sumSQL)){ $sumSQL = 0; } if (empty($docSQL)){ $docSQL = 0; } if (empty($urlSQL)){ $urlSQL = 0; } if (empty($tagSQL)){ $tagSQL = 0; }
At the end the queries are all concatenated and added together to determine the relevance of the post to the search term.
// Remove unnecessary words from the search term and return them as an array function filterSearchKeys($query){ $query = trim(preg_replace("/(\s+)+/", " ", $query)); $words = array(); // expand this list with your words. $list = array("in","it","a","the","of","or","I","you","he","me","us","they","she","to","but","that","this","those","then"); $c = 0; foreach(explode(" ", $query) as $key){ if (in_array($key, $list)){ continue; } $words = $key; if ($c >= 15){ break; } $c++; } return $words; } // limit words number of characters function limitChars($query, $limit = 200){ return substr($query, 0,$limit); } function search($query){ $query = trim($query); if (mb_strlen($query)===0){ // no need for empty search right? return false; } $query = limitChars($query); // Weighing scores $scoreFullTitle = 6; $scoreTitleKeyword = 5; $scoreFullSummary = 5; $scoreSummaryKeyword = 4; $scoreFullDocument = 4; $scoreDocumentKeyword = 3; $scoreCategoryKeyword = 2; $scoreUrlKeyword = 1; $keywords = filterSearchKeys($query); $escQuery = DB::escape($query); // see note above to get db object $titleSQL = array(); $sumSQL = array(); $docSQL = array(); $categorySQL = array(); $urlSQL = array(); /** Matching full occurences **/ if (count($keywords) > 1){ $titleSQL = "if (p_title LIKE "%".$escQuery."%",{$scoreFullTitle},0)"; $sumSQL = "if (p_summary LIKE "%".$escQuery."%",{$scoreFullSummary},0)"; $docSQL = "if (p_content LIKE "%".$escQuery."%",{$scoreFullDocument},0)"; } /** Matching Keywords **/ foreach($keywords as $key){ $titleSQL = "if (p_title LIKE "%".DB::escape($key)."%",{$scoreTitleKeyword},0)"; $sumSQL = "if (p_summary LIKE "%".DB::escape($key)."%",{$scoreSummaryKeyword},0)"; $docSQL = "if (p_content LIKE "%".DB::escape($key)."%",{$scoreDocumentKeyword},0)"; $urlSQL = "if (p_url LIKE "%".DB::escape($key)."%",{$scoreUrlKeyword},0)"; $categorySQL = "if ((SELECT count(category.tag_id) FROM category JOIN post_category ON post_category.tag_id = category.tag_id WHERE post_category.post_id = p.post_id AND category.name = "".DB::escape($key)."") > 0,{$scoreCategoryKeyword},0)"; } // Just incase it"s empty, add 0 if (empty($titleSQL)){ $titleSQL = 0; } if (empty($sumSQL)){ $sumSQL = 0; } if (empty($docSQL)){ $docSQL = 0; } if (empty($urlSQL)){ $urlSQL = 0; } if (empty($tagSQL)){ $tagSQL = 0; } $sql = "SELECT p.p_id,p.p_title,p.p_date_published,p.p_url, p.p_summary,p.p_content,p.thumbnail, ((-- Title score ".implode(" + ", $titleSQL).")+ (-- Summary ".implode(" + ", $sumSQL).")+ (-- document ".implode(" + ", $docSQL).")+ (-- tag/category ".implode(" + ", $categorySQL).")+ (-- url ".implode(" + ", $urlSQL).")) as relevance FROM post p WHERE p.status = "published" HAVING relevance > 0 ORDER BY relevance DESC,p.page_views DESC LIMIT 25"; $results = DB::query($sql); if (!$results){ return false; } return $results; }
Now your search.php file can look like this:
$term = isset($_GET["query"])?$_GET["query"]: ""; $search_results = search($term); if (!$search_results) { echo "No results"; exit; } // Print page with results here.
We created a simple search algorithm that can handle a fair amount of content. I arbitrarily chose the score for each match, feel free to tweak it to something that works best for you. And there is always room for improvement.
It is a good idea to track the search term coming from your users, this way you can see if most users search for the same thing. If there is a pattern, then you can save them a trip and just cache the results using Memcached .
If you want to see this search algorithm in action, go ahead and try looking for an article on the search box on top of the page. I have added extra features like returning the part where the match was found in the text. Feel free to add features to yours.
Did you like this article? You can subscribe to read more awesome ones. .
On a related note, here are some interesting articles.
A few months ago I updated my PHP version. PHP 5.4 to 5.5 . I never had any problems updating PHP before. I follow its development closely and try to remove my deprecated functions long before they are officially removed. But this time I was caught off guard. It silently broke part of my website for the silliest reason.
Comments(45)
Zaryel Aug 12 2015:
Ian Mustafa Sep 26 2015:
Rob Sep 29 2015:
adeem Feb 11 2016:
Ivan Venediktov Apr 9 2016.
Поиск на сайте — вещь определенно нужная, часто мы не уделяем ему должного внимания. Если у вас старый, массивный и большой проект, то найти нужную информацию там становится не такой простой задачей. Для специализированный сайтов на различных CMS поиск может быть не совсем тривиальной задачей, требующей дополнительной установки. К счастью, данная сложность попросту ликвидирована — наверное 99% дизайнов имеют в своей структуре работающий поиск — вам остается лишь активировать тот или иной шаблон для блога.
Поиск в wordpress, конечно, на любителя. Изначально в вашем шаблоне может выводиться вариант с обрезанным видом анонса статьи. То есть, выводится заголовок, мета данные и с помощью функции the_excerpt отображается часть поста длинною вроде бы в 55 символов. Не всегда в дизайне это выглядит красиво и здорово, поэтому лично я стараюсь сделать страницу поиска похожей на архивные разделы. Кроме того, что внешний вид страницы поиска в таком случае очень даже привычный для посетителя сайта (хотя и не совсем стандартный в плане поиска), так в нашем случае сделать это не так сложно.
Как правило внешний вид страницы поиска задается в файле шаблона search.php . Открываем его и, после внимательного изучения, аккуратно добавляем туда код из файла архивов archive.php. Таким образом, настроив единственный раз внешний вид постов на главной, страницах тегов и я достаточно легко внедряю его и для поиска.
На для красоты и функциональности можно добавить кое-кто интересное на страницу поиска . Для этого заходим в файл search.php , находим место после заголовка, но перед статьями и добавляем что-то вроде такого кода:
$s
&showposts=-1"
)
;
$key
=
wp_specialchars($s
,
1
)
;
$count
=
$allsearch
->
post_count
;
_e(""
)
;
_e(""
)
;
echo
$key
;
_e("""
)
;
_e(" найдено "
)
;
echo
$count
.
" "
;
_e("статьи. "
)
;
wp_reset_query()
;
?>
|
В результате чего на странице результатов поиска появится надпись — Для вашего поискового запроса «ключевое слово » найдено 29 статьи. Текст, понятное дело, можно изменять так, как вам будет угодно, код в свою очередь определяет какой запрос вы ввели в форме поиска и сколько результатов для него было получено.
В одном из блогов я нашел еще хак для страницы поиска wordpress. Он позволяет «подсвечивать» слова, которые вы искали в результатах поиска . Для этого в файле search.php находим строку с функцией the_title, которая по умолчанию будет заключена в код типа этого:
" rel="bookmark" title="Permanent Link to "> |
" rel="bookmark" title="Permanent Link to ">
Так вот ее нужно заменить на
Но перед этим вставить следующую строку:
"\0" , $title ) ; ?> |
\0", $title); ?>
Этот код будет выделять «поисковые слова» в заголовке постов жирным шрифтом. Если выделение жирным вы практикуете по умолчанию, то в любом случае можно изменить стили в CSS.
Пример работы когда на сайте я так и не увидел, но судя по нему, выделение применяется только к заголовку. В принципе, то же самое можно сделать и с текстом анонса. Более того, существуют специальные плагины для этих целей. В данном случае использование wordpress плагина позволит получать подсветку поисковых слов даже после смены шаблона, куда не придется в очередной раз вносить правки.
В любом случае все эти правки вы можете и не использовать — все зависит от личных пожеланий и предпочтений. Хотя я бы также рекомендовал обратить внимание на пользовательский поиск Google или (Google Custom Search), который не только позволит реализовать какие-то дополнительные возможности поиска, но позволит получить максимально стандартный его вид и даже немного на этом заработать через Google Adsense. Собственно на WordPress inside вы можете видеть пример его реализации — меня лично все более чем устраивает. К тому же это позволило объединить поиск по данному блогу и Tod’s Blog, а я в свою очередь размещаю не совместить ли мне информацию со всех блогов, тематика то у них почти одинаковая — интернет.
P.S. Постовой. Киевское лето! Только оптимальный выбор отели Киева цены ! Приезжай в гостиницу «Украина».
The world’s largest bittorrent system fot free torrent downloads music, movies, games and other files.
Теперь купить в интернете контактные линзы стало гораздо проще, доставка по Украине и Киеву.
With a custom to give users more information for searching your site.
Things You Need to Know
Creating a Search Page Template
1. Using a , open the page.php and save as searchpage.php . If you do not have a page.php , you can create one based upon your Theme"s index.php template file.
Note:
The filename search.php is reserved as a special template name, so avoid its usage; the suggested searchpage.php just makes it easy to recognize in the list of files.
2. After saving it, edit the file:
- Delete (i.e. basically everything within your content div), leaving the div tags intact.
- Add a such as "Search Posts" or something similar. You can use an existing class from your CSS style sheet, or create a new one.
- Copy the following into the content div or any other div that contains the content of your Page:
- At the top of your searchpage.php , before anything else, add this to give your Search Page a heading WordPress will recognize in the Administration Screens:
3. Save the file.
4. Upload the file to your theme directory (if you made changes to your style.css style sheet file, upload that, too).
If you create searchpage.php from page.php in Twenty Seventeen, it would be as like as followings:
Creating a Search Page
Based on the Search Page Template, we will create the seach page.
- In the go to Pages > Add New.
- In the title field enter Search
.
Do not write anything in the content area. - While still on the same page, look for Page Attributes on right side menu.
- Select the drop-down menu in Template , and select Search Page .
- Click the Publish button.
It will show simple search form such as
Linking to Your Search Page
You can now make a link to your custom Search Page in several ways.
Using the Page ID
Whether or not you use permalinks, you can link to your new Search Page by using Page ID number of the Page. Insert the next line into your any posts, pages or templates
Search Page
OR you may insert the next line into templates
/?page_id=17">Search Page
Using the Page Slug
The Page slug is set in the screen. It is the name of the page if you are using . You can manually change this. An example of a Page slug link would be:
Search Page
for any posts, pages or templates when slug is "search-page". OR you may insert the next line into templates
/wordpress/search-page/" title="Search Page">Search Page
Using wp_list_pages()
If you are using the template tag, the page name would be automatically generated in your Pages list.
Customizing Your Search Page
Now that you have created your custom Search Page, you can customize the display. Open your searchpage.php in a text editor and edit it there. Above the get_search_form() function for your searchform.php within the content div , you can add text to help visitors search your site.
My Site features articles about WordPress, web page design, website development, and CSS.
To search my website, please use the form below.
You might want to include a list of keywords or other information, images, or details to customize your custom Search Page.
Preserving Search Page Results and Pagination
Search results and Pagination may stop working when applying customization to the search template. To avoid these issues the first thing any developer needs to do is add the following code to the start of their Search template to ensure that the original WordPress query is preserved. To customize the query append additional arguments to (array) $search_query . Execute the $search_query through a new $wp_query object, more information on the WP_Query object can be found at