wp-search-with-algolia icon indicating copy to clipboard operation
wp-search-with-algolia copied to clipboard

Feature/272 autocomplete upgrade

Open tw2113 opened this issue 2 years ago • 2 comments
trafficstars

I named the branch wrong, it should be "feature/232-autocomplete-upgrade", so this should be for #232

Upgrade our available options for Algolia Autocomplete

With this feature, we will not be forcing everyone to upgrade their Autocomplete version, but we will start the process of offering the ability to.

Due to the detail that Algolia Autocomplete version 1.x and higher changes from listening to all specified form inputs, to requesting a dedicated div to render in, we can't blanket update everyone. Every user wanting to upgrade will need to amend their theme and website to have something like <div id="autocomplete"></div> or similar selector. This is where Algolia will render the autocomplete search field. The ID does not matter so much, as much as a valid selector in general. I have added filterability for this detail, as you'll see in the code.

With this PR, to help with some separation, there is a new assets directory that stores the frontend assets for:

  1. AlgoliaSearch Javascript Client
  2. Autocomplete.js 1.x
  3. Autocomplete Theme classic 1.x
  4. instantsearch.js

Autocomplete.js 0.38.x will at present time be left in the original js location, as well as the other libraries. We can remove the duplicates from version control if really desired.

Choosing Autocomplete version

There is a new setting on the "Autocomplete" settings page that lets users choose between "Legacy" aka our current 0.38.x version, or "Modern", which is presently at version 1.11.x. This option defaults to "Legacy" and upon admin loading, should populate the option with that default value, preventing accidental breaking changes.

What assets and template file(s) gets loaded depends on the selected setting.

Template changes

The plugin has a new autocomplete-modern.php file, as well as a new algolia-autocomplete-modern.css stylesheet file. The template file has been updated to match the structure and style that Autocomplete 1.11.x expects, and I aimed to replicate the look and feel of the dropdown as much as possible from our legacy. The stylesheet file is largely retained but the selectors are updated to match what comes in.

Autocomplete config changes

I have gone ahead and added a new input_selector_modern property with its own WordPress filter for customization. It does default to '#autocomplete' where that gets passed into the configuration object for Autocomplete in the template file.

Let me know what your thoughts are, anything you would like changed, anything you think could be changed but needs further discussion, and whatnot.

Hopefully this pushes us over the proverbial edge to help our users start leveraging modern Autocomplete functionality, without having to leave them scratching their heads with a blank slate.

tw2113 avatar Sep 20 '23 22:09 tw2113

This PR needs this re-added somehow

<?php
do_action( 'algolia_autocomplete_after_hit' );
?>

tw2113 avatar Oct 10 '23 19:10 tw2113

Let's also look into adding any of the UX tracking/analytics/etc features that come with Autocomplete modern into the new template file, even if we have them commented out. Just placing things in the correct spot for users to see, would be a big step up for someone coming into the plugin, and wanting those features.

tw2113 avatar Dec 14 '23 17:12 tw2113

This obviously seems like a nice addition, why did you not merge it yet into the main branch?

8ctopus avatar Jun 06 '25 07:06 8ctopus

Good day @8ctopus

Thank you for chiming in.

It's definitely the next big thing on my mind for the plugin, and I don't want to drag it out more than absolutely needed at this point.

That said, I know I need to get the PR updated to resolve conflicts. I also want to get things re-tested and confirmed that we shouldn't be breaking anything in some way.

One of the biggest reasons that "modern autocomplete" has yet to be merged in is because of how Algolia changed instantiation processes. Before version 1.x, we are able to attach to any text input, which is extremely convenient with WordPress because typically theme search fields all make use of <input type="text" name="s" .../> and that name attribute is pretty global.

With Autocomplete version 1.x going forward, they're expecting say <div id="autocomplete"></div> and they handle the rendering of everything else. Thus we lose that ease of attachment for themes out of box. Site owners are going to need to modify and implement the <div id="autocomplete"></div> or similar on their own, which may not be feasible for everyone.

This upgrade definitely isn't forgotten, but we're treading a little carefully still.

tw2113 avatar Jun 06 '25 13:06 tw2113

@tw2113 Good day Michael, thank you for your reply, it's much appreciated. I just discovered your plugin today, took it for a test ride, and it works very well, congrats! I will try next week to play with this branch as I plan on running it with the minimum number of extra stuff. I will update this thread with what I find out.

8ctopus avatar Jun 06 '25 14:06 8ctopus

I'm eying getting this sync'd up with the main branch today as much as able, which could help you with any testing you can do.

tw2113 avatar Jun 06 '25 14:06 tw2113

I believe the branch should be updated with version 2.9.0 now.

tw2113 avatar Jun 06 '25 21:06 tw2113

Good morning, thank you for taking the time to solve the conflicts. I've just tested the branch this morning and it worked once I applied two fixes which I just opened a PR for. Here's what I tested:

  • Use Algolia with the native WordPress search template
  • Use Algolia with Instantsearch.js
  • Enable Autocomplete in legacy and modern version

Autocomplete js code can be improved in the modern way to check that the div actually exists

