WP Manifestindependent plugin directory
manifest / content / fuzzify-search

Fuzzify Search – Add Instant Search Results for Static Sites

Instant results for native WordPress search forms without database calls. Works for both static and dynamic sites

★ 1stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/cheey2003/fuzzify-search/archive/refs/heads/main.zip
Updates itself. It ships its own updater (Troy), so new versions appear under Dashboard → Updates.

Fuzzify Search enhances the default WordPress search and the core Search block directly, by attaching to whatever standard search field is already on the page rather than replacing or registering anything: it adds instant, typo-tolerant search to WordPress that runs entirely in the visitor's browser. It writes one JSON index of your content and searches it with Fuse.js, so search behaves the same on the live site and in static HTML exports, where WordPress's own live search has no admin-ajax.php and no PHP results page to rely on. Nothing is sent to a server at search time: the browser downloads the index file once and searches it locally. It is tested with the free Simply Static, and there is no Pro version and no need for Simply Static Pro. You choose what is indexed, drag to set how results are ranked, and decide whether Enter opens a results page.

  • Version: 0.1.0
  • Author: Tangency
  • Requires: WordPress 6.0, PHP 7.4
  • Settings: Settings → Fuzzify Search
  • License: GPL-2.0-or-later (bundles Fuse.js 7.5.0, Apache-2.0, and, on the settings screen only, SortableJS 1.15.7 and Select2 4.1.0, both MIT)

Install

  1. Download fuzzify-search-<version>.zip from Releases (the attached file, not Source code) and upload it under Plugins → Add New → Upload Plugin, or copy the folder to wp-content/plugins/fuzzify-search/. The built scripts are included, so Node is not needed.
  2. Activate it. Activation creates a Search page (the results page) and builds the first index.
  3. If SearchWP Live Ajax Search is active, deactivate it. Fuzzify Search leaves any field that plugin has taken over alone.
  4. Clear any page cache so pages pick up the new script.

Fuzzify Search is the new name of Static Search (versions up to 0.2.0), which lived in subsite-static-search/. If you installed that version, switch over in this order: deactivate it, activate Fuzzify Search (your settings, hidden items and index carry over), then remove the old folder with wp plugin delete subsite-static-search or over SFTP. Do not use the Delete link in Plugins: it runs the old plugin's uninstall step, which clears the settings and hidden-item flags that Fuzzify Search now uses. The two cannot be active together.

Settings

