7 Best WooCommerce Reporting and Analytics Plugins for 2021

Are you looking for a reporting plugin for your WooCommerce store?

A reporting and analytics plugin for WooCommerce will help you track your online store’s performance and also give you key insights to understand your audience and boost your revenue.

In this article, we’ll help you pick the best WooCommerce report and analytics plugins for your online store.

Best WooCommerce reporting and analytics plugins

Why Do You Need a WooCommerce Reporting Plugin?

WooCommerce is the world’s most popular eCommerce platform. It’s a free eCommerce plugin for WordPress that makes it super easy to sell products and services online.

If you’re running a WooCommerce store, then it’s important to know how well it’s performing. You should be able to track your conversions, find out where your customers are from, and uncover which marketing strategies are working.

To find out all of this and more, you’ll need a WooCommerce reporting plugin. It will help you get insights into how customers use your website, so you can offer the products and services they like the most.

Besides that, you can use a WooCommerce reporting and analytics tool to measure your marketing campaigns and discover where potential customers are leaving your site before they complete a purchase.

That being said, let’s look at some of the best WooCommerce reporting and analytics plugins.

1. MonsterInsights

MonsterInsights

MonsterInsights is the best Google Analytics plugin for WordPress. It comes with an eCommerce addon that lets you track your WooCommerce conversions with ease.

The best part about using MonsterInsights is that it shows all the information you need to measure your WooCommerce store’s performance inside your WordPress dashboard.

It makes it super easy to set up and use Google Analytics. Plus, you don’t have to work your way through the complicated Google Analytics reports to find the data you need to make decisions.

An example of an ecommerce report in MonsterInsights

The MonsterInsights eCommerce report lets you view your revenue, number of transactions, conversion rate, and average order value at a glance.

MonsterInsights also shows the most popular products on your WooCommerce store and helps you find out which products generate the most sales and revenue.

Using this information, you can offer similar products and services that your customer prefer and grow your eCommerce revenue.

The plugin also tracks your top conversion sources, so you can see which websites are sending you high-converting traffic. This helps you to invest more in marketing strategies that are already proven to work.

Top Conversion Sources

There are more shopper behavior reports you can view in your WordPress dashboard. For instance, MonsterInsights shows you the total items added to cart, removed from cart, time to purchase, and sessions to purchase a product.

Another advantage of using MonsterInsights is its Popular Products feature. You can display your top-selling products anywhere on your WooCommerce store using this feature.

Customize popular products blog post

MonsterInsights offers multiple themes to choose from and also provides different options to customize and display popular products on WooCommerce product pages.

Display popular products end of blog post

Other than that, you also get advanced tracking features with MonsterInsights. For instance, it helps you set up custom dimension tracking, scroll tracking, link click tracking, outbound link tracking, and much more.

Pricing: To track your WooCommerce store in Google Analytics, you’ll need the MonsterInsights Pro plan which will cost you $199.50 per year. There is also a free version, but it doesn’t include enhanced eCommerce tracking report.

2. WP Mail SMTP

WP Mail SMTP

WP Mail SMTP is one of the best WooCommerce plugins for your store. It ensures that your emails reach the inbox of your customers, and offers tracking and reporting on all the emails your site sends out.

On a WooCommerce store, you’ll need to send your customers receipts of their purchases, order details, user account details, order confirmation emails, and much more.

If your customers aren’t getting these important emails, then it will result in a bad user experience and you’ll lose potential customers.

With WP Mail SMTP, you can track whether your emails are being delivered or not. All you have to do is enable the email logs in WP Mail SMTP and the plugin will take care of the rest.

Turn on email logs

You can then view your email logs inside your WordPress dashboard and see the delivery statues, opens, and clicks for each email.

WP Mail SMTP email reporting

For more information, you can follow our step by step tutorial on how to setup WordPress email logs.

Pricing: WP Mail SMTP premium plans include the email logs feature with prices starting from $39 per year.

3. Product Sales Report for WooCommerce

Product Sales report for WooCommerce

Product Sales Report for WooCommerce is a great reporting tool for finding out how many sales your eCommerce store is getting and then sharing the sales reports with other people.

The WordPress plugin is very easy to use and create by Aspen Grove Studios. You can change the reporting period and select which products to include in the sales report.

There are also different options for showing reporting fields in the report. For instance, you can choose to show product ID, SKU, name, quantity sold, gross sales, product category, and much more.

The best part about using Product Sales Report for WooCommerce is that you can generate and view the sales report inside your WordPress dashboard and download it as a CSV file to share it with others.

Pricing: You can use Product Sales Report for WooCommerce for free. However, you can also subscribe to its premium version for more reporting features with prices starting from $199 per year.

4. Google Analytics and Google Shopping plugin for WooCommerce

Google Shopping plugin for WooCommerce

Google Analytics and Google Shopping plugin for WooCommerce, which was formerly known as Enhanced Ecommerce Google Analytics Plugin, is the next plugin on our list.

The plugin allows you to easily set up Enhanced Ecommerce tracking in Google Analytics with your WooCommerce store. Not only that, but you can also connect your Google Ads and Google Merchant accounts.

The downside of using Google Analytics and Google Shopping plugin for WooCommerce is that you don’t get to see reports inside your WordPress dashboard, like you can with MonsterInsights.