2025-06-10_091314

  const containerElement = getHTMLElement(environment, container);

  invariant(
    containerElement.tagName !== 'INPUT',
    'The `container` option does not support `input` elements. You need to change the container to a `div`.'
  );```

If I tried the following:

wp_deregister_script('jquery');

then everything is broken.

8ctopus avatar Jun 10 '25 05:06 8ctopus

Added a new issue for the div bits over at https://github.com/WebDevStudios/wp-search-with-algolia/issues/484

tw2113 avatar Jun 10 '25 18:06 tw2113

Note to me:

We have Autocomplete config overrides in Algolia Pro that we need to keep in mind for this.

Particularly this line: 'tmpl_suggestion' => 'autocomplete-post-suggestion'

tw2113 avatar Jun 10 '25 19:06 tw2113

@tw2113 Anything else you want me to test?

8ctopus avatar Jun 11 '25 11:06 8ctopus

@8ctopus Nothing at the moment. I'm prepping for 2.10.0 release before I go more in depth with this Autocomplete stuff and a 2.11.0 release

tw2113 avatar Jun 11 '25 13:06 tw2113

hello @tw2113

I have managed to use instantsearch v4 with the default wordpress input after a while of trial and error. I'm attaching the code snippet, I hope it saves you a bunch of time when you get to it.

const algolia = () => {
  const { algoliasearch, instantsearch } = window;

  const searchClient = algoliasearch(
    'APPLICATION_ID',
    'SEARCH_API_KEY'
  );

  // https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/
  const search = instantsearch({
    indexName: 'YOUR_INDEX',
    searchClient,
    future: {
      preserveSharedStateOnUnmount: true
    },
    searchFunction(helper) {
      if (helper.state.query === '') {
        // hide hits container when nothing is typed yet
        document.querySelector('#hits').style.display = 'none';
        return;
      }

      document.querySelector('#hits').style.display = '';
      helper.search();
    },
  });

  // create custom search widget
  const { connectSearchBox } = instantsearch.connectors;

  // create a render function
  const renderSearchBox = (renderOptions, isFirstRender) => {
    const { query, refine, clear, isSearchStalled, widgetParams } = renderOptions;

    const input = document.querySelector('input[type=search]');

    if (isFirstRender) {
      input.addEventListener('input', event => {
        refine(event.target.value);
      });
    }

    input.value = query;
  };

  const customSearchBox = connectSearchBox(renderSearchBox);

  search.addWidgets([
    customSearchBox({
      container: document.querySelector('#searchbox'),
    }),
    instantsearch.widgets.poweredBy({
      container: '#poweredBy',
    }),
    // https://www.algolia.com/doc/api-reference/widgets/hits/js/
    instantsearch.widgets.hits({
      container: '#hits',
      escapeHTML: true,
      templates: {
        item: (hit, { html, components }) => html`
          <article>
            <a href="?p=${hit.post_id}">${components.Highlight({ hit, attribute: 'post_title' })}</a>
          </article>
        `,
        empty: "We didn't find any results for the search <em>\"{{query}}\"</em>",
      },
      hitsPerPage: 8,
    }),
    instantsearch.widgets.configure({
      hitsPerPage: 8,
      distinct: true,
      clickAnalytics: true,
      enablePersonalization: true,
    }),
    instantsearch.widgets.pagination({
      container: '#pagination',
    }),
  ]);

  search.start();
};

export default algolia;

and the html code

<form role="search" method="get" action="<?= home_url('/'); ?>">
    <div class="d-flex">
        <div class="flex-grow-1 ps-2 ps-lg-0">
            <input type="search" class="form-control form-control-lg" name="s" placeholder="<?php _e('Search...', 'framework'); ?>" value="<?php the_search_query(); ?>">
        </div>
        <div class="px-2 pe-lg-0">
            <button type="submit" class="btn btn-primary btn-lg ctst-red-new-bg ctst-red-bg-hover">
                <i class='bx bx-search'>&nbsp;</i> <?php _e('Search', 'framework'); ?>
            </button>
        </div>
    </div>
</form>
<div id="poweredBy" class="pt-2"></div>
<div class="search-panel__results">
    <div id="hits"></div>
    <div id="pagination"></div>
</div>

8ctopus avatar Jun 18 '25 06:06 8ctopus

Not quite sure what issue you're solving here, as we're already shipping with InstantSearch 4.x. Are you referring to shipping something that isn't all tied in with an instantsearch.php template file, allowing for some separation?

The PR we're discussing this in is regarding Autocomplete as well.

tw2113 avatar Jun 18 '25 13:06 tw2113

@tw2113 sorry I made a mistake. I assumed that:

| One of the biggest reasons that "modern autocomplete" has yet to be merged in is because of how Algolia changed instantiation processes. Before version 1.x, we are able to attach to any text input, which is extremely convenient with WordPress because typically theme search fields all make use of <input type="text" name="s" .../> and that name attribute is pretty global.

meant that you didn't yet figure out a way how to do it, hence why I posted the info in this thread.

I my case, I wanted to use a lighter implementation of the frontend that only covers my specific use case, hence I dequeued most of the frontend stuff and implemented the js myself.

8ctopus avatar Jun 19 '25 13:06 8ctopus

Noted on that part.

While I definitely want to get things merged in, usage of Autocomplete 1.x won't be default until Algolia stops supporting 0.38.x completely.

tw2113 avatar Jun 23 '25 13:06 tw2113

https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-insights

tw2113 avatar Jun 25 '25 19:06 tw2113

Potentially once again needs another new branch with re-applied changes.

tw2113 avatar Aug 08 '25 21:08 tw2113