Search Installed

Provide a helper to search pages from other pages.

Options See on deno.land

name string

The helper name

Default:
"search"
returnPageData boolean

To return only the page.data value

Default:
false

Description

This plugin registers the search helper to search pages from other pages. It's useful to build menus or other navigation stuff.

Installation

This plugin is installed by default. 🎉

Searching pages

The function search.pages() returns an array of pages that you can filter and sort.

To search by tags, just include the tag names as the first argument, separated by spaces. For example, to search all pages containing the tags post and html, you would execute search.pages("post html"):

<ul>
  {% for post in search.pages("post html") %}
  <li>{{ post.data.title }}</li>
  {% endfor %}
</ul>

You can use quotes to search for tags containing spaces. For example to search by the tags post and static site generator:

<ul>
  {% for post in search.pages("post 'static site generator'") %}
  <li>{{ post.data.title }}</li>
  {% endfor %}
</ul>

Use the exclamation mark to search pages that doesn't contain a specific tag. For example, to search pages with the tag "post" not containing the tag "html":

<ul>
  {% for post in search.pages("post !html") %}
  <li>{{ post.data.title }}</li>
  {% endfor %}
</ul>

Sort pages

The second argument is the value used to sort. By default, the pages are sorted by date, but you can use any field. For example, if you want to sort by title:

<ul>
  {% for post in search.pages("post html", "title") %}
  <li>{{ post.data.title }}</li>
  {% endfor %}
</ul>

Note: You can use dot notation to sort by any subfield. For example: header.title.

Sorting allows specifying multiple fields. For example let's sort by the "order" and "title" fields:

{% for post in search.pages("post html", "order title") %}
  ...
{% endfor %}

By default, sort is ascendening, but this can be changed by appending =desc to the field name:

{% for post in search.pages("post html", "order=asc title=desc") %}
  ...
{% endfor %}

Limit the results

The third argument of search.pages() allows limiting the number of results. You can use a positive number to return the first n results or a negative number to return the last n results:

<!-- Get the 3 first values -->
{% for post in search.pages("post html", "order title", 3) %}
  ...
{% endfor %}

<!-- Get the 3 last values -->
{% for post in search.pages("post html", "order title", -3) %}
  ...
{% endfor %}

Filtering by a field

You can filter pages not only by tags but also by any other field that you want. For example, to search all pages with the value menu as true, simply include the query menu=true:

{% for option in search.pages("menu=true") %}
<a href="{{ option.data.url }}">
  {{ option.data.title }}
</a>
{% endfor %}

The available operators for the conditions are:

  • = to search coincidences, for example menu=true. The strings true and false are converted to booleans automatically. undefined and null are also converted so you can filter pages without a value with keyname=undefined. The strings with numeric values are also converted to numbers.
  • ^= to search values starting with another value. For example all categories starting with the letter A: category^=A.
  • $= to search values ending with another value. For example all categories ending with the letter b: category$=b.
  • *= to search values containing another value. For example all titles containing the string security: title*=security.
  • <, >, <=, >= to search values lower or greater than the other value. For example, all pages with level greater than 2: level>2.

You can use the dot notation and even combine queries with tags. For example, let's say you want to select all pages with the value taxonomy.category=sport and with the tag football:

{% for post in search.pages("taxonomy.category=sport football") %}
<a href="{{ post.data.url }}">
  {{ post.data.title }}
</a>
{% endfor %}

Negative conditions

You can prepend the ! character to the operator to negate the condition. For example while menu=true returns pages whose menu variable is true, menu!=true returns pages whose menu variable is NOT true.

All operators accepts NOT operators. For example category!^=A (pages which categories that does NOT start with the letter A), or title!*=security (pages whose title does NOT contain the word "security").

Alternatively, you can prepend the ! character at the begining of the condition. For example !menu=true is equivalent to menu!=true, and !category^=A is equivalent to category!^=A.

Using | for OR conditions

You can assign several values for any condition using the pipe character |. For example, if you want to search pages having the tag html OR css, you can do it with search.pages("html|css"). You can combine AND and OR using spaces and pipes. For example, to search all pages with the tag post and also one of the tags html or css: search.pages("post html|css").

OR conditions can be used with other fields. For example, to search pages with titles containing the words "html", "css" or "javascript": search.pages("title*=html|css|javascript").

The data filter

In most cases, you don't need the Page instance, only the data object of the pages. So you can use the data filter to return only these objects. So instead of this:

{% for post in search.pages("category=lume"]) %}
<a href="{{ post.data.url }}">
  {{ post.data.title }}
</a>
{% endfor %}

You can do this:

{% for post in search.pages("category=lume"]) | data %}
<a href="{{ post.url }}">
  {{ post.title }}
</a>
{% endfor %}

Search one page

The function search.page() is very similar to search.pages() but only returns the first page found. Note the limit argument is not available.

Searching next and previous page

If the current page belongs to a list of pages (for example, a list of pages under the same tag), you can get the previous and next page in this list. To do that we have the functions search.previousPage() and search.nextPage(). The syntax is the same as search.pages(), but the first argument is the URL of the current page. Let's see an example:

<h2>More articles tagged as "html"</h2>

{% set post = search.previousPage(url, "html") %}

{% if post %}
  <a href="{{ post.data.url }}" rel="prev">← {{ post.data.title }}</a>
{% endif %}

{% set post = search.nextPage(url, "html") %}

{% if post %}
  <a href="{{ post.data.url }}" rel="next">{{ post.data.title }} →</a>
{% endif %}

Get all values of a key

The function values() returns all values found for a specific key, removing duplicates. For example, let's say your pages have the variable author and you want to list all authors:

<strong>List of authors:</strong>

<ul>
  {% for author in search.values("author") %}
  <li>
    {{ author }}
  </li>
  {% endfor %}
</ul>

Use the second argument to filter the pages to get the values. For example, to get the authors of pages in the category sport: search.values("author", "category=sport")

There's the function search.tags() for backward compatibility. It's the equivalent of using search.values("tags"), to return all tags found in some pages.

Searching data

The function data returns the data associated with any file or directory in the source directory. This is useful to get the data stored in any _data of any directory. For example:

{% set companyData = search.data("about/the-company") %}

Search files

The function files() allows to search any file that will be copied to the dest folder and returns its URL. It accepts an regular expression or a string with a glob expression. For example, to search all CSS files:

This site uses the following CSS files:

<ul>
  {% for file in search.files("*.css") %}
  <a href="{{ file }}">
    {{ file }}
  </a>
  {% endfor %}
</ul>

Configuration

If you want to change the default configuration, use the second argument of lume() function in your _config.ts file.

import lume from "lume/mod.ts";

// Search plugin configuration
const search = {/* your config here */};

// Apply the plugin config
const site = lume({}, { search });

returnPageData

Use this option to return only the page.data object instead the page instance. Probably this is what you want and will make your code shorter.

It's disabled by default due compatibility with the old behavior but in the future Lume 2.0 it will be the default behavior.

import lume from "lume/mod.ts";

const search = { returnPageData: true };
const site = lume({}, { search });

Once configured, the following code:

{% for article in search.pages("type=article", "date=desc") %}
<a href="{{ article.data.url }}">
  <h1>{{ article.data.title }}</h1>
</a>
{% endfor %}

must be changed to:

{% for article in search.pages("type=article", "date=desc") %}
<a href="{{ article.url }}">
  <h1>{{ article.title }}</h1>
</a>
{% endfor %}