However, you can unlock different Google Analytics eCommerce reports and view them in your Analytics. These include the shopping behavior report, checkout behavior report, product performance report, and sales performance report.

Pricing: Google Analytics and Google Shopping plugin for WooCommerce is available for free.

5. Sales Report By Country for WooCommerce

s
Sales report by country for WooCommerce

Sales Report By Country for WooCommerce is another popular WooCommerce reporting and analytics tool. The plugin is designed specifically to track sales from different regions on your online store.

It is very easy to use and doesn’t require any setup. All you have to do is install the plugin and then view the sales report by country in your WooCommerce reports section.

With the plugin, you can easily see the top 10 countries that drive revenue to your WooCommerce store. You get different options to change the visualization of the graphs in the report.

Besides that, the plugin lets you sort the data based on different date ranges. For example, you can view your sales from last year, month, week, or choose a custom date range.

Pricing: Sales Report By Country for WooCommerce is a free WordPress plugin.

6. Advanced Reporting for WooCommerce

Advanced Reporting for WooCommerce

Advanced Reporting for WooCommerce is a free WordPress plugin that helps you track sales on your eCommerce store.

The plugin shows a detailed report inside your WordPress admin area. You can easily view your WooCommerce sales summary and get data about total sales, refunds, items purchased, and more.

Besides that, the Advanced Reporting for WooCommerce plugin shows your daily number of orders and earnings. You can also identify your top products and top categories in WooCommerce.

Another advantage of using the plugin is that it helps in finding your top customers. You can even view which country and state your highest paying customers are from.

Pricing: Advanced Reporting for WooCommerce is a free WooCommerce reporting plugin.

7. Abandoned Cart for WooCommerce

Abandoned cart for WooCommerce

Abandoned Cart for WooCommerce is one of the best WooCommerce reporting and analytics plugins to have on your website. It’s designed specifically to track abandoned carts and help recover lost sales.

An abandoned cart occurs when people visit your WooCommerce store, add products to the cart, but then leave without checking out. As a result, you lose potential customers and sales.

Using the plugin, you can easily track abandoned users and see a report inside your WordPress dashboard. You get to see a complete list of abandoned carts, capture customer emails at checkout, and see from which page the user left your store.

Another advantage of using the plugin is that it helps create workflows for abandoned customers and send automated emails to abandoned users.

Pricing: Abandoned Cart for WooCommerce is a free plugin to use. If you upgrade to the paid version, then you get features like instant notifications when any cart abandonment happens and more.

Which Is the Best WooCommerce Reporting Plugin?

If you want a complete reporting tool that easily tracks your WooCommerce store’s performance along with advanced tracking features, then we recommend MonsterInsights.

Its eCommerce addon automatically tracks your WooCommerce store and show you a detailed report insides the WordPress dashboard. Besides that, you also get features like scroll tracking, link tracking, custom dimensions, and much more.

We hope this article helped you pick the best WooCommerce reporting and analytics plugin. You may also want to look at our guide on how to create a free business email address, or see or expert comparison of the best live chat software for small business.

If you liked this article, then please subscribe to our YouTube Channel for WordPress video tutorials. You can also find us on Twitter and Facebook.

The post 7 Best WooCommerce Reporting and Analytics Plugins for 2021 appeared first on WPBeginner.

How To Implement Search Functionality In Your Nuxt App Using Algolia InstantSearch

Giving users the ability to quickly search through and navigate our content easily comes with great benefits. This not only improves the user experience, but also increases user retention and boosts conversion as users can now explore beyond what brought them to our site in the first place.

In this tutorial, we’ll be looking at how to integrate this search functionality into our Nuxt app using Algolia. Algolia is a third-party service that we can integrate into our app and provides us with a set of tools that allow us to create a full search experience in our sites and applications.

We’ll be using Nuxt Content, "Git Based Headless CMS" which allows us to create and manage content using Markdown, XML, JSON files, and so on. We’ll build a Nuxt site with Nuxt Content with a search feature using Algolia InstantSearch, for styling, we’ll use TailwindCSS. This tutorial is aimed at Vue.js devs that are familiar with Nuxt.

Prerequisites

To follow along with this tutorial, you’ll need to have the following installed:

  • Node,
  • A text editor, I recommend VS Code with the Vetur extension (for Vue.js syntax features in VS Code),
  • A terminal, you can use VS Code’s integrated terminal or any other of your choice.

You’ll also require a basic understanding of the following in order to follow along smoothly:

Setting Up Our Nuxt App

Nuxt.js is a framework built on Vue, it has many capabilities and features including Server-Side Rendering (SSR).

To install it, open our terminal and run:

npx create-nuxt-app <project-name>

Where <project-name> is the name of our project folder, I’ll be using algolia-nuxt for this project.

Running the command will ask you some questions (name, Nuxt options, UI framework, TypeScript, etc. ). To find out more about all the options, see the Create Nuxt app.

When asked for Nuxt.js modules, make sure to select Content - Git-based headless CMS to install the nuxt/content module along with our Nuxt app.

After selecting all of your options, installation can begin. My selected options look like this:

After successfully installing the Nuxt app, navigate to the directory by running this command:

