Drupal Installation

Add Babel Shield to Drupal 8, 9, or 10 with automatic AJAX form support, CKEditor integration, and Webform compatibility.

Before You Begin

  • A Babel Shield account and API token -- see Getting Started
  • Drupal 8.x, 9.x, or 10.x (the adapter also detects Drupal 7, but the Twig template and hook examples below target Drupal 8+)

Installation Methods

Theme Template (Recommended)

Add the script tag before the closing </body> in your theme's html.html.twig template. This is the simplest method and loads Babel Shield on every page.

Edit themes/YOUR_THEME/templates/html.html.twig:

{# ... existing content ... #}

<script src="https://cdn.babelshield.ai/v1/babel-shield.js"
        data-api-token="YOUR_API_TOKEN">
</script>

</body>
</html>

Asset Library

Define Babel Shield as an external library in your theme's asset files. This method integrates with Drupal's asset management, caching, and aggregation.

Add to YOUR_THEME.libraries.yml:

babel-shield:
  js:
    https://cdn.babelshield.ai/v1/babel-shield.js:
      type: external
      attributes:
        data-api-token: 'YOUR_API_TOKEN'

Attach the library globally in YOUR_THEME.info.yml:

libraries:
  - YOUR_THEME/babel-shield

Custom Module

Create a module that attaches the script via hook_page_attachments(). This gives you conditional loading -- skip admin pages, specific routes, or specific content types.

// babel_shield.module
function babel_shield_page_attachments(array &$attachments) {
  // Skip admin pages
  if (\Drupal::service('router.admin_context')->isAdminRoute()) {
    return;
  }

  $attachments['#attached']['html_head'][] = [
    [
      '#type' => 'html_tag',
      '#tag' => 'script',
      '#attributes' => [
        'src' => 'https://cdn.babelshield.ai/v1/babel-shield.js',
        'data-api-token' => 'YOUR_API_TOKEN',
      ],
    ],
    'babel_shield',
  ];
}

Custom Block Plugin

Create a block plugin that outputs the script tag. Place it in your site's footer region via Block Layout. This method lets non-developers enable or disable Babel Shield through the Block Layout UI.

// modules/custom/babel_shield/src/Plugin/Block/BabelShieldBlock.php
namespace Drupal\babel_shield\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * @Block(
 *   id = "babel_shield",
 *   admin_label = @Translation("Babel Shield")
 * )
 */
class BabelShieldBlock extends BlockBase {

  public function build() {
    return [
      '#type' => 'html_tag',
      '#tag' => 'script',
      '#attributes' => [
        'src' => 'https://cdn.babelshield.ai/v1/babel-shield.js',
        'data-api-token' => 'YOUR_API_TOKEN',
      ],
    ];
  }

}

Note: The block only loads on pages where its region is rendered. If your theme does not render the footer region on certain pages, Babel Shield will not load there.

Attaching to Specific Webforms

Use hook_webform_submission_form_alter() to attach Babel Shield only to specific Webform submission forms. This is useful when you want to moderate a contact form but not every form on the site.

// babel_shield.module
use Drupal\Core\Form\FormStateInterface;

function babel_shield_webform_submission_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  // Only attach to the 'contact' webform
  if ($form['#webform_id'] === 'contact') {
    $form['#attached']['html_head'][] = [
      [
        '#type' => 'html_tag',
        '#tag' => 'script',
        '#attributes' => [
          'src' => 'https://cdn.babelshield.ai/v1/babel-shield.js',
          'data-api-token' => 'YOUR_API_TOKEN',
        ],
      ],
      'babel_shield',
    ];
  }
}

The adapter auto-detects forms matching .webform-submission-form and handles Webform AJAX submissions via the webform:submit event.

What Gets Protected Automatically

Once loaded, Babel Shield detects Drupal and protects these form types:

  • Webform submissions (.webform-submission-form)
  • Contact forms (contact-message-*)
  • Comment forms
  • Node create/edit forms
  • User registration forms
  • AJAX-submitted forms (via Drupal.behaviors)
  • CKEditor content (both CKEditor 4 and CKEditor 5)

What Gets Excluded Automatically

The adapter excludes forms that should not be moderated:

  • Admin forms (/admin/*)
  • Developer tools (/devel/*)
  • Login forms (.user-login-form)
  • Password reset forms (.user-pass)
  • Search forms (.search-form, .search-block-form)
  • Views exposed filters (.views-exposed-form)
  • System configuration forms

Admin exclusion uses both URL path detection and form action URL checking for defense in depth.

AJAX Form Support

Babel Shield registers as Drupal.behaviors.babelShield to handle AJAX forms automatically. When Drupal rebuilds part of the page via AJAX, the behavior re-attaches to new form elements.

For AJAX form submissions, Babel Shield intercepts the jQuery ajaxSend event, moderates the content, and re-triggers approved submissions transparently via Drupal.ajax.

Note: In Drupal 10, jQuery is an optional library. If jQuery is not loaded on a page, AJAX interception falls back to standard submit event handling. Forms still work -- only the AJAX-specific interception path changes.

CKEditor Integration

CKEditor 4 (Drupal 8 and 9)

Content is extracted automatically from window.CKEDITOR.instances. No configuration needed -- the adapter iterates all active editor instances and includes their content in the moderation payload.

CKEditor 5 (Drupal 10)

Content is extracted from Drupal.CKEditor5Instances, a Map keyed by element ID. The adapter reads the editor data from each instance.

CKEditor 5 is the default editor in Drupal 10. The adapter handles both editor versions simultaneously, which is useful during a Drupal 9 to 10 migration when both editors may be present on the same site.

Version-Specific Notes

Feature Drupal 8 Drupal 9 Drupal 10
Installation methods All methods work All methods work All methods work
CKEditor CKEditor 4 (core) CKEditor 4 (deprecated in 9.3+) CKEditor 5 (core)
jQuery Always loaded Always loaded Optional -- may not be on every page
AJAX detection Full (drupalSettings.ajax + jQuery) Full Partial if jQuery absent
Drupal.behaviors Full support Full support Full support

Platform-Specific Troubleshooting

Forms Not Detected

Run BabelShield.diagnose() in the browser console. Check that adapter.name is drupal and adapter.confidence is greater than 0.

If adapter.name is none, verify that Drupal's window.Drupal global is present on the page. The script must load after the Drupal JavaScript framework initializes.

AJAX Forms Not Protected

Check the browser console for Drupal.behaviors.babelShield registration. If not present, the script may have loaded before Drupal.behaviors was available.

On Drupal 10, verify jQuery is loaded on the page by checking window.jQuery in the console. Without jQuery, AJAX form interception uses the standard submit event fallback.

CKEditor Content Not Extracted

  • CKEditor 4: Check window.CKEDITOR.instances in the console. Each editor instance should appear as a property.
  • CKEditor 5: Check Drupal.CKEditor5Instances in the console. It should be a Map containing your editor instances.
  • Ensure the editor is fully initialized before form submission.

For API-level errors (rate limits, CORS, authentication), see Troubleshooting.

Next Steps