Post Search
Fast, client side search against generated JSON.
Geppetto includes a collection of attributes and Handlebars helpers to allow you to build your own custom search, filter and sort experiences for your custom post lists.
How it works
For client-side re-rendering to work, elements need both Handlebars (for the initial static render) and data-field attributes (for JavaScript updates).
<a href="{{url}}" data-field-href="url" data-field="title">{{title}}</a>
data-field="name"
Sets the element's text content.
data-field-href="name"
Sets the href attribute.
data-field-src="name"
Sets the src attribute.
data-field-html="name"
Sets innerHTML (for WYSIWYG content).
Filtering
Add filter buttons for any field.
<div data-posts-filter="category">
<button data-filter-value="">All</button>
{{#each (postFieldValues "blog" "category")}}
<button data-filter-value="{{this}}">{{this}}</button>
{{/each}}
</div>
data-posts-filter
Declares the field.
data-filter-value
Sets the value (empty shows all).
Sorting
Add a sort dropdown
<select data-posts-sort>
<option value="publishedDate:desc">Newest</option>
<option value="publishedDate:asc">Oldest</option>
<option value="title:asc">A-Z</option>
<option value="title:desc">Z-A</option>
</select>
fieldName:direction where direction is asc or desc
Searching Posts
Add a search input. Case-insensitive, matches any part of a field.
<!-- Searches title, summary, and content (defaults) -->
<input type="search" data-posts-search placeholder="Search posts" />
<!-- Searches title, and author -->
<input type="search" data-posts-search data-search-fields="title,author" placeholder="Search posts" />
URL State
Filter, sort, and page state is preserved in the URL:
/blog?page=2&sort=title:asc&category=News
Complete Example
This example adds search, filter and sort to our previous paginated post example.
<div data-posts="blog" data-per-page="6">
<!-- Search -->
<input type="search" data-posts-search placeholder="Search posts" />
<!-- Filters -->
<div data-posts-filter="category">
<button data-filter-value="">All</button>
{{#each (postFieldValues "blog" "category")}}
<button data-filter-value="{{this}}">{{this}}</button>
{{/each}}
</div>
<!-- Sort -->
<select data-posts-sort>
<option value="publishedDate:desc">Newest</option>
<option value="publishedDate:asc">Oldest</option>
<option value="title:asc">A-Z</option>
</select>
<!-- Posts -->
<div data-posts-list>
{{#each (posts "blog")}}
<article data-post>
<img src="{{featured-image}}" data-field-src="featured-image" alt="">
<h2>
<a href="{{url}}" data-field-href="url" data-field="title">{{title}}</a>
</h2>
<p data-field="summary">{{summary}}</p>
<span data-field="category">{{category}}</span>
</article>
{{/each}}
</div>
<!-- Pagination -->
<nav data-posts-pagination>
{{#if (hasPrevPage)}}
<a href="{{paginationPrevUrl}}" data-page="prev">Previous</a>
{{else}}
<span class="disabled">Previous</span>
{{/if}}
{{#each (paginationPages)}}
{{#if isCurrent}}
<span class="current">{{number}}</span>
{{else}}
<a href="{{url}}">{{number}}</a>
{{/if}}
{{/each}}
{{#if (hasNextPage)}}
<a href="{{paginationNextUrl}}" data-page="next">Next</a>
{{else}}
<span class="disabled">Next</span>
{{/if}}
</nav>
</div>
Limitations
Complex
{{#if}}conditionals insidedata-postwon't work after client-side re-render (the template is cloned as-is).Single filter value per field (no multi-select).
All posts are loaded in the JSON index (works well for hundreds of posts; consider server-side pagination for thousands).