cd algolia-nuxt
Install Nuxt Content Separately

If you already have Nuxt set up before now, you can install the content module by running the command.

Skip this if you’ve already selected to install the nuxt/content module along with our Nuxt app.

#install nuxt content

npm install @nuxt/content

Then you can add it to our modules property inside our nuxt.config file.

//nuxt.config.js

export default {
  modules: ['@nuxt/content']
}
Install And Setup TailwindCSS

TailwindCSS is a utility first CSS framework that provides us with custom classes we can use to style our app.

We’ll also be using TailwindCSS Typography, which is "a plugin that provides a set of prose classes you can use to add beautiful typographic defaults to any vanilla HTML you don’t control (like HTML rendered from Markdown, or pulled from a CMS)."

First, we install @nuxtjs/tailwindcss which is a Nuxt module for TailwindCSS integration, as well as TailwindCSS and its peer-dependencies using npm:

npm install -D @nuxtjs/tailwindcss tailwindcss@latest postcss@latest autoprefixer@latest

Add the @nuxtjs/tailwindcss module to the buildModules section of our nuxt.config.js file:

// nuxt.config.js

export default {
  buildModules: ['@nuxtjs/tailwindcss']
}

Create Configuration File

Next, generate our tailwind.config.js file:

npx tailwindcss init

This will create a minimal tailwind.config.js file at the root of our project:

//tailwind.config.js

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

Create a tailwind.css file in assets/css/ use the @tailwind directive to inject TailwindCSS’ base, components, and utilities styles:

/*assets/css/tailwind.css*/

@tailwind base;
@tailwind components;
@tailwind utilities;

You can import the CSS file into our components or make it accessible globally by defining the CSS files/modules/libraries you want to set globally (included in every page).

  /* nuxt.config.js*/

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: [
    // CSS file in the project
    '@/assets/css/tailwind.css',
  ],

Here, we have added the path to our tailwind.css file to the list of global CSS files in our nuxt.config.js.

The @/ tells Nuxt that it's an absolute path to look for the file from the root directory.

Install TailwindCSS Typography

# Using npm
npm install @tailwindcss/typography

Then add the plugin to our tailwind.config.js file:

// tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [
    require('@tailwindcss/typography'),
  ],
}

Configure TailwindCSS To Remove Unused Styles In Production

In our tailwind.config.js file, configure the purge option with the paths to all of our pages and components so TailwindCSS can tree-shake unused styles in production builds:

// tailwind.config.js
module.exports = {
  purge: [
    './components/**/*.{vue,js}',
    './layouts/**/*.vue',
    './pages/**/*.vue',
    './plugins/**/*.{js,ts}',
    './nuxt.config.{js,ts}',
  ],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [
    require('@tailwindcss/typography'),
  ],
}

Since we’ve installed the packages, let’s start our app:

npm run dev

This command starts our Nuxt app in development mode.

Nice 🍻

Creating Our Pages And Articles

Now, let’s create our articles and a blog page to list out our articles. But first, let’s create a site header and navigation component for our site.

Creating A Site Header And Navigation

Navigate to our components/folder, and create a new file siteHeader.vue and enter the following code:

<!-- components/siteHeader.vue -->

<template>
  <header class="fixed top-0 w-full bg-white bg-opacity-90 backdrop-filter backdrop-blur-md">
    <div class="wrapper flex items-center justify-between p-4 m-auto max-w-5xl">
      <nuxt-link to="/">
        <Logo />
      </nuxt-link>

      <nav class="site-nav">
        <ul class="links">
          <li>
            <nuxt-link to="/blog">Blog</nuxt-link>
          </li>
        </ul>
      </nav>
    </div>
  </header>
</template>

Here, in our <header> we have a <Logo /> component wrapped in <nuxt-link> which routes to the home page and another <nuxt-link> that routes to /blog (We’ll create the blog page that we will create later on).

This works without us importing the components and configuring routing ourselves because, by default, Nuxt handles importing components and routing for us.

Also, let’s modify the default <Logo /> component. In components/Logo.vue, replace the content with the following code:

<!-- components/Logo.vue -->

<template>
  <figure class="site-logo text-2xl font-black inline-block">
    <h1>Algolia-nuxt</h1>
  </figure>
</template>

We can now add our siteHeader.vue component to our site. In layouts/default.vue, add <site-header /> just above the <Nuxt /> component.

<!-- layouts/default.vue -->

<template>
  <div>
    <site-header />
    <Nuxt />
  </div>
</template>

...

The <Nuxt /> component renders the current Nuxt page depending on the route.

Creating Our First Article

In content/, which is a folder created automatically for the nuxt/content module, create a new folder articles/ and then a new file in the folder first-blog-post.md. Here is the file for our first article in markdown format. Enter the following code:

<!-- content/articles/first-blog-post.md -->

---

title: My first blog post
description: This is my first blog post on algolia nuxt
tags: [first, lorem ipsum, Iusto]

---

## Lorem ipsum

Lorem ipsum dolor sit amet consectetur, adipisicing elit.
Assumenda dolor quisquam consequatur distinctio perferendis.

## Iusto nobis nisi

repellat magni facilis necessitatibus, enim temporibus.

- Quisquam
- assumenda
- sapiente explicabo
- totam nostrum inventore

