RF JSON Static Search - JSON Search Plugin untuk Publii
Plugin ini adalah plugin CMS Publii yang berguna untuk memberi fitur search pada halaman web.
Tutorialnya ada di artikel ini.
Cara Kerja
Cara kerjanya adalah dengan mem-fetch JSON feed kemudian memfilternya berdasarkan pencarian.
Teknologi yang Digunakan
- HTML
- CSS
- JavaScript
- Publii CMS
Screenshot
Rekonstruksi
Untuk membuat aplikasi seperti ini, buat sebuah folder kosong, kemudian isi dengan script-script ini:
- main.js
- plugin.json
Kemudian siapkan sebuah gambar SVG dan beri nama "thumbnail.svg". Letaknya di folder tadi.
Isi dari "plugin.json" adalah seperti ini:
{
"name": "RF JSON Static Search",
"description": "Publii Search Based on JSON Feed. Modified from Google Custom Search plugin by TidyCustoms.",
"license": "GPL-3.0",
"author": "RAKIFSUL",
"version": "2025.06.22",
"scope": "site",
"minimumPubliiVersion": "0.40.0",
"usePluginSettingsView": false,
"messageInOptions": {
"type": "info",
"text": "Make sure 'JSON Feed', 'Search' and 'Search subpage' options are enabled."
},
"requiredFeatures": [
"customSearch"
],
"config": [
{
"name": "jsonUrl",
"label": "JSON URL",
"note": "You can change the default JSON URL.",
"group": "Search config",
"value": "./search.json",
"type": "text"
},
{
"name": "searchParam",
"label": "Search parameter",
"note": "You can change the default \"q\" parameter.",
"group": "Search config",
"value": "q",
"type": "text"
},
{
"name": "searchPlaceholder",
"label": "Input placeholder",
"note": "",
"group": "Theme config",
"value": "search...",
"type": "text"
},
{
"name": "searchSubmitLabel",
"label": "Submit button label",
"note": "",
"group": "Theme config",
"value": "Submit",
"type": "text"
}
]
}
Isi dari "main.json" adalah seperti ini:
// const fs = require(fs);
class SHBJSONStaticSearchForPublii {
constructor(API, name, config) {
this.API = API;
this.name = name;
this.config = config;
this.finalSearchObj = [];
}
addInsertions() {
this.API.addModifier('postItemData', this.modifyHTML.bind(this), 1, this);
this.API.addInsertion('customSearchInput', this.addSearchInput, 1, this);
this.API.addInsertion('customSearchContent', this.addSearchContent, 1, this);
}
addSearchInput(rendererInstance, context) {
let actionUrl = '';
if (rendererInstance.globalContext && rendererInstance.globalContext.website) {
actionUrl = rendererInstance.globalContext.website.searchUrl;
}
let output = `<form action="${actionUrl}" class="search__form">
<input
class="search__input"
type="search"
name="${this.config.searchParam}"
placeholder="${this.config.searchPlaceholder}"
aria-label="${this.config.searchPlaceholder}"
autofocus/>
<button type="submit" class="search__button"><span>${this.config.searchSubmitLabel}</span></button>
</form>`;
return output;
}
addSearchContent(rendererInstance, context) {
let actionUrl = '';
if (rendererInstance.globalContext && rendererInstance.globalContext.website) {
actionUrl = rendererInstance.globalContext.website.searchUrl;
}
let output = `
<!-- <script type="text/javascript" src="https://unpkg.com/js-search@1.3.7/dist/umd/js-search.min.js"></script> -->
<script type="text/javascript" src="js-search.min.js"></script>
<script type="text/javascript" src="xml-js.js"></script>
<form
action="${actionUrl}"
class="search-page-form">
<input
type="search"
name="${this.config.searchParam}"
placeholder="${this.config.searchPlaceholder}"
class="search-page-input"/>
<button type="submit" class="search-page-button"><span>${this.config.searchSubmitLabel}</span></button>
</form>
<div id="js-search-results"></div>
<script>
(async function () {
console.log("${this.config.jsonUrl}");
console.log("${this.config.searchParam}");
let url = "${this.config.jsonUrl}";
let j = await fetch(url);
let jsn = await j.json();
let search = new JsSearch.Search('url');
search.addIndex('title');
search.addIndex('excerpt');
//search.addDocuments(JSON.parse(jsn));
search.addDocuments(jsn);
const params = new URLSearchParams(window.location.search)
let results = search.search(params.get("${this.config.searchParam}"));
let elm = document.querySelector("#js-search-results");
results.forEach((result)=>{
console.log(result);
elm.innerHTML += '<h5><a href="'+ result.url +'">' + result.title + '</a></h5><p>' + result.excerpt + '</p>'
});
// let search = new JsSearch.Search('url');
// search.addIndex('title');
// search.addIndex('content_html');
// search.addDocuments(jsn.items);
// const params = new URLSearchParams(window.location.search)
// let results = search.search(params.get("${this.config.searchParam}"));
// let elm = document.querySelector("#js-search-results");
// results.forEach((result)=>{
// console.log(result);
// elm.innerHTML += '<h5><a href="'+ result.url +'">' + result.title + '</a></h5><p>' + result.summary + '</p>'
// });
})();
</script>
`;
return output;
}
modifyHTML(rendererInstance, postData) {
const objct = {
title: postData.title,
url: postData.url,
excerpt: postData.excerpt
};
this.finalSearchObj.push(objct);
var result = this.API.createFile("[ROOT-FILES]/search.json", JSON.stringify(this.finalSearchObj, null, 2), this);
if (result.status != "FILE_SAVED") {
this.generatedContent["errors"] += result.status;
}
return postData;
}
}
module.exports = SHBJSONStaticSearchForPublii;
Setelah selesai ditulis, compress folder project ini menjadi zip, kemudian install melalui CMS Publii.