Custom Google Search Integration in Moodle: Step-by-Step Guide

Build and Troubleshoot a Google Search Block in Moodle Moodle LMS Custom Search Block with Google Search API; Moodle; Moodle LMS; Best LMS

 

Build a Custom Google Search Block for Moodle Implementation & Troubleshooting Guide

Search is the gateway to knowledge. In virtual learning environments like Moodle, students often need to look up concepts, definitions, and external resources. Instead of forcing users to constantly leave the Learning Management System (LMS) and switch tabs, bringing a search interface directly into the Moodle dashboard significantly boosts productivity and keeps students engaged.

In this guide, we will walk through how we built a custom, lightweight Google Search Block for Moodle LMS, how it integrates with Google's Programmable Search Engine (CSE), and how to resolve common configuration and loading bugs.

____________________________________________________

The Architectural Challenge: Client-Side vs. Server-Side Search

When building a Google search feature on a custom website, developers usually consider one of two paths:

1.     Server-side scraping: Making HTTP requests to Google from the backend (PHP Curl) and parsing the returned HTML.

2.     Official Google Custom Search Engine (CSE): Injecting Google's client-side JavaScript component.

While server-side scraping seems attractive because it allows full UI customization, Google actively blocks script-based automated queries using anti-bot gates (like JS challenges and enablejs redirects). This makes server-side scraping highly fragile.

To deliver a robust, enterprise-ready experience, we designed the Moodle block to support both:

·        Google CSE (Default): Client-side script injection that handles bot detection naturally, uses browser cookies, and provides unlimited free web searches.

·        Google Custom Search JSON API: A server-side REST API proxy that fetches JSON data using an API Key and renders results in a premium custom layout with modern CSS loading skeletons.

____________________________________________________

Step 1: Building the Moodle Block Structure

Moodle plugins follow a strict directory structure. We created a new block named google_search under the blocks/ directory:

blocks/google_search/
├── db/
   └── access.php          # Access capabilities
├── lang/
   └── en/
       └── block_google_search.php  # English translations
├── amd/
   ├── src/
      └── search.js       # AJAX client-side handler (source)
   └── build/
       └── search.min.js   # Production build
├── block_google_search.php # Primary block controller
├── edit_form.php           # Block instance settings
├── settings.php            # Global site-wide settings
├── search_ajax.php         # Server-side JSON API proxy
├── styles.css              # Custom block styling
└── version.php             # Moodle block version metadata

The Block Controller (`block_google_search.php`)

This file defines the block class, which extends block_base. It retrieves configurations (like the Search Engine ID) and renders either the Google CSE script or the custom search form:

class block_google_search extends block_base {
    public function init() {
        $this->title = get_string('pluginname', 'block_google_search');
    }

    public function get_content() {
        global $CFG, $PAGE;
        if ($this->content !== null) {
            return $this->content;
        }

        $this->content = new stdClass();
        $cx = !empty($this->config->cx) ? $this->config->cx : $CFG->block_google_search_cx;
       
        // Render Google Custom Search Engine (CSE)
        $this->content->text = '
            <div class="google-search-cse-container">
                <script async src="https://cse.google.com/cse.js?cx=' . urlencode($cx) . '"></script>
                <div class="gcse-search" data-linktarget="_blank" data-defaultToImageSearch="false"></div>
            </div>
        ';
        return $this->content;
    }
}

____________________________________________________

Step 2: Configuring Google Programmable Search

To display results, the block requires a Search Engine ID (CX ID).

Why You Get "Your search did not match any results"

A common pitfall during setup is searching for a term (like "what is lms") and receiving a blank screen or a "no results matched" warning.

 

Google Programmable Search Results Screen

Google Programmable Block Screen in Moodle LMS

 

Google Programmable Search Results Screen in Moodle LMS

 

By default, newly created Google Custom Search Engines are restricted to searching only the specific websites you entered during setup.

To expand this to the entire web:

3.     Log in to the [Google Programmable Search Control Panel](https://cse.google.com/cse/).

4.     Select your search engine and navigate to Overview.

5.     Under Search settings, locate "Search the entire web" and toggle it ON.

6.     Save the settings. The block will immediately start returning general web results.

____________________________________________________

Step 3: Troubleshooting JavaScript Loading Issues

Because Moodle uses RequireJS to manage and load JavaScript asynchronously on demand, a single syntax error in a custom JavaScript module can crash the entire page script environment.

The Problem: Moodle Menus Not Loading

After installing the block, you might notice that Moodle’s navigation dropdowns and action menus stop working, accompanied by these console errors:

Uncaught SyntaxError: missing ) after argument list
require.min.js:5 Uncaught Error: No define call for core/first

The Fix

This occurs when there is a syntax error (such as a mismatched parenthesis or bracket) in the block's compiled AMD module amd/build/search.min.js. Because Moodle loads the block's JavaScript, the syntax error crashes RequireJS completely, preventing the rest of Moodle's core UI scripts from executing.

To resolve this:

7.     Validate the source Javascript (amd/src/search.js) using a linter or Node:

   node -c blocks/google_search/amd/src/search.js

8.     Replace amd/build/search.min.js with the correct unminified script (Moodle will load unminified JS perfectly).

9.     Clear Moodle's caches to force it to download the corrected script by going to Site Administration > Development > Purge caches and clicking Purge all caches.

____________________________________________________

Step 4: Refining User Experience: Defaulting to Web Search

Google CSE includes two tabs by default: Web and Image. Depending on browser caching or previous settings, Google may default to showing the Image tab.

To force the block to default to text-based web results:

·        Add the data-defaultToImageSearch="false" attribute to Google's <div class="gcse-search"></div> element.

·        If you want to get rid of the Image tab entirely, open your Google Programmable Search console, select your search engine, navigate to Search features > Image Search, and toggle it OFF.

____________________________________________________

Conclusion

By combining Moodle's standard block architecture with Google's Programmable Search Engine, we created a seamless search hub directly inside the LMS. Understanding how Moodle handles RequireJS dependencies and how Google's site-restriction settings work ensures a smooth installation, giving administrators complete control over where students search while keeping their learning workflow uninterrupted.