The area enclosed with --- is the YAML Front Matter which will be used as a custom injected variable that we will access in our template.

Next, we’re going to create a dynamic page which will be used to:

  • Fetch the article content using asyncData which runs before the page has been rendered. We have access to our content and custom injected variables through the context by using the variable $content. As we are using a dynamic page, we can know what article file to fetch using the params.slug variable provided by Vue Router to get the name of each article.
  • Render the article in the template using <nuxt-content>.

Ok, navigate to pages/ and create a blog/ folder. Create a _slug.vue (our dynamic page) file and insert the following:

<!-- pages/blog/_slug.vue -->

<template>
  <article class="prose prose-lg lg:prose-xl p-4 mt-24 m-auto max-w-4xl">
    <header>
      <h1>{{ article.title }}</h1>
      <p>{{ article.description }}</p>
      <ul class="list-none">
        <li class="inline-block mr-2 font-bold font-monospace" v-for="tag in article.tags" :key="tag" > {{tag}} </li>
      </ul>
    </header>
    <!-- this is where we will render the article contents -->
    <nuxt-content :document="article" />
  </article>
</template>

<script>
export default {
  async asyncData({ $content, params }) {
    //here, we will fetch the article from the articles/ folder using the name provided in the `params.slug`
    const article = await $content('articles', params.slug).fetch()

    //return `article` which contains our custom injected variables and the content of our article
    return { article }
  },
}
</script>

If you go to your browser and navigate to http://localhost:3000/blog/first-blog-post you should see our rendered content:

Now that our dynamic page is working and our article is rendering, let’s create some duplicates for the purpose of this tutorial.

<!-- content/articles/second-blog-post.md -->

---

title: My first blog post
description: This is my first blog post on algolia nuxt
tags: [first, Placeat amet, Iusto]

---

## Lorem ipsum

Lorem ipsum dolor sit amet consectetur, adipisicing elit.
Assumenda dolor quisquam consequatur distinctio perferendis.

## Iusto nobis nisi

repellat magni facilis necessitatibus, enim temporibus.

- Quisquam
- assumenda
- sapiente explicabo
- totam nostrum inventore

Create Blog Page To List Our Articles

Let’s now create a blog page to list our articles. This is also where our search bar will live. Create a new file pages/blog/index.vue.

<!-- pages/blog/index.vue -->

<template>
  <main>
    <section class="p-4 mt-24 m-auto max-w-4xl">
      <header>
        <h1 class="font-black text-2xl">All posts</h1>

        <!-- dummy search bar -->
        <div class="search-cont inline-flex gap-2 bg-white p-2 rounded-lg shadow-lg">
          <input class="px-2 outline-none" type="search" name="search" id="search">
          <button class="bg-blue-600 text-white px-2 rounded-md" type="submit">Search</button>
        </div>
      </header>
      <ul class="prose prose-xl">
          <!-- list out all fetched articles --> 
        <li v-for="article in articles" :key="article.slug">
          <nuxt-link :to="{ name: 'blog-slug', params: { slug: article.slug } }">
            <h2 class="mb-0">{{ article.title }}</h2>
            <p class="mt-0">{{ article.description }}</p>
          </nuxt-link>
        </li>
      </ul>
    </section>
  </main>
</template>

<script>
export default {
  async asyncData({ $content }) {
    // fetch all articles in the folder and return the:
    const articles = await $content('articles')
      // title, slug and description
      .only(['title', 'slug', 'description'])
      // sort the list by the `createdAt` time in `ascending order`
      .sortBy('createdAt', 'asc')
      .fetch()

    return { articles }
  },
}
</script>

Here, in our asyncData function, when fetching $content('articles') we chain .only(['title', 'slug', 'updatedAt', 'description']) to fetch only those attributes from the articles, .sortBy('createdAt', 'asc') to sort it and lastly fetch() to fetch the data and assign it to const articles which we then return.

So, in our <template>, we can the list of articles and create links to them using their slug property.

Our page should look something like this:

Great 🍻

Install And Set Up Algolia Search And Vue-instantSearch

Now that we’ve gotten the basic stuff out of the way, we can integrate Algolia Search into our blog site.

First, let’s install all the packages we will be needing:

#install dependencies

npm install vue-instantsearch instantsearch.css algoliasearch nuxt-content-algolia remove-markdown dotenv
  • vue-instantsearch
    Algolia InstantSearch UI component/widget library for Vue.
  • instantsearch.css
    Custom styling for instantSearch widgets.
  • algoliasearch
    A HTTP client to interact with Algolia.
  • nuxt-content-algolia
    Package for indexing our content and sending it to Algolia.
  • remove-markdown
    This strips all markdown characters from the bodyPlainText of the articles.
  • dotenv
    This helps to read environment variables from .env files.

We’ll be using these packages throughout the rest of this tutorial, but first, let’s set up an Algolia account.

Set Up Algolia Account

Sign up for an Algolia account at https://www.algolia.com/. You can do this for free, however, this will give you a trial period of 14days. Since we’re not performing heavy tasks with Algolia, their free tier will do just fine for our project after the trial expires.

