{"id":305148,"url":"https://github.com/HauntedThemes/ghost-search","last_synced_at":"2025-07-16T12:31:31.962Z","repository":{"id":47939940,"uuid":"149125702","full_name":"HauntedThemes/ghost-search","owner":"HauntedThemes","description":"A simple but powerful search library for Ghost Blogging Platform.","archived":false,"fork":false,"pushed_at":"2023-01-05T00:54:32.000Z","size":545,"stargazers_count":117,"open_issues_count":13,"forks_count":18,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-04-23T14:43:47.199Z","etag":null,"topics":["ghost","search"],"latest_commit_sha":null,"homepage":"https://www.hauntedthemes.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HauntedThemes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-17T13:00:17.000Z","updated_at":"2023-09-08T08:20:07.000Z","dependencies_parsed_at":"2023-02-03T02:46:26.072Z","dependency_job_id":null,"html_url":"https://github.com/HauntedThemes/ghost-search","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HauntedThemes%2Fghost-search","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HauntedThemes%2Fghost-search/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HauntedThemes%2Fghost-search/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HauntedThemes%2Fghost-search/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HauntedThemes","download_url":"https://codeload.github.com/HauntedThemes/ghost-search/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226130353,"owners_count":17578097,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ghost","search"],"created_at":"2024-01-07T07:56:20.737Z","updated_at":"2024-11-24T05:31:05.685Z","avatar_url":"https://github.com/HauntedThemes.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","others"],"sub_categories":[],"readme":"[![Min Ghost Version](https://img.shields.io/badge/Min%20Ghost%20v.-%3E%3D%203.0.0-blue.svg)](https://github.com/TryGhost/Ghost)\n[![npm version](https://badge.fury.io/js/ghost-search.svg)](https://www.npmjs.com/package/ghost-search)\n\n# ghost-search\n\nA simple but powerful search library for [Ghost Blogging Platform](https://ghost.org/).\n\n## Setup\n\n### Step 1 - Setup Content API Client Library\n\nGet the [latest version](https://unpkg.com/@tryghost/content-api) of Ghost Content API Client Library from unpkg.com.\n\n```js\n\u003cscript src=\"https://unpkg.com/@tryghost/content-api@{version}/umd/content-api.min.js\"\u003e\u003c/script\u003e\n```\n\nAdd the script before the `{{ghost_foot}}` tag. This will, most likely, be in `default.hbs`.\n\n### Step 2 - Setup ghost-search\n\nOpen your theme directory and navigate to `assets` subdirectory. \\\nCreate a directory called `js`, if there isn't already one in there, and add the minified version of `ghost-search` in it. \\\nOpen `default.hbs` that is located at the root of your theme. \\\nAt the bottom of this file you should see `{{ghost_foot}}`. \\\nAdd the following code above it (after the content-api script at Step 1) and save it:\n\n```\n\u003cscript type=\"text/javascript\" src=\"{{asset \"js/ghost-search.min.js\"}}\"\u003e\u003c/script\u003e\n```\n\nAdd the following code, in a `.hbs` file, where you want to show the search input:\n\n```html\n\u003cinput id=\"ghost-search-field\"\u003e\n```\n\nAdd the following code, in a `.hbs` file, where you want to show the search results:\n\n```html\n\u003cdiv id=\"ghost-search-results\"\u003e\u003c/div\u003e\n```\n\nYou will need to initialize `ghost-search` to make the search functional. \\\nAdd the following js code after you included `ghost-search.min.js`:\n\n```javascript\n\u003cscript\u003e\n    let ghostSearch = new GhostSearch({\n        key: '22444f78447824223cefc48062', // This is just a demo key. Replace the key with a real one. See Step 3.\n        url: 'https://demo.ghost.io', // This is just a demo host. Replace the demo url with a real one. See Step 3.\n    })\n\u003c/script\u003e\n```\n\n### Step 3 - Setup a Custom integration\n\nGo in your Ghost's dashboard -\u003e Integrations -\u003e Add custom integration \\\nSet a name: Haunted Themes Search \\\nGet the Content API Key and replace the demo key with this one. [More details](https://ghost.org/docs/api/v3/content/#key). \\\nGet the admin domain. This will be different in some cases. [More details](https://ghost.org/docs/api/v3/content/#url).\n\n## Use ghost-search from CDN\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/ghost-search@1.0.1/dist/ghost-search.min.js\"\u003e\u003c/script\u003e\n```\n\n## npm\n\n```javascript\nnpm install ghost-search\n```\n\n## Live Examples\n\n[Set a basic search](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#set-a-basic-search) \\\n[Display a message if there are no posts found](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#display-a-message-if-there-are-no-posts-found) \\\n[Search only through tags](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#search-only-through-tags) \\\n[Search posts from a custom collection](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#search-posts-from-a-custom-collection) \\\n[Search posts that are published after 01 Jan 2018](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#search-posts-that-are-published-after-01-jan-2018) \\\n[Search through the title and content of posts](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#search-through-the-title-and-content-of-posts) \\\n[Get the results when a button is clicked](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#get-the-results-when-a-button-is-clicked) \\\n[Get proper results when your Ghost is on a sub-path](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#get-proper-results-when-your-ghost-is-on-a-sub-path) \\\n[Set multiple instances of ghost-search on the same page](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#set-multiple-instances-of-ghost-search-on-the-same-page) \\\n[Add a loading icon when you have a lot of posts](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#add-a-loading-icon-when-you-have-a-lot-of-posts) \\\n[Limit the results displayed](https://www.hauntedthemes.com/ghost-search-our-first-open-source-library-for-ghost/#limit-the-results-displayed)\n\n## Default Options\n\n```js\n{\n    host: '',\n    key: '',\n    version: 'v2',\n    input: '#ghost-search-field',\n    results: '#ghost-search-results',\n    button: '',\n    development: false,\n    defaultValue: '',\n    template: function(result) {\n        let url = [location.protocol, '//', location.host].join('');\n        return '\u003ca href=\"' + url + '/' + result.slug + '/\"\u003e' + result.title + '\u003c/a\u003e';  \n    },\n    trigger: 'focus',\n    options: {\n        keys: [\n            'title'\n        ],\n        limit: 100,\n        threshold: -3500,\n        allowTypo: false\n    },\n    api: {\n        resource: 'posts',\n        parameters: { \n            limit: 'all',\n            fields: ['title', 'slug'],\n            filter: '',\n            include: '',\n            order: '',\n            formats: '',\n        },\n    },\n    on: {\n        beforeDisplay: function(){},\n        afterDisplay: function(results){},\n        beforeFetch: function(){},\n        afterFetch: function(){}\n    }\n}\n```\n\n## Options\n\n### url\n\nThe url that needs to be set in order for Content API to properly authenticate. [More details](https://docs.ghost.org/api/content/#url).\n\n### key\n\nThe key that needs to be set in order for Content API to properly authenticate. [More details](https://docs.ghost.org/api/content/#key).\n\n### version\n\nThe version that needs to be set in order for Content API to properly authenticate. [More details](https://ghost.org/docs/api/v3/content/#path--version).\n\nDefault value: `'v3'`\n\n### input\n\nThe ID of the input field that will be transformed into search filter. \\\nYou can set your own id if you want like this:\n\n```html\n\u003cinput id=\"my-custom-input\"\u003e\n```\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        input: '#my-custom-input'\n    })\n\u003c/script\u003e\n```\n\nDefault value: `'#ghost-search-field'`\n\n### results\n\nThe ID of the element that will be transformed into search results. \\\nYou can set your own id if you want like this:\n\n```html\n\u003cdiv id=\"my-custom-results\"\u003e\u003c/div\u003e\n```\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        results: '#my-custom-results'\n    })\n\u003c/script\u003e\n```\n\nDefault value: `'#ghost-search-results'`\n\n### button\n\nThe ID of the element that will trigger the search results after it's clicked. \\\nBy default, the button parameter is empty because `ghost-search` displays the results when you write in the input. \\\nTo make this work you need to add the input and the button in a `form` element:\n\n```html\n\u003cform\u003e\n    \u003cinput id=\"my-custom-input\"\u003e\n    \u003cinput type=\"submit\" id=\"my-custom-button\"\u003e\n\u003c/form\u003e\n\u003cdiv id=\"my-custom-results\"\u003e\u003c/div\u003e\n```\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        input: '#my-custom-input',\n        results: '#my-custom-results',\n        button: '#my-custom-button'\n    })\n\u003c/script\u003e\n```\n\nDefault value: `''`\n\n### defaultValue\n\nA parameter that will set a default value for the input and performs the search.\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        defaultValue: 'ghost'\n    })\n\u003c/script\u003e\n```\n\nDefault value: `''`\n\n### template\n\nThe template that will be used to render individual items in the search result. \\\nThe method has a parameter `result` that stores all the data that you can use inside the method.\n\n#### Examples:\n\nMake the results a list and wrap each result with `\u003cli\u003e`:\n\n```html\n\u003cdiv id=\"my-custom-input\"\u003e\u003c/div\u003e\n\u003cul id=\"my-custom-results\"\u003e\u003c/ul\u003e\n```\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        input: '#my-custom-input',\n        results: '#my-custom-results',\n        template: function(result) {\n            let url = [location.protocol, '//', location.host].join('');\n            return '\u003cli\u003e\u003ca href=\"' + url + '/' + result.slug + '\"\u003e' + result.title + '\u003c/a\u003e\u003c/li\u003e';  \n        }\n    })\n\u003c/script\u003e\n```\n\nSet url with sub-path:\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        input: '#my-custom-input',\n        results: '#my-custom-results',\n        template: function(result) {\n            let url = [location.protocol, '//', location.host].join('') + '/sub-path/';\n            return '\u003ca href=\"' + url + '/' + result.slug + '\"\u003e' + result.title + '\u003c/a\u003e';  \n        }\n    })\n\u003c/script\u003e\n```\n\nDefault value:\n\n```js\nfunction(result) {\n    let url = [location.protocol, '//', location.host].join('');\n    return '\u003ca href=\"' + url + '/' + result.slug + '\"\u003e' + result.title + '\u003c/a\u003e';  \n}\n```\n\n### trigger\n\nTells the script when to fetch the collection of data. The default value is `focus`, that means when a user clicks the input, all the data is fetched. \\\nYou can also use `load`. This will fetch the data when the page loads.\n\n`load` might **create a DDOS effect** because it loads all the data every time a page loads. Use carefully.\n\nDefault value: `'focus'`\n\n### options\n\n`ghost-search` is using `fuzzysort` as an algorithm for search. The `option` parameter supports all the options from [fuzzysort](https://github.com/farzher/fuzzysort#options).\nBy default, `ghost-search` is showing the first 10 results and searches only based on title.\n\nLet's try another example that will show the first 3 results and searches both title and the content of a collection:\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        options: {\n            keys: [\n                'title',\n                'plaintext'\n            ],\n            limit: 3,\n        },\n        api: {\n            resource: 'posts',\n            parameters: { \n                fields: ['title', 'slug', 'plaintext'],\n                formats: 'plaintext',\n            },\n        },\n    })\n\u003c/script\u003e\n```\n\nDefault value:\n\n```js\n{\n    keys: [\n        'title'\n    ],\n    limit: 10,\n    threshold: -3500,\n    allowTypo: false\n}\n```\n\n### api\n\nThe api parameter is an object that supports most of the [resources](https://docs.ghost.org/api/content/#resources) and [parameters](https://docs.ghost.org/api/content/#parameters) by [Content API](https://docs.ghost.org/api/content/).\n\nResources: [posts](https://docs.ghost.org/api/content/#posts), [tags](https://docs.ghost.org/api/content/#tags), [authors](https://docs.ghost.org/api/content/#authors) \\\nParameters: [fields](https://docs.ghost.org/api/content/#fields), [filter](https://docs.ghost.org/api/content/#filter), [include](https://docs.ghost.org/api/content/#include), [order](https://docs.ghost.org/api/content/#order), [formats](https://docs.ghost.org/api/content/#formats), [limit](https://docs.ghost.org/api/content/#limit)\n\nExamples:\n\nSearch through tags:\n\n```html\n\u003cscript type=\"text/javascript\"\u003e\n    let ghostSearch = new GhostSearch({\n        options: {\n            keys: [\n                'name',\n            ],\n        },\n        api: {\n            resource: 'tags',\n            parameters: { \n                fields: ['name', 'slug'],\n            },\n        },\n        template: function(result) {\n            let url = [location.protocol, '//', location.host].join('') + '/tag';\n            return '\u003ca href=\"' + url + '/' + result.slug + '/\"\u003e' + result.name + '\u003c/a\u003e';  \n        },\n    })\n\u003c/script\u003e\n```\n\nSearch through a custom collection:\n\nLet's say we have a `routes.yaml` like this:\n\n```yaml\nroutes:\n\ncollections:\n  /themes/:\n    permalink: /themes/{slug}/\n    filter: tag:themes\n    data: tag.themes\n  /:\n    permalink: /{slug}/\n    filter: tag:-themes\n    template:\n      - index\n\ntaxonomies:\n  tag: /tag/{slug}/\n  author: /author/{slug}/\n```\n\n`/themes/` is a collection that will show posts with tag `themes`. A post like this will have the url `example.com/themes/post-slug`.\n\nOur `ghost-search` will become:\n\n```js\nlet ghostSearch = new GhostSearch({\n    options: {\n        keys: [\n            'title',\n        ],\n    },\n    api: {\n        resource: 'posts',\n        parameters: { \n            fields: ['title', 'slug'],\n            filter: 'tags:[themes]',\n            include: 'tags'\n        },\n    },\n    template: function(result) {\n        let collection = 'themes';\n        let url = [location.protocol, '//', location.host].join('') + '/' + collection;\n        return '\u003ca href=\"' + url + '/' + result.slug + '/\"\u003e' + result.title + '\u003c/a\u003e';  \n    },\n})\n```\n\n### on\n\nThis parameter has 4 methods in it: `beforeDisplay`, `afterDisplay`, `beforeFetch`, `afterFetch`. \\\n`afterDisplay` and `afterFetch` have a parameter `results` that contains the results fetched. \\\nThey are useful to do things before results are visible to users.\n\nExample:\n\n```\nlet ghostSearch = new GhostSearch({\n    on: {\n        beforeFetch: function(){\n            // Create a div that has a spinning icon\n            console.log('Loading appears');\n        },\n        afterFetch: function(results){\n            // Remove the spinning icon\n            console.log('Loading disappears');\n        }\n    }\n})\n```\n\n## Contributing\n\nAll changes should be committed to `src/` files only.\n\n## Known Issues\n* DDOS effect when `trigger` is set to `load`.\nIf you have a lot of posts and set `trigger` to `load` you might get a DDOS effect because you are loading all the post everything a page loads. It would be better to just set `trigger` to `focus`.\n\n## Changelog\n\n### 1.1.0 - 15 Nov 2019\n* Migrated to Ghost v3\n\n### 1.0.1 - 28 Jan 2019\n* Editable limit parameter. [5](https://github.com/HauntedThemes/ghost-search/issues/5)\n\n### 1.0.0 - 21 Jan 2019\n* Public API (deprecated) will not work anymore. The library is accessing Content API.\n\n### 0.1.1 - 29 Nov 2018\n* Added `defaultValue` parameter.\n\n### 0.1.0 - 17 Sep 2018\n* Initial release\n\n## Thank You\nghost-search is using as a search algorithm [fuzzysort](https://github.com/farzher/fuzzysort). \\\nThank you [farzher](https://github.com/farzher/) for creating fuzzysort, a simple and usable search library.\n\n## Copyright \u0026 License\n\nCopyright (c) 2019 Haunted Themes - Released under the [MIT license](LICENSE). \\\n[Ghost is a trademark of The Ghost Foundation](https://ghost.org/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHauntedThemes%2Fghost-search","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FHauntedThemes%2Fghost-search","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHauntedThemes%2Fghost-search/lists"}