migrating from instantsearch templates to block themes - WebDevStudios/wp-search-with-algolia GitHub Wiki
Since version 2.10.4, WP Search with Algolia no longer loads instantsearch.php or instantsearch-modern.php on block (FSE) themes. It still loads the InstantSearch assets and the algolia config object, and lets your theme's block-based Search template render the page. You supply the InstantSearch markup and the JavaScript that starts it.
This guide covers two paths:
-
Migrate (recommended): move the markup and JS from your
instantsearch*.phpoverride into a block-based search template. -
Opt out: return
falsefrom thealgolia_is_block_themefilter so the PHP template files load as they always have.
Classic (PHP) themes are not affected. Their instantsearch*.php templates, including overrides in your-theme/algolia/, load exactly as before.
The PHP templates call get_header() and get_footer(). Block themes have no header.php or footer.php, and a PHP template can't render block template parts or block styles properly (#216, #355). Site owners started building InstantSearch into block templates themselves. The 2.10.x releases changed how the plugin loads assets to support that:
| Version | Change | Reference |
|---|---|---|
| 2.10.4 | On a block theme with the InstantSearch setting on, the plugin enqueues InstantSearch CSS/JS but returns the theme's own template instead of instantsearch*.php. |
#522, PR #524 |
| 2.10.3 | Added the algolia_is_block_theme filter, plus a built-in callback that sets it from wp_is_block_theme(). On block themes the algolia config is printed again. |
#504, PR #505 |
| 2.10.2 | Added the Insights option. Both InstantSearch templates were updated (template @version 2.10.2). |
Changelog |
| 2.10.0 | Config and assets stopped loading when only "native search template" mode was on. This broke hand-built FSE integrations. | PR #474 |
What the plugin loads on a search results page depends on two things: whether algolia_is_block_theme is true, and the Search results source setting under Algolia Search > Search Page.
| Theme / filter | Search results source |
algolia config printed |
InstantSearch CSS/JS enqueued | Template rendered |
|---|---|---|---|---|
| Classic theme | Use Algolia with InstantSearch.js | Yes | Yes |
instantsearch.php or instantsearch-modern.php (theme override first) |
| Block theme | Use Algolia with InstantSearch.js | Yes | Yes | The theme's block Search template (search.html) |
| Block theme | Use Algolia, keep your theme's search template | Yes | No, enqueue them yourself | The theme's block Search template |
Block theme, filter forced to false
|
Use Algolia with InstantSearch.js | Yes | Yes |
instantsearch*.php, same as a classic theme |
The code behind this, in includes/:
-
class-algolia-compatibility.php:maybe_block_theme()is hooked toalgolia_is_block_themeat priority 10 and returnswp_is_block_theme(), unless an earlier callback already returnedtrue. -
class-algolia-template-loader.php: the constructor runs oninitat priority 20. When the filter is true, it keeps going and prints thealgoliaconfig inwp_footer(or inwp_headif scripts load in the header). Block themes get this config on every front-end page, not only on search. -
Algolia_Template_Loader::template_loader()runs ontemplate_include. On a search request with the InstantSearch setting on, a block theme only getsload_instantsearch_assets(), and the original$templateis returned. Otherwise,load_instantsearch_template()loads the assets and finds the PHP file. -
load_instantsearch_assets()enqueues thealgolia-instantsearchstyle and script onwp_enqueue_scripts, then firesalgolia_instantsearch_scripts. The script depends onalgolia-search(algoliasearch-lite),underscore, andwp-util, so those load too.
The InstantSearch setting also routes the main WordPress search query through Algolia on the back end. The "keep your theme's search template" mode does this as well.
The migration splits each instantsearch*.php file in two. The HTML goes into the block Search template. The <script> that starts InstantSearch goes into a JS file that you enqueue. This is the split tw2113 described in #216 and on the wordpress.org support forum. Since 2.10.4, the plugin loads the assets and config for you.
-
Check the prerequisites. You need WP Search with Algolia 2.10.4 or later and an active block theme (
wp_is_block_theme()returnstrue). Set Algolia Search > Search Page > Search results source to Use Algolia with InstantSearch.js. Make sure the Searchable posts index is indexed. -
Start from your current template. Open your override (
your-theme/algolia/instantsearch-modern.phporinstantsearch.php). If you have no override, open the plugin's copy intemplates/. Drop theget_header()andget_footer()calls. -
Move the markup into the Search template. Copy everything from
<div id="ais-wrapper">through its closing</div>. Put it in the theme's Search template, keeping the header and footer template parts:<!-- wp:template-part {"slug":"header","tagName":"header"} /--> <!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} --> <main class="wp-block-group"> <!-- wp:html --> <div id="ais-wrapper"> <!-- …markup copied from instantsearch-modern.php… --> </div> <!-- /wp:html --> </main> <!-- /wp:group --> <!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
You can add this to
your-theme/templates/search.html. You can also use Appearance > Editor > Templates > Search Results: replace the Query Loop with a Custom HTML block. Template edits saved in the Site Editor override the theme file. -
Replace PHP-only pieces in the markup. A block template can't run PHP. The
esc_html_e()facet headings ("Post Types", "Categories", "Tags", "Users") must become plain text. If you need them translated, use a dynamic block (see the next section). -
Move the JavaScript into a file. Copy the contents of the inline
<script type="text/javascript">, but not the tag itself, into a file such asyour-theme/assets/js/algolia-instantsearch.js. Keep thewindow.addEventListener( 'load', … )wrapper. It makes sureinstantsearch,algoliasearch, and thealgoliaconfig exist before the code runs. -
Enqueue the file from the plugin's InstantSearch hook.
algolia_instantsearch_scriptsfires only when the plugin enqueues InstantSearch, so your script loads only on the search page:add_action( 'algolia_instantsearch_scripts', function () { wp_enqueue_script( 'my-theme-algolia-instantsearch', get_theme_file_uri( 'assets/js/algolia-instantsearch.js' ), [ 'algolia-instantsearch' ], wp_get_theme()->get( 'Version' ), true ); } );
-
Remove the unused PHP override. On a block theme,
your-theme/algolia/instantsearch*.phpdoesn't load any more. Delete it, unless you plan to opt out (see below). -
Test. Load
/?s=test. The page source should containvar algolia = {…}andinstantsearch.production.min.js. Hits, facets, and pagination should render in your block layout, and the browser console should show no errors.
The legacy template renders hits with wp.template( 'instantsearch-hit' ), which is an Underscore/Backbone template. It needs two extra steps:
-
The
<script type="text/html" id="tmpl-instantsearch-hit">block must be on the page. A Custom HTML block may strip<script>for users who don't haveunfiltered_html. Thealgolia_instantsearch_after_hitaction inside it also can't run in a block template. Print it from PHP:add_action( 'wp_footer', function () { if ( ! is_search() ) { return; } ?> <script type="text/html" id="tmpl-instantsearch-hit"> <!-- …hit template copied from instantsearch.php… --> </script> <?php } );
-
Alternatively, switch to the modern template, which uses InstantSearch's
htmltagged templates and needs notmpl-markup. Start frominstantsearch-modern.php. On a block theme, the InstantSearch template setting has no effect, because the plugin loads the same assets for both versions and no template file.
If you need PHP in the markup, such as translated headings, do_action( 'algolia_instantsearch_after_hit' ), or conditional widgets, register a dynamic block. Its render_callback outputs the instantsearch-modern.php markup without get_header() and get_footer(). Then place the block in the Search Results template. This is the approach from kjtolsma in #216. Enqueue the JS as in step 6, or with viewScript in block.json and a dependency on algolia-instantsearch.
The plugin enqueues InstantSearch assets only on is_search() requests with Use Algolia with InstantSearch.js selected. In any other case, the algolia config is still printed on a block theme, but you must enqueue the assets yourself. Examples are a page that searches only one post type, or a site using Use Algolia, keep your theme's search template. Without them you get Uncaught ReferenceError: instantsearch is not defined (bridgetwes in #216).
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_search() && ! has_block( 'my-theme/algolia-instantsearch' ) ) {
return;
}
wp_enqueue_style( 'algolia-instantsearch' ); // Optional: skip if you style it yourself.
wp_enqueue_script( 'my-theme-algolia-instantsearch' ); // Registered with a dependency on 'algolia-instantsearch'.
}, 20 );The plugin registers its scripts on wp_enqueue_scripts at the default priority. Enqueue at priority 11 or later so the handles exist.
algolia-instantsearch (css/algolia-instantsearch.css) targets the #ais-wrapper, #ais-main, and #ais-facets IDs used by the reference templates. Keep those IDs to reuse the default layout. To replace the styles entirely, dequeue it from the same hook:
add_action( 'algolia_instantsearch_scripts', function () {
wp_dequeue_style( 'algolia-instantsearch' );
} );Return false from algolia_is_block_theme at a priority later than 10. The plugin then treats the site as a classic theme and loads instantsearch.php / instantsearch-modern.php, checking your-theme/algolia/ first, as it did before 2.10.3.
// In your theme's functions.php or a small plugin.
add_filter( 'algolia_is_block_theme', '__return_false', 20 );| Name | algolia_is_block_theme |
| Since | 2.10.3 |
| Type |
bool, default false before callbacks run |
| Built-in callback |
Algolia_Compatibility::maybe_block_theme() at priority 10. It returns true unchanged, otherwise wp_is_block_theme(). |
| Read by |
Algolia_Template_Loader::__construct() on init priority 20, and Algolia_Template_Loader::template_loader() on template_include
|
Effect of true
|
Prints the algolia config on the front end. On InstantSearch searches, enqueues assets only and keeps the theme template. |
Effect of false
|
Prints config only if Autocomplete or InstantSearch is on. On InstantSearch searches, loads the PHP template file. |
Notes on the filter:
-
Priority matters. The built-in callback overwrites any
falseit receives withwp_is_block_theme(). Afalsereturned at priority 1–9 is lost. At priority 10, it works only because the plugin registers its callback first. Use 11 or later. -
Add it early. The filter is read on
initat priority 20.functions.php, a plugin, or an mu-plugin all run before that. Don't add it inside a template or awp/template_redirectcallback. -
Forcing
truehelps whenwp_is_block_theme()is wrong for your setup, such as a hybrid theme with block templates. Useadd_filter( 'algolia_is_block_theme', '__return_true' );. - The name is
algolia_is_block_theme.algolia_is_fse_themewas proposed in #504 but never shipped. -
Related:
algolia_should_override_search_with_instantsearch(since 1.0.0) forces the InstantSearch setting on or off in code. On a block theme, turning it on also switches the main search query to Algolia on the back end.
The plugin's templates call get_header() and get_footer(). Block themes usually have no header.php or footer.php, so WordPress falls back to its deprecated theme-compat header and footer, and your block header, footer, and global styles are missing. Before opting out, copy the template to your-theme/algolia/. Replace those calls with the block template parts, rendered before wp_head() so their styles get enqueued. This is the workaround from Gutenberg #40018 and the same order that core's wp-includes/template-canvas.php uses:
<?php
/**
* your-theme/algolia/instantsearch-modern.php
*/
// Render block parts first so their styles are enqueued for wp_head().
$algolia_header = do_blocks( '<!-- wp:template-part {"slug":"header","tagName":"header"} /-->' );
$algolia_footer = do_blocks( '<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->' );
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div class="wp-site-blocks">
<?php echo $algolia_header; // phpcs:ignore WordPress.Security.EscapeOutput ?>
<!-- #ais-wrapper markup and the <script> block from the plugin template, unchanged -->
<?php echo $algolia_footer; // phpcs:ignore WordPress.Security.EscapeOutput ?>
</div>
<?php wp_footer(); ?>
</body>
</html>The template-part slugs (header, footer) differ between themes. Check your theme's parts/ folder, and confirm the page still outputs a <title>.
| Symptom | Likely cause | Fix |
|---|---|---|
ReferenceError: instantsearch is not defined |
The assets aren't enqueued. The setting isn't Use Algolia with InstantSearch.js, the page isn't a search request, or the plugin is older than 2.10.4. | Update the plugin, change the setting, or enqueue algolia-instantsearch yourself (see Other ways to build it). |
ReferenceError: algolia is not defined |
The config isn't printed. algolia_is_block_theme is false, and neither Autocomplete nor InstantSearch is on. This is the 2.10.0–2.10.2 behavior. |
Update to 2.10.3 or later, or return true from the filter. |
| The plugin's default InstantSearch page shows instead of your block template | The filter is false, either forced by code or because wp_is_block_theme() returns false. |
Remove the __return_false filter, or add __return_true. |
| Your block template shows, but results are the plain WordPress list | Your template still has a Query Loop and no InstantSearch markup, or your init script didn't load. | Add the #ais-wrapper markup, and enqueue your script from algolia_instantsearch_scripts. |
An empty #algolia-hits in legacy mode |
tmpl-instantsearch-hit is missing, or <script> was stripped from the Custom HTML block. |
Print the template from wp_footer in PHP, or switch to the modern template. |
| The opt-out page has no theme header or styles |
get_header() / get_footer() fell back to theme-compat. |
Use the do_blocks()-before-wp_head() template above. |
| An admin-bar alert says the searchable posts index isn't indexed |
algolia.indices.searchable_posts is undefined. |
Index Searchable posts from the plugin's Settings page. |
- #216 Full Site Editing Search Results: the main discussion
- #355 FSE compatible template files: closed as a duplicate of #216
- PR #474: the early return in the template loader, 2.10.0
-
#504 Full Site Editing InstantSearch integration broken in 2.10.0 and PR #505:
algolia_is_block_theme, 2.10.3 - #522 Instantsearch assets not loading when using a FSE theme and PR #524: asset loading without the template, 2.10.4
- wordpress.org support: Customize instantsearch.php with FSE theme
- Gutenberg #40018 workaround comment
- Plugin source, 2.14.1:
includes/class-algolia-template-loader.php,includes/class-algolia-compatibility.php,includes/class-algolia-scripts.php,templates/instantsearch*.php,CHANGELOG.md