You’ll be taken through some onboarding steps. After that, an UNAMED APP will be created for you. On the sidebar, on the left, navigate to the API Keys you’ll be provided with:

  • Application ID
    This is your unique application identifier. It’s used to identify you when using Algolia’s API.
  • Search Only API Key
    This is the public API key to use in your frontend code. This key is only usable for search queries and sending data to the Insights API.
  • Admin API Key
    This key is used to create, update and DELETE your indices. You can also use it to manage your API keys.

Now that we have our API Keys, let’s save them in an .env file for our project. Navigate to the project root folder and create a new file .env and enter your API keys:

.env

ALGOLIA_APP_ID=algolia-app-id
ALGOLIA_API_KEY=algolia-admin-api-key

Replace algolia-app-id and algolia-admin-api-key with your Application ID and Admin API Key respectively.

Create An 'Articles' Index For Our Nuxt Articles In Algolia

On your Algolia account, go to Indices and click on create Index. Then enter the name of your index and we’ll be using articles for this tutorial.

As you can see, our 'article' index has been created.

Set Up nuxt-content-algolia To Send Content Index To Algolia

We’ve successfully created an index property on our account. Now we have to generate an index from our Nuxt articles which is what Algolia will use to provide results for search queries. This is what the nuxt-content-algolia module that we previously installed is for.

We need to configure it in our nuxt.config.js.

First, we will add it to our buildModules:

// nuxt.config.js

...

// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: ['@nuxtjs/tailwindcss', 'nuxt-content-algolia'],

...

Then, we create a new nuxtContentAlgolia object and add a few configurations to it:

// nuxt.config.js

export default {
...

nuxtContentAlgolia: {

  // Application ID
  appId: process.env.ALGOLIA_APP_ID,

  // Admin API Key
  // !IMPORTANT secret key should always be an environment variable
  // this is not your search only key but the key that grants access to modify the index
  apiKey: process.env.ALGOLIA_ADMIN_API_KEY,

  paths: [
    {
      name: 'articles',
      index: process.env.ALGOLIA_INDEX || 'articles',
      fields: ['title', 'description', 'tags', 'bodyPlainText']
    }
  ]
},


...
}

The nuxtContentAlgolia takes in the following properties:

  • appId
    Application ID*.
  • apiKey
    Admin API Key.
  • paths
    An array of index objects. This is where we define where we want to generate indexes from. Each object takes the following properties:
    • name
      The name of the folder within the content/ folder. In other words, we’ll be using files within content/articles/ since we defined the name as 'articles'.
    • index
      This is the name of the index we created on our Algolia dashboard.
    • fields
      An array of fields to be indexed. This is what Algolia will base its search queries on.

Generate bodyPlainText From Articles

Note that in the fields array, we have bodyPlainText as one of its values. Nuxt Content does not provide such a field for us. Instead, what Nuxt Content provides is body which is a complex object that will be rendered in the DOM.

In order to get our bodyPlainText which is simply all text, stripped of markdown and HTML characters, we have to make use of yet another package, remove-markdown.

To use the remove-markdown function we need to make use of Nuxt hooks. We’ll use the 'content:file:beforeInsert' hook which allows you to add data to a document before it is inserted, to strip off the markdown and add the generated plain text to bodyPlainText.

// nuxt.config.js

export default {
...

hooks: {
  'content:file:beforeInsert': (document)=>{
    const removeMd = require('remove-markdown');

    if(document.extension === '.md'){
      document.bodyPlainText = removeMd(document.text);
    }
  }
},

...
}

In the 'content:file:beforeInsert' hook, we get the remove-markdown package. Then we check if the file to be inserted is a markdown file. If it is a markdown file, we generate the plain text by calling removeMd which takes document.text — the text of our content, as an argument, which we assign to a new document.bodyPlainText property. The property will now be available for use through Nuxt Content.

Great! Now that that’s done, we can generate the index and send it over to Algolia.

Confirm Algolia Index

Alright. We’ve set up nuxt-content-algolia and we’ve generated bodyPlainText for our articles. We can now generate this index and send the data over to Algolia by building our project using nuxt generate.

npm run generate

This will start building our project for production and run the nuxtContentAlgolia config. When we look at our terminal after the build we should see that our content has been indexed and sent to Algolia.

To verify, you can go to your Algolia dashboard:

Open Indices, then go to Search API logs, where you will see a log of operations performed with your Search API. You can now open and check the API call sent from your Nuxt project. This should have the content of your article as specified in the fields section of nuxtContentAlgolia config.

Nice! 🍻

Building The Search UI

So far we’ve been able to generate and send index data to Algolia, which means that we are able to query this data to get search results.

To do that within our app, we have to build our search UI.

Vue-InstantSearch provides lots of UI components using Algolia that can be integrated to provide a rich search experience for users. Let’s set it up.

Create And Configure vue-instantSearch Plugin

In order to use the Algolia InstantSearch widgets in our Nuxt app, we will have to create a plugin in our plugins folder.

Go to plugins/ and create a new file vue-instantsearch.js.

// plugins/vue-instantsearch.js

import Vue from 'vue'
import InstantSearch from 'vue-instantsearch'

Vue.use(InstantSearch)

Here, we’re simply importing InstantSearch and using it on the Vue frontend.

