Skip to content

Search Implementation

Implement search functionality using the plugin's template variables.

Search Methods Overview

The plugin provides two main search methods:

Standard search functionality.

twig
{# Basic search #}
{% set results = craft.searchWithElastic.search('coffee recipes') %}

2. Advanced Search (searchExtra)

Search with additional options.

twig
{% set results = craft.searchWithElastic.searchExtra(query, {
    fuzzy: true,
    fields: ['title', 'content', 'summary'],
    size: 20,
    siteId: 2
}) %}

Basic Search Form

twig
{# search.twig #}
<form method="get" action="{{ url('search') }}" class="search-form">
    <input 
        type="search" 
        name="q" 
        value="{{ craft.app.request.getParam('q', '') | e('html_attr') }}"
        placeholder="Search..."
        required
    >
    <button type="submit">Search</button>
</form>

Processing Search Queries

twig
{# Get search query #}
{% set query = craft.app.request.getParam('q', '') | trim %}

{% if query | length >= 2 %}
    {# Simple search (recommended for most cases) #}
    {% set results = craft.searchWithElastic.search(query) %}
    
    {# Or advanced search with options #}
    {% set results = craft.searchWithElastic.searchExtra(query, {
        fuzzy: true,
        size: 20,
        fields: ['title', 'content']
    }) %}
    
    {# Display results #}
    <h2>{{ results | length }} results for "{{ query }}"</h2>
    
    {% for result in results %}
        <article>
            <h3>{{ result.title }}</h3>
            <p>{{ result.highlight|raw }}</p>
            <a href="{{ result.url }}">Read more</a>
        </article>
    {% endfor %}
{% endif %}

Search Options

Standard search across all indexed content:

twig
{% set results = craft.searchWithElastic.search('coffee brewing') %}

Advanced Search with Options

Search with fuzzy matching enabled:

twig
{% set results = craft.searchWithElastic.searchExtra('coffee recipes', {
    fuzzy: true,
    fields: ['title', 'content']
}) %}

Target specific fields:

twig
{# Search with field specification #}
{% set results = craft.searchWithElastic.searchExtra(query, {
    fields: ['title'],
    fuzzy: false
}) %}

{# Multiple fields #}
{% set results = craft.searchWithElastic.searchExtra(query, {
    fields: ['title', 'summary', 'content']
}) %}

Search within specific sites:

twig
{# Search current site #}
{% set results = craft.searchWithElastic.search(query, currentSite.id) %}

{# Search specific site #}
{% set results = craft.searchWithElastic.searchExtra(query, {
    siteId: 2
}) %}

PHP Implementation

For module or plugin development, use the service methods directly:

php
use pennebaker\searchwithelastic\SearchWithElastic;

// Get the Elasticsearch service
$elasticsearch = SearchWithElastic::getInstance()->elasticsearch;

// Basic search
$results = $elasticsearch->search('coffee brewing');

// Advanced search with options
$results = $elasticsearch->advancedSearch(
    'coffee',
    [
        'fuzzy' => true,
        'fields' => ['title', 'content'],
        'size' => 20
    ]
);

Search Filters

Filter results after searching:

twig
{# Get search results #}
{% set results = craft.searchWithElastic.search(query) %}

{# Filter by element type #}
{% set entries = results | filter(r => r._source.elementType == 'entry') %}
{% set assets = results | filter(r => r._source.elementType == 'asset') %}

{# Filter by date #}
{% set recentResults = results | filter(r => 
    r._source.dateCreated | date('U') > date('-30 days') | date('U')
) %}

{# Filter by section #}
{% set blogPosts = results | filter(r => 
    r._source.section is defined and r._source.section == 'blog'
) %}

Pagination

Implement pagination for large result sets:

twig
{% set page = craft.app.request.getParam('page', 1) %}
{% set perPage = 20 %}
{% set offset = (page - 1) * perPage %}

{# Search with pagination #}
{% set allResults = craft.searchWithElastic.search(query) %}
{% set totalResults = allResults | length %}
{% set results = allResults | slice(offset, perPage) %}

{# Display pagination #}
{% if totalResults > perPage %}
    {% set totalPages = (totalResults / perPage) | round(0, 'ceil') %}
    
    <nav class="pagination">
        {% if page > 1 %}
            <a href="?q={{ query }}&page={{ page - 1 }}">Previous</a>
        {% endif %}
        
        {% for p in 1..totalPages %}
            <a href="?q={{ query }}&page={{ p }}" 
               class="{{ p == page ? 'active' : '' }}">{{ p }}</a>
        {% endfor %}
        
        {% if page < totalPages %}
            <a href="?q={{ query }}&page={{ page + 1 }}">Next</a>
        {% endif %}
    </nav>
{% endif %}

Error Handling

Gracefully handle search failures:

twig
{% if query %}
    {% try %}
        {% set results = craft.searchWithElastic.search(query) %}
    {% catch %}
        {# Fallback to Craft's native search #}
        {% set results = craft.entries.search(query).limit(20).all() %}
        <div class="notice">
            Using backup search. Some features may be limited.
        </div>
    {% endtry %}
{% endif %}

Rate Limit Status

Display rate limit information to users:

twig
{# Check rate limit status #}
{% set rateLimit = craft.searchWithElastic.getRateLimitStatus() %}

{% if rateLimit.enabled %}
    <div class="rate-limit-info">
        Searches remaining: {{ rateLimit.remaining }} / {{ rateLimit.limit }}
    </div>
{% endif %}

Index Statistics

Display search index health:

twig
{# Get index stats for debugging #}
{% set stats = craft.searchWithElastic.getIndexStats() %}

<div class="index-stats">
    <p>Index: {{ stats.index_name }}</p>
    <p>Documents: {{ stats.count }}</p>
    <p>Status: {{ stats.exists ? 'Active' : 'Missing' }}</p>
</div>

{# Get all index stats #}
{% set allStats = craft.searchWithElastic.getAllIndexStats() %}

Complete Example

A full search page implementation:

twig
{# templates/search/index.twig #}
{% extends "_layout" %}

{% set query = craft.app.request.getParam('q', '') | trim %}

{% block content %}
    <h1>Search</h1>
    
    <form method="get" class="search-form">
        <input 
            type="search" 
            name="q" 
            value="{{ query | e('html_attr') }}"
            placeholder="What are you looking for?"
            required
        >
        <button type="submit">Search</button>
    </form>
    
    {% if query | length >= 2 %}
        {% try %}
            {# Perform search #}
            {% set results = craft.searchWithElastic.searchExtra(query, {
                fuzzy: true,
                size: 20,
                fields: ['title', 'content', 'summary']
            }) %}
            
            <div class="search-results">
                <h2>{{ results | length }} results for "{{ query }}"</h2>
                
                {% for result in results %}
                    <article class="search-result">
                        <h3>
                            <a href="{{ result.url }}">{{ result.title }}</a>
                        </h3>
                        {% if result.highlight %}
                            <p class="highlight">{{ result.highlight | raw }}</p>
                        {% endif %}
                        <footer>
                            <span class="type">{{ result._source.elementType | title }}</span>
                            <time>{{ result._source.dateCreated | date('M j, Y') }}</time>
                        </footer>
                    </article>
                {% else %}
                    <p>No results found. Try different keywords or check your spelling.</p>
                {% endfor %}
            </div>
        {% catch %}
            <div class="error">
                <p>Search is temporarily unavailable. Please try again later.</p>
            </div>
        {% endtry %}
    {% elseif query %}
        <p>Please enter at least 2 characters to search.</p>
    {% endif %}
{% endblock %}

Next Steps