ghost-search: Our First Open Source Library for Ghost
After a bored day, a month ago, I decided to work on something new that might help others too. So I started working on ghost-search. Why? I felt that there is no search library for Ghost that takes advantage of their API. Hence ghost-search.
You can search through any Ghost resource (posts, tags, users) and use most of their parameters (fields, filter, include, order, formats, limit).
ghost-search is using as a search algorithm fuzzysort. Why not lunr or fuse you may ask? Well, the answer is simple. I wanted to use a search that returns relevant results to my query. After some heavy tests with lunr, fuse and other libraries, I was unhappy with the results that I've got. So thank you farzher for creating this simple and usable search library.
Read more here if you want to know how to setup and customize ghost-search.
Enough boring stuff, let's start with examples:
How to:
- Set a basic search
- Display a message if there are no posts found
- Search only through tags
- Search posts from a custom collection
- Search posts that are published after 01 Jan 2018
- Search through the title and content of posts
- Get the results when a button is clicked
- Get proper results when your Ghost is on a sub-path
- Set multiple instances of ghost-search on the same page
- Add a loading icon when you have a lot of posts
- Limit the results displayed
more examples in the future.
Set a basic search
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
results: '#my-custom-results'
})
</script>
Display a message if there are no posts found
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
on: {
afterDisplay: function(results){
if (results.total == 0 && document.getElementById('my-custom-input').value != '') {
let resultsElement = document.getElementById('my-custom-results');
let e = document.createElement('p');
e.innerHTML = 'No results';
resultsElement.appendChild(e.firstChild);
};
}
}
})
</script>
Search only through tags
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
options: {
keys: [
'name',
],
},
api: {
resource: 'tags',
parameters: {
fields: ['name', 'slug'],
},
},
template: function(result) {
let url = [location.protocol, '//', location.host].join('') + '/tag';
return '<a href="' + url + '/' + result.slug + '/">' + result.name + '</a>';
}
})
</script>
Search posts from a custom collection
Let's say we have a routes.yaml
like this:
routes:
collections:
/themes/:
permalink: /themes/{slug}/
filter: tag:themes
data: tag.themes
/:
permalink: /{slug}/
filter: tag:-themes
template:
- index
taxonomies:
tag: /tag/{slug}/
author: /author/{slug}/
/themes/
is a collection that will show posts with tag themes. A post like this will have the url example.com/themes/post-slug
.
Our ghost-search will become:
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
options: {
keys: [
'title',
],
},
api: {
resource: 'posts',
parameters: {
fields: ['title', 'slug'],
filter: 'tags:[themes]',
include: 'tags'
},
},
template: function(result) {
let collection = 'themes';
let url = [location.protocol, '//', location.host].join('') + '/' + collection;
return '<a href="' + url + '/' + result.slug + '/">' + result.title + '</a>';
},
})
</script>
Unfortunately our theme doesn't have any custom collections yet. So we can't put a live example for this.
Search posts that are published after 01 Jan 2018
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
api: {
parameters: {
filter: "published_at:>'2018-01-01 00:00:00'",
},
}
})
</script>
Search through the title and content of posts
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
options: {
keys: [
'title',
'plaintext'
],
},
api: {
resource: 'posts',
parameters: {
fields: ['title', 'slug', 'plaintext'],
formats: 'plaintext',
},
},
})
</script>
Get the results when a button is clicked
<form>
<div id="my-custom-input"></div>
<input type="submit" id="my-custom-button">
</form>
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
button: '#my-custom-button'
})
</script>
Get proper results when your Ghost is on a sub-path
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
template: function(result) {
let url = [location.protocol, '//', location.host].join('') + '/sub-path/';
return '<a href="' + url + '/' + result.slug + '">' + result.title + '</a>';
}
})
</script>
Set multiple instances of ghost-search on the same page
<input id="my-custom-input-1">
<div id="my-custom-results-1"></div>
<input id="my-custom-input-2">
<div id="my-custom-results-2"></div>
<script type="text/javascript">
let ghostSearch1 = new GhostSearch({
input: '#my-custom-input-1',
results: '#my-custom-results-1'
})
let ghostSearch2 = new GhostSearch({
input: '#my-custom-input-2',
results: '#my-custom-results-2'
})
</script>
Add a loading icon when you have a lot of posts
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
on: {
beforeFetch: function(){
let resultsElement = document.getElementById('my-custom-results');
let e = document.createElement('div');
e.innerHTML = '<img src="https://loading.io/spinners/spinner/index.ajax-spinner-preloader.svg">';
resultsElement.appendChild(e.firstChild);
},
afterFetch: function(results){
let resultsElement = document.getElementById('my-custom-results');
resultsElement.innerHTML = '';
}
}
})
</script>
Limit the results displayed
<input id="my-custom-input">
<div id="my-custom-results"></div>
<script type="text/javascript">
let ghostSearch = new GhostSearch({
input: '#my-custom-input',
results: '#my-custom-results',
options: {
limit: 3
}
})
</script>
more examples in the future.