Now, we have to add the vue-instantSearch plugin to our plugins and build options in nuxt.config.js in order to transpile it to Vue.js.

So, go over to nuxt.config.js and add the following:

// nuxt.config.js

export default {
...

// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: ['@/plugins/vue-instantsearch.js'],

// Build Configuration: https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-build#transpile
build: {
  transpile: ['vue-instantsearch', 'instantsearch.js/es']
}

...
}

InstantSearch code uses ES modules, yet it needs to be executed in Node.js. That’s why we need to let Nuxt know that those files should be transpiled during the build. Now that we’ve configured our vue-instantSearch plugin, let’s create a search component.

Create A Search Component

Create a new file components/Search.vue.

Since we’ve installed vue-instantSearch as a plugin, we can use it within our Vue components.

<!-- components/Search.vue -->

...

<script>
import algoliaSearch from 'algoliasearch/lite'
import 'instantsearch.css/themes/satellite-min.css'

// configurations for Algolia search
const searchClient = algoliaSearch(
  // Applictaion ID
  '34IIDW6KKR',

  // Search API key
  '3f8d80be6c42bb030d27a7f108eb75f8'
)
export default {
    data(){
        return{
            searchClient
        }
    }
}
</script>

First, in the <script> section, we’re importing algoliaSearch and instantsearch.css.

Next, we provide the credentials for our Algolia search which are:

  • Application ID,
  • Search API key.

As parameters to algoliaSearch then assign it to searchClient which we will use in our <template> to configure our Algolia search widgets.

ais-instant-search Widget

ais-instant-search is the root Vue InstantSearch component. All other widgets need to be wrapped with the root component to function. The required attributes for this component are:

  • index-name
    Name of the index to query, in this case, it would be articles.
  • search-client
    algoliaSearch object containing Application ID and Search API Key.
<!-- components/Search.vue -->

<template>
  <div class="search-cont inline-flex gap-2 bg-white p-2 rounded-lg shadow-lg">
    <ais-instant-search index-name="articles" :search-client="searchClient">
    </ais-instant-search>
  </div>
</template>

...

ais-configure Widget

The ais-configure widget helps configure the search functionality by sending defined parameters to Algolia.

Any props you add to this widget will be forwarded to Algolia. For more information on the different parameters you can set, have a look at the search parameters API reference.

The parameters we’ll set for now will be:

  • attributesToSnippet
    The name of the attribute or field to snippet in, we’ll soon see more on this.
  • hits-per-page.camel
    Number of results in one page.
  • snippetEllipsisText="…"
    Set ... before and after snipped text.
<!-- components/Search.vue -->

<template>
  <div class="search-cont inline-flex gap-2 bg-white p-2 rounded-lg shadow-lg">
    <ais-instant-search index-name="articles" :search-client="searchClient">
      <ais-configure
        :attributesToSnippet="['bodyPlainText']"
        :hits-per-page.camel="5"
        snippetEllipsisText="…"
      >
      </ais-configure>
    </ais-instant-search>
  </div>
</template>

...

ais-autocomplete Widget

This widget is basically a wrapper that allows us to create a search result that autocompletes the query. Within this widget, we can connect to other widgets to provide a richer UI and access multiple indices.

<!-- components/Search.vue -->

<template>
  <div class="search-cont inline-flex gap-2 bg-white p-2 rounded-lg shadow-lg">
    <ais-instant-search index-name="articles" :search-client="searchClient">
      <ais-configure
        :attributesToSnippet="['bodyPlainText']"
        :hits-per-page.camel="5"
        snippetEllipsisText="…"
      >
        <ais-autocomplete>
          <template v-slot="{ currentRefinement, indices, refine }">
            <input
              type="search"
              :value="currentRefinement"
              placeholder="Search for an article"
              @input="refine($event.currentTarget.value)"
            />
            <ais-stats />
            <template v-if="currentRefinement">
              <ul v-for="index in indices" :key="index.indexId">
                <li>
                  <h3>{{ index.indexName }}</h3>
                  <ul>
                    <li v-for="hit in index.hits" :key="hit.objectID">
                      <h1>
                        <ais-highlight attribute="title" :hit="hit" />
                      </h1>
                      <h2>
                        <ais-highlight attribute="description" :hit="hit" />
                      </h2>
                      <p>
                        <ais-snippet attribute="bodyPlainText" :hit="hit" />
                      </p>
                    </li>
                  </ul>
                </li>
              </ul>
            </template>
            <ais-pagination />
          </template>
        </ais-autocomplete>
      </ais-configure>
    </ais-instant-search>
  </div>
</template>

...

So, within our ais-autocomplete widget, we’re doing a few things:

  • Overriding the DOM output of the widget using the default slot. We’re doing this using the scopes:
    • currentRefinement: string: the current value of the query.
    • indices: object[]: the list of indices.
    • refine: (string) => void: the function to change the query.
...
<template v-slot="{ currentRefinement, indices, refine }">
...
  • Create a search <input> to hold, change the query and value of the currentRefinement.
...
<input
    type="search"
    :value="currentRefinement"
    placeholder="Search for an article"
    @input="refine($event.currentTarget.value)"
/>
...
  • Render the search results for each index. Each index has the following properties:
    • indexName: string: the name of the index.
    • indexId: string: the id of the index.
    • hits: object[]: the resolved hits from the index matching the query.