Setting What it does
Post types Which content is searched. Default: everything WordPress' own search covers.
Fields to search Excerpt, content, categories/tags/other terms, product SKU. The title is always searched.
Content length limit Caps the body text kept per item, to keep the index small on large sites.
WooCommerce Leaves out Cart, Checkout and My account. Products set to hidden or "shop only" are always left out. WooCommerce's own Product Search widget/block is enhanced too: it marks its form with a hidden post_type field, which the script detects and uses to keep both the dropdown and the results page to that type.
Result ranking Drag-and-drop order of Title, Categories and tags, SKU, Excerpt and Body text, and, when several post types are searched, of the post types. See below.
Try it Type a search on the settings screen and see the ranked results and which field each matched in, using the values in the form as you change them.
Search box Minimum characters, delay, results in the dropdown, typo tolerance, thumbnails, highlighted matches with a colour you choose (WordPress' own colour picker), and, under a result, why it matched when that is not its title: a text snippet when the words were found in the text, or the category or tag ("Filed under: …") when they matched that.
Results page: Activate Send Enter to the results page. Unticked, pressing Enter (or a Search button) in a search box does nothing; the instant-results dropdown still works, a highlighted result still opens on Enter, and there is no "View all" link. The settings below then dim and are ignored (their saved values are kept).
Results page: Page The page Enter goes to, chosen from a searchable list (Select2). Must contain [static_search_results].
Old search addresses Forward /?s=term addresses to the results page. On by default.
Automatic rebuild Rebuild shortly after content is published, changed or removed.

Result ranking

Both lists are drag-and-drop (SortableJS). Each row is a tab: drag it by the six-dot grip on its left, or use the arrow buttons on its right, which also work from the keyboard and with screen readers. The top row ranks first; no numbers are shown, the order on screen is the ranking.

  • Field priority. A match in a field higher in the list always ranks above a match in a field lower down. Tick Same priority as above on a row to rank it together with the row above (the tab is tinted and drawn attached to the one above it). The defaults are Title, then Categories and tags together with SKU, then Excerpt, then Body text. Fields you don't search are ignored. Moving a row clears the "same priority" ticks around it, so a tie never quietly changes meaning.
  • Within a priority, whole-word matches come before matches inside a word, exact matches before typos (typos are forgiven only in titles, categories/tags and SKUs), and equal matches are newest first.
  • Post type priority (shown when more than one post type is searched). By default all types share one priority, which means no preference. Only between equally good matches orders, say, a Product and a Post that match equally well; a body-text match on a Product still ranks below a title match on a Post. Before everything else puts every result of the top type ahead of the next type's, whatever the field.
  • Try it. Ranking changes show in the box straight away, before you save. Changes to what is indexed (post types, fields) show after you save, because the index is rebuilt then.

Under the hood each row saves a rank number (ranking[field], type_priority[type]), so the same settings can be set with the static_search_settings filter.

To hide a single item, tick Hide this item from search in the Fuzzify Search box on its edit screen. Hidden items are labelled in the Posts / Pages / Products lists and listed on the settings screen. Password-protected posts are indexed by title only.

For developers

Filters

Filter Purpose
static_search_settings Override any setting at runtime.
static_search_include_post ( bool $include, WP_Post $post ) — keep a post out of (or in) the index.
static_search_item ( array $item, WP_Post $post ) — add fields or change an index entry.
static_search_config Change what is passed to the script.
static_search_selector CSS selector of the fields to enhance (default input[type="search"][name="s"]).

Events — static_search_index_built fires after each build.

Script API — window.StaticSearch.search( 'query', { type: 'product' } ) returns a promise of [ { item, score, matched } ] (matched lists the fields the words were found in); window.StaticSearch.rescan() enhances search fields added after load.

Styling — colours come from CSS custom properties (--static-search-bg, --static-search-fg, --static-search-border, --static-search-hover, --static-search-muted, --static-search-mark, --static-search-shadow; the highlight colour setting prints --static-search-mark for you); a [data-scheme="dark"] variant is included.

SEO — the results page is set to noindex through WordPress' robots filter and All in One SEO's. Other SEO plugins that print their own robots tag need the results page set to noindex in their settings.

Source — the scripts in assets/js/ are minified builds of src/, which lives in the GitHub repo (the downloadable zip leaves it out). Rebuild with npm install && npm run build; test with npm test. The Select2 files in assets/vendor/select2/ are the unmodified upstream release.

Releasing a new version

Installable zips are built by GitHub Actions (.github/workflows/release.yml) and attached to a GitHub Release. The folder inside the zip is always fuzzify-search/, whatever the version, so uploading a newer zip under Plugins → Add New → Upload Plugin replaces the installed plugin instead of adding a second, versioned copy. Use the attached fuzzify-search-<tag>.zip, not GitHub's Source code download, whose folder name carries the version.

  1. Bump the version in fuzzify-search.php (the Version: header and STATIC_SEARCH_VERSION), package.json and package-lock.json, and the Stable tag in readme.txt. Add the changelog entry here and in readme.txt.
  2. Run npm run build and npm test, then commit.
  3. Tag it and push the tag, e.g. git tag v0.1.1 && git push origin v0.1.1. Only tags starting with v start the workflows.
  4. Actions builds the zip with git archive (dev files and .github left out, per .gitattributes) and attaches it to that tag's Release with generated notes.

If a release is ever published without the zip, run the Release workflow from the Actions tab and enter the existing tag.

Publishing to WordPress.org

The same tag also starts Deploy to WordPress.org (.github/workflows/deploy-wporg.yml, built on 10up's deploy action). It checks that the version in the plugin header, STATIC_SEARCH_VERSION, package.json and the Stable tag in readme.txt all match the tag, runs the tests, checks that the committed scripts are what the source builds, and then commits trunk and tags/<version> to the WordPress.org SVN repository in one commit. The files it sends are the same ones as in the release zip.

One-time setup. In the repository's Settings → Environments, create an environment named wordpress-org, add yourself under Required reviewers, and add two secrets there: SVN_USERNAME (your WordPress.org username) and SVN_PASSWORD (the SVN password from your WordPress.org profile, under Account & Security; it is separate from your login password). Each deploy then waits for your approval before it runs.

Pushing a tag is always a dry run: it goes through every check and produces the log of what SVN would receive, but publishes nothing. A real publish only happens from a manual run: Actions tab → Deploy to WordPress.org → Run workflow → enter the tag → untick Dry run. That run also waits for your approval before anything happens.

SVN versions are permanent. If tags/<version> already exists the deploy does nothing, so a bad release is fixed by shipping a new version. The icon, banner and screenshots for the WordPress.org page are in .wordpress-org/. Each deploy syncs that folder to SVN's assets/ folder (and removes anything else in there), and .gitattributes keeps it out of the zip. Because a deploy stops early when tags/<version> already exists, changes to the artwork or to readme.txt alone do not go out with it: ship a new version, or use 10up's asset-update action. design/ holds the sources of the icon (icon.svg) and banner (banner.html, which runs the plugin's own script and styles against a demo index); the screenshots are captures of the plugin on a demo site.

Changelog

0.1.0 (2026-09-22)

First release as Fuzzify Search, ready for the WordPress.org directory.

  • Renamed. The plugin folder and text domain are fuzzify-search. Settings, hooks, filters, the shortcode, window.StaticSearch and the wp static-search command keep their names, so nothing else needs changing.
  • Rebuild errors. The notice after a failed Rebuild index now uses fixed wording; the reason is listed in the warnings below it, as before.
  • Old search addresses. The forwarding script is printed with WordPress' own script function.
  • Translations. The plugin no longer loads its own translation files; WordPress.org provides them.
  • Matched categories and tags. A result whose words matched a category or tag, and not its title or text, now says which ("Filed under: Post- pregnancy", with the matching word highlighted), in the dropdown and on the results page. Before, it showed nothing that explained why it was there. It goes with the Show a piece of the text around the match setting, whose label now covers both.