What is the best way to implement faceted search? Finding the right path: how faceted navigation affects SEO (translation). Faceted Navigation: Definition

Smart filter or Faceted search is a filter by product category, which can be seen in large online stores and the same Yandex.market. It helps to consistently sort products with the properties the user needs, eliminating all that is unnecessary. This is a very convenient option that allows you to quickly find the desired product or material on the site.

And so let's move on directly to installing and configuring the modules we need

First, we will need to download and install the following modules: Search API, Search API Database Search, Entity API and Views.

On the modules page we enable:

  • Search API
  • Search views
  • Database search
  • Entity API
  • Views
  • Views UI
  • Ctools
Creating a search server

Go to Configuration > Search and metadata > Search API (/admin/config/search/search_api) and click Add server.
Then enter the server name, select Database service in the Service class drop-down list and save.

Creating an Index

Go to Configuration > Search and metadata > Search API (/admin/config/search/search_api), click Add server (Add index).
Enter the name of the index, select ‘Material’ in the Item type field, select Database server in the Server field, and click Create Index.


In the form that opens, check the boxes by which the sorting will be performed and save.
To be able to sort by node name, enable title and opposite it in the drop-down list, select the string type, not fulltext. You cannot sort by fulltext.

In the next form that opened, Filters (workflow), I left everything by default, go to the View tab (Status), and click Index Now (Index Now).
After indexing is complete, we will create a search page.

Creating a Search Page

Go to Structure > Views and click Add new view.
In the new view, in the Show drop-down list, select the index we previously created, fill in the remaining fields (name, title and path) as you need.


Next, click Continue & edit and configure the view as usual. In the filtering criteria I added showing only published materials and desired type node and configured the display of the required fields (you need to add these fields to the index to be able to filter by them).

At this stage we are done with setting up the view, now let's move directly to the facet filter.