...
<template v-if="currentRefinement">
    <ul v-for="index in indices" :key="index.indexId">
        <li>
            <h3>{{ index.indexName }}</h3>

...
  • Then render the results — hits.
...
<ul>
    <li v-for="hit in index.hits" :key="hit.objectID">
      <h1>
        <ais-highlight attribute="title" :hit="hit" />
      </h1>
      <h2>
        <ais-highlight attribute="description" :hit="hit" />
      </h2>
      <p>
        <ais-snippet attribute="bodyPlainText" :hit="hit" />
      </p>
    </li>
</ul>

...

Here’s what we’re using:

  • <ais-highlight>
    Widget to highlight the portion of the result which directly matches the query of the field passed to the attribute prop.
  • <ais-snippet>
    Widget to display the relevant section of the snippeted attribute and highlight it. We defined the attribute in attributesToSnippet in <ais-configure>.

Let’s run our dev server and see what our New search looks like.

Styling Our Search Component

InstantSearch comes with some default styles that we included in our project using the instantsearch.css package. However, we might need to change or add some styles to our components to suit the site we’re building.

The CSS classes with many widgets can be overwritten using the class-names prop. For example, we can change the highlighted style of <ais-highlight>.

<!-- components/Search.vue -->

...
<h1>
  <ais-highlight
    :class-names="{
      'ais-Highlight-highlighted': 'customHighlighted',
    }"
    attribute="title"
    :hit="hit"
  />
</h1>

...

And in our CSS:

<!-- components/Search.vue -->

...

<style>
    .customHighlighted {
      @apply text-white bg-gray-600;
    }
</style>
...

We see that the class we defined has been applied to the highlight.

So, I’ll go ahead and style it using tailwind till I feel it looks good.

<!-- components/Search.vue -->

<template>
  <div class="search-cont relative inline-flex mt-6 bg-gray-100 border-2 rounded-lg focus-within:border-purple-600">
    <ais-instant-search-ssr index-name="articles" :search-client="searchClient">
      <ais-configure :attributesToSnippet="['bodyPlainText']" :hits-per-page.camel="5">
        <ais-autocomplete class="wrapper relative">
          <div slot-scope="{ currentRefinement, indices, refine }">
            <input class="p-2 bg-white bg-opacity-0 outline-none" type="search" :value="currentRefinement" placeholder="Search for an article" @input="refine($event.currentTarget.value)" />
            <div class="results-cont relative">
              <div
                class=" absolute max-h-96 overflow-y-auto w-96 top-2 left-0 bg-white border-2 rounded-md shadow-lg" v-if="currentRefinement">
                <ais-stats class="p-2" />
                <ul v-for="index in indices" :key="index.indexId">
                  <template v-if="index.hits.length > 0">
                    <li>
                      <h2 class="font-bold text-2xl p-2">
                        {{ index.indexName }}
                      </h2>
                      <ul>
                        <li
                          class="border-gray-300 border-t p-2 hover:bg-gray-100" v-for="hit in index.hits" :key="hit.objectID" >
                          <nuxt-link
                            :to="{
                              name: 'blog-slug',
                              params: { slug: hit.objectID },
                            }"
                          >
                            <h3 class="font-extrabold text-xl">
                              <ais-highlight
                                :class-names="{
                                  'ais-Highlight-highlighted':
                                    'customHighlighted',
                                }"
                                attribute="title"
                                :hit="hit"
                              />
                            </h3>
                            <p class="font-bold">
                              <ais-highlight
                                :class-names="{
                                  'ais-Highlight-highlighted':
                                    'customHighlighted',
                                }"
                                attribute="description"
                                :hit="hit"
                              />
                            </p>
                            <p class="text-gray-500">
                              <ais-snippet
                                :class-names="{
                                  'ais-Snippet-highlighted':
                                    'customHighlighted',
                                }"
                                attribute="bodyPlainText"
                                :hit="hit"
                              />
                            </p>
                          </nuxt-link>
                        </li>
                      </ul>
                    </li>
                  </template>
                </ul>
              </div>
            </div>
          </div>
        </ais-autocomplete>
      </ais-configure>
    </ais-instant-search-ssr>
  </div>
</template>

...

<style>
.customHighlighted {
  @apply text-purple-600 bg-purple-100 rounded p-1;
}
</style>

Alright, the styling is done and I’ve included a <nuxt-link> to route to the article on click.

<nuxt-link :to="{ name: 'blog-slug', params: { slug: hit.objectID }}">

We now have something like this:

Configuring InstantSearch For Server-Side Rendering (SSR)

We now have our search component up and running but it only renders on the client-side and this means we have to wait for the search component to load even after the page loads. We can further improve the performance of our site by rendering it on the server-side.

According to Algolia, the steps for implementing server-side rendering are:

On the server:

  • Make a request to Algolia to get search results.
  • Render the Vue app with the results of the request.
  • Store the search results on the page.
  • Return the HTML page as a string.

On the client:

  • Read the search results from the page.
  • Render (or hydrate) the Vue app with search results.

Using Mixins, serverPreFetch, beforeMount

Following Algolia’s documentation on implementing SSR with Nuxt, we have to make the following changes:

<!-- components/Search.vue -->

...
<script>
// import 'vue-instantsearch';
import { createServerRootMixin } from 'vue-instantsearch'

import algoliaSearch from 'algoliasearch/lite'
import 'instantsearch.css/themes/satellite-min.css'

const searchClient = algoliaSearch(
  '34IIDW6KKR',
  '3f8d80be6c42bb030d27a7f108eb75f8'
)

export default {
  data() {
    return {
      searchClient,
    }
  },

  mixins: [
    createServerRootMixin({
      searchClient,
      indexName: 'articles',
    }),
  ],

  serverPrefetch() {
    return this.instantsearch.findResultsState(this).then((algoliaState) => {
      this.$ssrContext.nuxt.algoliaState = algoliaState
    })
  },

  beforeMount() {
    const results =
      (this.$nuxt.context && this.$nuxt.context.nuxtState.algoliaState) ||
      window.__NUXT__.algoliaState

    this.instantsearch.hydrate(results)

    // Remove the SSR state so it can’t be applied again by mistake
    delete this.$nuxt.context.nuxtState.algoliaState
    delete window.__NUXT__.algoliaState
  },
}
</script>

We’re simply doing the following:

  • createServerRootMixin to create a reusable search instance;
  • findResultsState in serverPrefetch to perform a search query on the back end;
  • hydrate method in beforeMount.

Then in our <template>,

<!-- components/Search.vue -->

...
<ais-instant-search-ssr index-name="articles" :search-client="searchClient">
    ...
</ais-instant-search-ssr>
...

Here, we to replace ais-instant-search with ais-instant-search-ssr.

Conclusion

We’ve successfully built a Nuxt site with some content handled by Nuxt Content and integrated a simple Algolia search into our site. We’ve also managed to optimize it for SSR. I have a link to the source code of the project in this tutorial and a demo site deployed on Netlify, the links are down below.

We have tons of options available to customize and provide a rich search experience now that the basics are out of the way. The Algolia widgets showcase is a great way to explore those options and widgets. You’ll also find more information on the widgets used in this tutorial.

GitHub Source Code

Further Reading

Here are some links that I think you will find useful:

Predictions of Future Trends in Accessibility Tests

The mobile app is projected to account for a great market share as a result of the increasing penetration of mobile gadgets around the world. Therefore, along with the rising growth of smartphones, technology providers are concentrating on executing enhanced accessibility software for disabled persons. The higher demand for accessibility tests is expected to observe very strong growth in the upcoming years. 

Statistic Scenario

How to calculate monthly combine sales ,annual sales in Java programming

A shop owner has 2 outlets namely a High Street Branch and Mall Branch, before Covid19 lockdown the respective shops recorded sales as follows:
High Street Branch
Quarter Sales
Q1 42,000 48,000 50,000
Q2 52,000 58,000 60,000
Q3 46,000 49,000 58,000
Q4 50,000 51,000 61,000
Mall Branch
Quarter Sales
Q1 57,000 63,000 60,000
Q2 70,000 67,000 72,000
Q3 67,000 65,000 62,000
Q4 72,000 69,000 75,000
As a programmer hired by the shops owner, write a java program to calculate:
(a) the monthly combine sales figures for both shops;
(b) the respective shops annual sales figures;
(c) the grand annual combine total sales figures.

Gutenberg 11.6 Introduces New API for Locking Blocks

Gutenberg 11.6 was released this week with a new API for managing lock control at the block-type level. When defining a block, developers can now use the lock attribute to designate whether a block can be moved or removed. The PR introduces parts of the locking support mechanisms proposed by Matias Ventura in a separate issue earlier this year.

Ventura explained that while the editor already has template locking support to prevent inserting or moving blocks (i.e. for custom post type templates), it doesn’t yet offer much granular control or a UI for the different locking states. He identified block themes as an important use case for establishing a new block-level API for representing lock status. Block themes may necessitate the ability to lock down key elements, such as preventing the removal of the post-content for a single post template. If you have ever played around with the template editor then you have likely discovered how easy it is to remove important elements by accident.

“Another use case that we’re building for is having a Checkout Block with different blocks that act as fundamental steps,” WooCommerce and Gutenberg engineer Seghir Nadir said. “We don’t want people to delete or move those steps since they’re fundamental and their order is also important, but we want to allow people to select them, access settings, and insert blocks in between them.”

During this week’s core editor chat, Paal Joachim Romdahl highlighted the need for a locking mechanism for Reusable blocks.

“At the moment it is too easy to make an accidental change to a Reusable block,” Romdahl said. “I worry that only having the hover overlay and the initial click [to] select the parent Reusable block is just not good enough, that we soon should get a lock mechanism in place. There is a lot of feedback from users who have accidentally deleted the inner contents of the blocks and wondered what happened.”

Romdahl has created several issues about to the possibility of adding a locking mechanism to the inline toolbar for reusable blocks, where users would need to unlock to edit the contents.

Now that the foundational infrastructure is in place for managing lock control at the block-type level, contributors can begin building a UI to control it, as outlined in the Locking and TemplateLocking issue. Ventura said future iterations should include a UI that indicates which blocks are user-editable and also display block status in the list view and block inspector.