A/search_api_ranges.module +++ b/search_api_ranges.module @@ -144.11 +144.8 @@ function search_api_ranges_minmax($variables, $order = "ASC") ( // otherwise our min/max would always equal user input. $filters = &$query->getFilter()->getFilters(); foreach ($filters as $key => $filter) ( - - // Check for array: old style filters are objects which we can skip. - if (is_array($filter)) ( - if ($filter == $variables["range_field"] || ($filter != $variables["range_field"] && $filter == "")) ( - $ current_filter = $filters[$key]; + if(isset($filter->tags) && is_array($filter->tags))( + if(in_array("facet:".$variables["range_field"], $ filter->tags))( unset($filters[$key]); ) )

Patching JQuery UI Slider: setting up a redirect

In the module version 7x-1.5, I encountered the fact that if the slider widget is located on a page other than the search page, then after changing the price range, the direction was redirected to current page, not the search page.
The error lies in the function search_api_ranges_block_slider_view_form_submit()(file search_api_ranges.module, line 364).
I didn’t really look into what was there and why, I just changed the code a little on line 427:

Drupal_goto($path, array("query" => array($params), "language" => $language)); + drupal_goto($values["path"], array("query" => array($params), "language" => $language));

after which the problem was solved.

In today's lesson we will try to recreate an imitation of faceted search using Javascript. I'm assuming you already know what faceted search is if you're reading this tutorial, otherwise google it or check out Amazon or my Demo.

First we need the library github.com/eikes/facetedsearch. Download it and connect the facetedsearch.js file to our project. We will also need the jQuery and Underscore libraries.

Disclaimer: I understand that JQ is no longer a cake, but I use it as familiar syntactic sugar, you can rewrite it for libraries more familiar to you or in vanilla JS.

So, first, let's make a simple markup with connected dependencies:

Document // Here we will display facet filters // And here our elements will be

Now we need to describe the settings of our application and create a template for displaying array elements that we will sort using facets:

$(function())( var item_template = // Describe the template "" + " " class="img-responsive">" + ", " + "

" + "" + ", " + ", " + "

" + "

" + ""; settings = ( items: example_items, facets: ( // Specify facet categories "category" : "What Category", "continent" : "Which Continent", "language" : "Programming Language"), resultSelector: "#results", // DOM element where we display the results facetSelector: "#facets", // DOM element for facets resultTemplate: item_template, paginationCount: 8, // Number of elements per page orderByOptions: ("firstname": "First name ", "lastname": "Last name", "category": "Category", "RANDOM": "Random"), facetSortOption: ("continent": ["North America", "South America"]) ) $. facetelize(settings);

Well, actually create a JSON array itself with elements to display in our faceted search in JS:

Var items = [ ( "firstname": "Mary", "lastname": "Smith", "imageURL": "http://lorempixel.com/150/150/cats/2", "description": "Sed Ea Amet. Stet Voluptua. Nonumy Magna Takimata", "category": "Mouse", "language": ["Smalltalk", "XSLT"], "continent": "Africa" ​​), ( "firstname": "Patricia", "lastname": "Johnson", "imageURL": "http://lorempixel.com/150/150/cats/3", "description": "Ut Takimata Sit Aliquyam Labore Aliquyam Sit Sit Lorem Amet. Ipsum Rebum." , "category": "Lion", "continent": "North America", ... ];

This array I would put it in a separate JS file that would be generated dynamically, from the database, for example.

That's all, we get a faceted search in JavaScript and can customize it. Next, I provide translated documentation of the library, where you can see the triggers you need.

Documentation Features

Two functions are exported to the jQuery namespace.

facetelize Used to initialize a faceted search with the given settings.

facetUpdate Can be used if you want to change the facet lookup state externally.

Object settings

items: An array of items that will be filtered and sorted in the process.

facets: An object whose keys correspond to element keys and values ​​is the header for that facet. Items will be filtered based on what value they have for these keys.

orderByOptions: Similar to facets, except these key-value pairs are used only for sorting. When the RANDOM key is enabled, the results can be randomized.

facetSelector: This is a selector that is used to find a DOM node from which to select facet filters.

resultSelector: This is a selector that is used to find the DOM node where results are displayed.

resultTemplate: A string that is used by the Underscore template engine to render each element from the items array. The following attributes are added to each element, which can also be used in the template: batchItemNr, batchItemCount, and totalItemCount.

state: This object stores the current filters, sorts: currentResult and others. You can provide an orderBy string or a filters object to preset them.

enablePagination: Boolean to enable pagination and the "load more" button, defaults to true .

paginationCount: If paginator is enabled, sets the number of elements per page, default is 50.

facetSortOption: Use this function to change the order of facet elements. Takes an object whose keys correspond to facet names and values ​​into an array of facet values, which can be arranged in the order you would like them to be. This example will sort the continents in a different order, adding items not included in the array in alphabetical order:

FacetSortOption: ("continent": ["North America", "South America"])

There are some more templates, please have a look source facetedsearch.js to see all available template options.

Events

You can bind to some events which should send notifications when some actions happened. To do this, we use the jquery event system:

facetuicreated: You can bind this function to the settings.facetSelector DOM element which should be notified when user interface was created.

facetedsearchresultupdate: You can bind this function to the settings.resultSelector DOM element to be notified of the update results.

facetedsearchfacetclick: This event is fired when a facet is clicked and fired on the settings.facetSelector element. Which receives the facet id as an argument.

facetedsearchorderby: This event is fired when the sorting element is clicked on the settings.facetSelector element. It takes the ID order as an argument.

$(settings.resultSelector).bind("facetedsearchresultupdate", function())( // do something, maybe ));

We took a quick look at the installation and basic syntax of PINQ, a port of LINQ to PHP. In this article, we'll look at how to use PINQ to simulate the faceted search feature in MySQL.

In this article we will not cover all aspects of faceted search. Interested people can search for suitable information on the Internet.

A typical faceted search works like this:

  • The user enters a keyword, or several keywords For search. For example, “router” to search for products in which the word “router” appears in the description, keywords, category name, tags, etc.
  • The site returns a list of products that match these criteria.
  • The site provides several links to customize your search terms. For example, it may allow you to specify specific router manufacturers, or set a price range, or other features.
  • The user can continue to specify additional search criteria in order to obtain the data set of interest.

Faceted search is quite popular and a powerful tool that can be seen on almost any e-commerce website.

Unfortunately, faceted search is not built into MySQL. So what should we do if we still use MySQL, but want to give the user this opportunity?

With PINQ, which has a similar, powerful and simple approach, we can achieve the same behavior as if we were using other database engines.

Expanding the demo from the first part

Note: all code from this part, and from the first part, can be found in the repository.

In this article, we'll expand on the demo from Part 1 with a significant improvement in the form of facet search.

Let's start with index.php by adding following lines:

$app->get("demo2", function () use ($app) ( global $demo; $test2 = new pinqDemo\Demo($app); return $test2->test2($app, $demo->test1 ($app)); $app->get("demo2/facet/(key)/(value)", function ($key, $value) use ($app) ( global $demo; $test3 = new pinqDemo\Demo($app); return $test3->test3($app, $demo->test1($app), $key, $value ));

The first route takes us to a page to view all posts that match the keyword search. To keep the example simple, we select all books from the book_book table. It will also display the resulting data set and a set of links to specify the search criteria.

In real applications, after clicking on such links, all facet filters will adjust to the boundary values ​​of the resulting data set. The user will thus be able to sequentially add new search conditions, for example, first select a manufacturer, then specify a price range, etc.

But in this example we will not implement this behavior - all filters will reflect the boundary values ​​​​of the original data set. This is the first limitation and the first candidate for improvement in our demo.

As you can see in the code above, the actual functions are located in another file called pinqDemo.php. Let's take a look at the corresponding code that provides the faceted search feature.

Aspect class

The first step is to create a class that represents an aspect. In general, an aspect should contain several properties:

  • The data it operates on ($data)
  • The key by which the grouping is performed ($key)
  • Key type ($type). Can be one of the following:
    • specify the full string for an exact match
    • indicate part of the string (usually the initial one) to search by pattern
    • indicate a range of values, for grouping by range
  • if the key type is a range of values, you need to define a value step to determine the lower and upper bounds of the range; or if the type is part of a string, you must specify how many first letters will be used for grouping ($range)

Grouping is the most critical part of the aspect. All aggregated information that an aspect may be able to return depends on the grouping criteria. Typically the most used search criteria are “Full String”, “Part of String”, or “Range of Values”.

Namespace classFacet ( use Pinq\ITraversable, Pinq\Traversable; class Facet ( public $data; // Original data set public $key; // field by which to group public $type; // F: entire row; S: start strings; R: range; public $range; // plays a role only if $type != F ... public function getFacet() ( $filter = ""; if ($this->type == "F") // entire line ( ... ) elseif ($this->type == "S") // start of line ( ... ) elseif ($this->type == "R") // range of values ​​( $ filter = $this->data ->groupBy(function($row) ( return floor($row[$this->key] / $this->range) * $this->range; )) ->select(function (ITraversable $data) ( return ["key" => $data->last()[$this->key], "count" => $data->count()]; )); return $filter; ) ) )

The main function of this class is to return a filtered dataset based on the original dataset and aspect properties. From the code it is clear that for various types accounts are used various ways grouping data. In the code above, we showed what the code might look like if we group the data by a range of values ​​in increments specified in $range .

Setting aspects and displaying source data

Public function test2($app, $data) ( $facet = $this->getFacet($data); return $app["twig"]->render("demo2.html.twig", array("facet" = > $facet, "data" => $data)); private function getFacet($originalData) ( $facet = array(); $data = \Pinq\Traversable::from($originalData); // 3 creation examples different aspect objects, and return the aspects $filter1 = new \classFacet\Facet($data, "author", "F"); $filter2 = new \classFacet\Facet($data, "title", "S", 6) ; $filter3 = new \classFacet\Facet($data, "price", "R", 10); $facet[$filter1->key] = $filter1->getFacet(); ] = $filter2->getFacet(); $facet[$filter3->key] = $filter3->getFacet(); return $facet;

In the getFacet() method we do the following:

  • Convert the original data into a Pinq\Traversable object for further processing
  • We create three aspects. The 'author' aspect will group by the author field, and implement grouping by the entire row; aspect 'title' - by the title field with grouping by part of the line (by the first 6 characters); aspect 'price' - by the price field with grouping by range (in increments of 10)
  • Finally, we extract the aspects and return them to the test2 function so that they can be output to the template for display
Outputting aspects and filtered data

In most cases, filters will be displayed as a line, and will lead you to view the filtered result.

We've already created a route ("demo2/facet/(key)/(value)") to display faceted search results and filter links.

The route takes two parameters, depending on the key being filtered by and the value for that key. The test3 function that is bound to this route is shown below:

Public function test3($app, $originalData, $key, $value) ( ​​$data = \Pinq\Traversable::from($originalData); $facet = $this->getFacet($data); $filter = null; if ($key == "author") ( $filter = $data ->where(function($row) use ($value) ( ​​return $row["author"] == $value; )) ->orderByAscending( function($row) use ($key) ( return $row["price"]; )) ; ) elseif ($key == "price") ( ... ) else //$key==title ( .. . ) return $app["twig"]->render("demo2.html.twig", array("facet" => $facet, "data" => $filter) )

Basically, depending on the key, we apply filtering (an anonymous function in the where statement) according to the passed value and get the following set of filtered data. We can also set the order of data filtering.

Finally, we display the raw data (along with filters) in the template. This route uses the same pattern we used in "demo2".

Search Bar

    (% for k, v in facet %)
  • ((k|capitalize))
    • (% for vv in v %)
    • ((vv.count))((vv.key))
    • (%endfor%)
    (%endfor%)

We need to remember that the aspects generated by our application are nested arrays. At the first level, this is an array of all aspects, and, in our case, there are three of them (for author, title, price, respectively).

Each aspect has a key-value array, so we can iterate over it using normal methods.

Notice how we build the URLs for our links. We use both the outer loop key (k) and the inner loop keys (vv.key) as parameters for the route ("demo2/facet/(key)/(value)"). The size of the arrays (vv.count) is used for display in the template.

The first image shows the original data set, and the second image is filtered by price range from $0 to $10, and sorted by author.

Great, we were able to simulate faceted search in our application!

Before concluding this article, we need to take a final look at our example and determine what can be improved and what limitations we have.

Possible improvements

In general, this is a very basic example. We've just gone over the basic syntax and concepts and implemented them as a working example. As previously stated, we have several areas that could be improved for greater flexibility.

We need to implement “overlay” search criteria, since the current example limits us to the ability to apply search filtering only to the original data set; we cannot apply faceted search to an already filtered result. This is the biggest improvement I can imagine.

Restrictions

The facet search implemented in this article has serious limitations (which may also apply to other facet search implementations):

We fetch data from MySQL every time

This application uses the Silex framework. Like any single entry point framework like Silex, Symfony, Laravel, its index.php (or app.php) file is called every time a route is parsed and controller functions are executed.

If you look at the code in our index.php, you will notice that the following line of code:

$demo = new pinqDemo\Demo($app);

is called every time the application page is rendered, which means the following lines of code are executed each time:

Class Demo ( private $books = ""; public function __construct($app) ( $sql = "select * from book_book order by id"; $this->books = $app["db"]->fetchAll($sql ; )

Will it be better if we don't use a framework? Well, despite the fact that developing applications without frameworks is not a good idea, I can say that we will encounter the same problems: data (and state) is not preserved between different HTTP requests. This is a fundamental characteristic of HTTP. This can be avoided by using caching mechanisms.

We saved some SQL queries using aspects. Instead of passing one select query to retrieve the data, and three group by queries with corresponding where clauses, we ran just one where query, and used PINQ to get the aggregated information.

Conclusion

In this part, we implemented the ability to facet search a collection of books. As I said, this is just a small example, which has room for improvement, and which has a number of limitations.

Faceted navigation is a problem for all e-commerce sites. Excessive number of pages that are used for different options of the same element poses a threat to search efficiency. This can negatively impact SEO and user experience. Experts from the SEO Hacker blog explained what faceted navigation is and how to improve it.

Faceted Navigation: Definition

This type of navigation is usually found in the sidebars of e-commerce sites and contains filters and facets - parameters that the user configures as desired. allows online store customers to search for the product they want using a combination of attributes that will filter products until users find what they need.

Facets and filters are different from each other. Here's the difference:

  • Facets are indexed categories. They help refine product listings and act as extensions of core categories. Facets add unique meaning to each choice the user makes. Since facets are indexed, they must send relevant signals to the search engine, ensuring that the page contains all the important attributes.

  • Filters are used to sort and refine items within lists. They are necessary for users, but not for search engines. Filters are not indexed because they do not change the content of the page, but only sort it in a different order. This results in multiple URLs having duplicate content.

Potential problems

Each possible facet combination has its own unique URL. It can cause some problems from an SEO perspective. Here are the main ones:

  • Duplicate content.
  • Waste of budget on scanning.
  • Eliminate link differences.

As your site grows, so does the number of duplicate pages. Incoming links may go to various duplicate pages. This reduces the value of links and limits the ability of pages to rank.

The likelihood of keyword cannibalization also increases. Multiple pages try to rank for the same keywords, resulting in less consistent and lower rankings. This problem could be avoided if each keyword was targeted only to a single page.

Faceted Navigation Solutions

When choosing a solution for faceted navigation, consider your end goal: increasing the number of pages you index or reducing the number of pages you don't want indexed. Here are some solutions that may be useful for you:

AJAX

If you use AJAX, a new URL is not created when the user clicks on a facet or filter. Since there will be no unique URLs for every possible facet combination, the problem of duplicate content, keyword cannibalization, and wasted indexing costs is potentially eliminated.

AJAX can only be effective before the e-commerce site is launched. It is not used to solve problems of existing resources. This method also requires certain expenses on your part.

noindex tag

The noindex tag is used to tell bots to exclude a specific page from the index. This way it won't show up in the results. Google search. This helps reduce the amount of duplicate content that appears in the index and search results.

This won't solve the crawl budget problem because bots will still visit your page. It also doesn't help distribute the value of the links.

The rel=canonical attribute

With this attribute, you tell Google that you have one main preferred page to index and rank, and all other versions of content from that page are just duplicates that don't need to be indexed.

Sofia Ibragimova

Content Marketer

If the same page on your site can be reached from multiple URLs, search robots will treat each URL as a separate page. Bots will decide that the content on your site is not unique, and this will negatively affect rankings and reduce your position in search results. To avoid this, specify the main canonical page by inserting the following sequence of characters into the HEAD block:

You can use canonical pages to solve the problem of duplicate content, and the share link will be merged with your main page. But there is a chance that bots will still crawl duplicate pages, which is a waste of crawling budget.

Robots.txt

Closing some pages from indexing allows you to achieve good results. It's simple, fast and reliable way. The easiest way to do this is to set a custom option to specify all the possible combinations of facets and filters that you want to block. Include it at the end of each URL you want to hide (http://full page address/robots.txt) or use the Robots meta tag in the HEAD area of ​​the page code.

When making changes to the URL, keep in mind that it takes 3-4 weeks for robots to notice and respond to these changes.

There are certain problems here too. The value of links will be limited, and a blocked URL may be indexed due to the presence of external links.

Console Google Search

This is a great way to temporarily fix your problems while you work on creating a better and more user-friendly navigation system. You can use the Google Search Console to tell the search engine how to crawl your site.

  • Sign in account console and select the “Crawl” section:

  • Click on the “URL Parameters” button:

  • Indicate the impact each of your settings will have on the page and how you want Google to treat those pages.

Remember that this method only hides duplicate content from Google's crawlers. Pages will still appear in Bing and Yahoo.

How to Improve Faceted Navigation

Let's briefly consider all the methods that allow you to create the correct faceted navigation:

  • Using AJAX
  • Remove or hide links to categories or filter pages that are missing content.
  • Allow indexing of certain combinations of facets that have high volume of search traffic
  • Setting up a site hierarchy via bread crumbs in categories and subcategories.
  • Creating canonical (main) pages for duplicate content.
  • Consolidate indexing properties from component pages across the entire series using page markup with rel="next" and rel="prev" .
Conclusion

Each of the solutions mentioned has its own advantages and disadvantages. There is no universal solution; it all depends on the specifics of your business and the specific case. Optimized faceted navigation will allow your site to target a wider range of keywords. To avoid risk, make sure that the navigation not only meets the requirements of search robots, but also provides a good user experience.

In this article (webmaster level - advanced) we will talk about the so-called intersecting in different ways. "faceted" navigation. To simplify the assimilation of the material, I recommend going through the Wikipedia article “Facet classification” and publications on English language(but with pictures!) "Design better faceted navigation for your websites."

Faceted navigation that filters by color or price range can be useful for your visitors, but it often hurts search results because it creates multiple URL combinations with duplicate content. Due to duplicates search engines will not be able to quickly scan the site for content updates, which consequently affects indexing. To minimize this problem and help webmasters make faceted navigation search friendly, we'd like to:

Ideal for users and Google search

Clear path to products/article pages:

URL representation for the category page:
http://www.example.com/category.php?category=gummy-candies

Product specific URL representation:
http://www.example.com/product.php?item=swedish-fish

Unwanted duplicates caused by faceted navigation

The same page is accessible from different web addresses:

Canonical page



URL: example.com/product.php? item=swedish-fish

Duplicate page



URL:example.com/product.php? item=swedish-fish&category=gummy-candies&price=5-10


category=gummy-candies&taste=sour&price=5-10

Errors:

  • Pointless for Google since users rarely search for [marmalade priced at $9:55].
  • Meaningless to web crawlers, who will find the same item ("fruit salad") from parent category pages (either "Jummy" or "Sour Gummy").
  • A negative point for the site owner, because indexing requests are diluted with numerous versions of the same category.
  • A negative point for the site owner, because it is useless and an extra burden on bandwidth site
Blank pages:


URL: example.com/category.php? category=gummy-candies&taste=sour&price=over-10

Errors:

  • The code for search engines is returned incorrectly (in this case, the page should return a 404 code)
  • Blank page for users


Worst solutions (not search friendly) for faceted navigation

Example No. 1: Non-standard parameters are used as part of the URL: commas and parentheses, instead key=value&:

  • example.com/category? [ category:gummy-candy ][ sort:price-low-to-high ][ sid:789 ]
  • example.com/category?category , gummy-candy , sort , lowtohigh , sid , 789
How to:
example.com/category?category=gummy-candy&sort=low-to-high&sid=789

Example #2: Using directories or file paths rather than parameters in lists of values ​​that do not change the content of the page:
example.com/c123 /s789/ product?swedish-fish
(where /c123/ category, /s789/ session ID, which does not change the page content)

Good decision:

  • example.com /gummy-candy/ product?item=swedish-fish&sid=789 (the directory, /gummy-candy/, changes the content of the page in a meaningful way)
The best decision:
  • example.com/product?item=swedish-fish&category=gummy-candy&sid=789 (URL parameters give greater flexibility for search engines to determine how to crawl effectively)
It is difficult for crawlers to differentiate useful values ​​(such as "gummy-candy") from useless ones (such as "SESSIONID") when these values ​​are placed directly in link paths. On the other hand, URL parameters provide flexibility for search engines to quickly check and determine when given value does not require access of a scanning robot (crawler) to all options.

Common values ​​that do not change the content of the page and must be listed as URL parameters include:

  • Session ID
  • ID Tracking
  • Referrer IDs
  • Timestamps
Example #3: Converting user-generated values ​​(possibly infinite) into URL parameters that are crawlable and indexable, but useless for search.
Using minor data generated by site users (such as longitude/latitude or "days ago") in crawled and indexed addresses:
  • example.com/find-a-doctor? radius=15&latitude=40.7565068&longitude=-73.9668408
  • example.com/article?category=health& days-ago=7
How to:
  • example.com/find-a-doctor?city=san-francisco&neighborhood=soma
  • example.com/articles?category=health&date=january-10-2014
Instead of allowing the user to generate values ​​to create crawlable URLs (which results in endless possibilities with very little value to visitors), it is better to publish a page category for the most popular values, in addition you can include Additional information so that the page provides more value than a regular search results page. Alternatively, you might consider placing user-generated values ​​in a separate directory, and then using robots.txt to prevent crawling from that directory.
  • example.com/filtering/ find-a-doctor?radius=15&latitude=40.7565068&longitude=-73.9668408
  • example.com/filtering/ articles?category=health&days-ago=7
And in robots.txt:
User-agent: *
Disallow: /filtering/

Example No. 4. Adding URL parameters without logic.

  • example.com/gummy-candy/lollipops/gummy-candy/gummy-candy/product?swedish-fish
  • example.com/product?cat=gummy-candy&cat=lollipops&cat=gummy-candy &cat=gummy-candy&item=swedish-fish
Good decision:
  • example.com /gummy-candy/ product?item=swedish-fish
The best decision:
  • example.com/product?item=swedish-fish&category=gummy-candy
Extraneous URL parameters only increase duplication, causing the site to be crawled and indexed less efficiently. Therefore, it is necessary to get rid of unnecessary URL parameters and periodically clean up junk links before generating new URLs. If many parameters are needed for a user session, you can hide the information in cookies rather than constantly adding values ​​like cat=gummy-candy&cat=lollipops&cat=gummy-candy&...

Example #5: Suggest further refinements (filtering) when there are null results.

Badly:
Allow users to select filters when there are null items to refine.


Clarification to a page with zero results (for example, price=over-10), which frustrates users and causes unnecessary requests for search engines.

How to:
Create links only when there are elements for the user to select. If the result is zero, the link is marked “gray” (i.e., unclickable). To further improve usability, consider including an indicator of the number of available items next to each filter.


Displaying a page with zero results (for example, price=over-10) is not allowed, plus users are prohibited from making unnecessary clicks, and search engines are prohibited from crawling this not useful page.

It is necessary to prevent the appearance of unnecessary addresses and minimize the space for the visitor by creating URLs only when products are available. This will help keep users engaged on your site (fewer clicks on the back button when no products are found) and will reduce the number of possible URLs known to search engines. Additionally, if a page is not just "temporarily out of stock" but is unlikely to ever contain relevant information, you might want to consider giving it a 404 response code. On the 404 page you can create useful message for users with more options in the navigation or search box so that users can find related products.

For new sites whose webmasters are considering implementing faceted navigation, there are several options for optimizing the crawling (the set of addresses on your site known to Google) of unique content pages and reducing duplicate pages from getting into the search engine index (consolidation of indexing signals).

Determine what URL parameters are required for search engines to crawl each individual content page (that is, determine what parameters are needed to create at least one click path to each item). Required parameters may include item-id , category-id , page etc.

Determine which parameters will be useful to visitors with their queries, and which are likely to cause duplication in crawling and indexing. In the confectionery example (marmalade), the URL parameter "taste" could be valuable for users with queries in the example taste=sour. However, it is logical to consider the "price" parameter to cause unnecessary duplication of category=gummy-candies&taste=sour&price=over-10 . Other common examples:

  • Valuable parameters for search engines: item-id , category-id , name , brand ...
  • Unnecessary parameters: session-id , price-range ...
Let's look at implementing one of several configuration options for URLs that contain unnecessary parameters. Just make sure that the "unnecessary" URL parameters are not actually required for search engine crawlers to crawl or for the user to find each individual product!

Option 1: and internal links

Mark all unnecessary URLs with the . This will reduce the search robot's labor costs and prevent a decrease in crawling frequency. You need to manage scanning globally through robots.txt (Translator's note: see article " ").
Use the rel="canonical" attribute to separate pages for the search index from pages that are not needed there (for example, on the page price=5-10 you can add the rel="canonical" attribute, indicating the category of all sour marmalade example.com/category. php?category=gummy-candies&taste=sour& page=all ).

Option 2: Robots.txt and Disallow

URLs with unnecessary parameters are included in the /filtering/ directory, which will be closed in robots.txt (disallow). This will allow all search engines to crawl only the “correct” in-link (content) of the site, but will block crawling of unwanted URLs at once. For example (example.com/category.php?category=gummy-candies), if the valuable parameters were item, category and taste, and the session ID and price were unnecessary, then the URL for taste would be like this:
example.com/category.php?category=gummy-candies&taste=sour , but all unnecessary parameters, such as price, will be included in the URL in a predefined directory - /filtering/:
example.com/filtering/category.php?category=gummy-candies&price=5-10 ,
which will then be prohibited via robots.txt:
User-agent: *
Disallow: /filtering/

Option 3: Separate Hosts

Make sure that best solutions, listed above (for example, for unnecessary addresses) still apply. Otherwise, search engines have already formed a large link mass in the index. This way, your work will be aimed at reducing the further growth of unnecessary pages viewed using Google robot and consolidation of indexing signals.

Use parameters with standard encoding and key=value format.

Make sure that values ​​that do not change page content, such as session IDs, are implemented as key=value rather than directories.

Don't allow clicks or generate URLs when there are no elements to filter.

Add logic to URL parameter mapping: remove unnecessary parameters rather than constantly adding values ​​(e.g. avoid link generation like this: example.com/product?cat=gummy-candy&cat=lollipops &cat=gummy-candy&item=swedish-fish ).

Store valuable parameters in URLs by listing them first (since URLs are visible in search results) and less relevant parameters last (for example, session ID).
Avoid this link structure: example.com/category.php?session-id=123&tracking-id=456 &category=gummy-candies&taste=sour
Configure URL parameters in Webmaster Tools if you have a clear understanding of how links work on your site.

Make sure that when using JavaScript for dynamic control content (sort/filter/hide) without updating the URL, there are actual web addresses on your site that have search value, such as the main categories and product pages that are crawlable and indexable. Try not to use only home page(i.e. one URL) for your entire site, and using JavaScript to dynamically change the content with navigation - this, unfortunately, will give users only one URL in searches. In addition, check that performance does not affect the performance of dynamic filtering for the worse, as it will interfere with the user's ability to work with the site.

Improve the indexing of different pages of the same content by specifying the rel="canonical" attribute on the privileged version of the page. The rel="canonical" attribute can be used within one or more domains.

Optimize the indexing of content paginated (for example, page=1 and page=2 from the "gummy candies" category) by either:

  • Add a rel="canonical" attribute to a series of pages indicating the canonical category with the “view-all” parameter (for example, page=1, page=2, and page=3 from the “gummy candies” category with with rel=”canonical” on category=gummy-candies&page=all ), making sure the page is relevant to users and loads quickly.
  • Use pagination markup rel="next" and rel="prev" to indicate the relationship between separate pages(see article "Paginaton with rel="next" and rel="prev" ").
Include only canonical links in your sitemaps.