Skip to content

Development Standards

When to Use

Follow Drupal and Klaro development best practices when extending, theming, or integrating Klaro into custom code.

Decision

Development Task Standard Why
Add custom service programmatically Use Configuration API Exportable, version-controllable, translatable
Modify Klaro behavior Use event subscribers Proper Drupal architecture; avoid hacks
Theme consent modal Override CSS variables first Maintains upgradeability; avoids conflicts
Test consent flow Automated browser testing Regression prevention; compliance verification
Deploy configuration Use config export/import Consistent across environments

Pattern

Programmatic Service Creation (use Configuration API):

// In custom module or update hook
use Drupal\klaro\Entity\KlaroService;

$service = KlaroService::create([
  'id' => 'custom_analytics',
  'label' => 'Custom Analytics',
  'description' => 'Our custom analytics implementation',
  'status' => TRUE,
  'purposes' => ['statistics'],
  'required' => FALSE,
  'toggled_by_default' => FALSE,
  'sources' => ['https://analytics.example.com/tracker.js'],
  'cookies' => ['_custom_analytics'],
]);
$service->save();

Event Subscriber (modify Klaro behavior):

// src/EventSubscriber/KlaroAlterSubscriber.php
namespace Drupal\my_module\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\klaro\Event\KlaroConfigAlterEvent;

class KlaroAlterSubscriber implements EventSubscriberInterface {

  public static function getSubscribedEvents() {
    return [
      KlaroConfigAlterEvent::EVENT_NAME => 'alterKlaroConfig',
    ];
  }

  public function alterKlaroConfig(KlaroConfigAlterEvent $event) {
    $config = $event->getConfig();
    // Modify config array
    $event->setConfig($config);
  }
}

Configuration Export Workflow:

# Export Klaro configuration
drush config:export

# Files exported:
# - klaro.settings.yml (main settings)
# - klaro.service.*.yml (each service)
# - klaro.purpose.*.yml (each purpose)

# Import on other environment
drush config:import

Automated Testing:

// tests/src/FunctionalJavascript/KlaroConsentTest.php
namespace Drupal\Tests\my_module\FunctionalJavascript;

use Drupal\FunctionalJavascriptTests\WebDriverTestBase;

class KlaroConsentTest extends WebDriverTestBase {

  public function testConsentFlow() {
    $this->drupalGet('<front>');

    // Verify modal appears
    $this->assertSession()->waitForElement('css', '#klaro');

    // Click accept
    $this->click('.cm-btn-accept-all');

    // Verify cookie set
    $this->assertTrue($this->getCookie('klaro'));
  }
}

Reference: /modules/contrib/klaro/src/Entity/ for entity definitions

Common Mistakes

  • Wrong: Creating services via UI only → Right: Not version-controlled; use config export
  • Wrong: Directly modifying klaro.js library → Right: Lost on updates; use event subscribers/CSS overrides
  • Wrong: Hard-coding service configuration → Right: Not translatable; use Configuration API
  • Wrong: Skipping automated testing → Right: Consent flow breaks unnoticed; test critical paths
  • Wrong: Not exporting configuration → Right: Dev/staging/prod configs drift; export and commit
  • Wrong: Using hook_preprocess instead of events → Right: Not Klaro-specific; use proper event subscribers
  • Wrong: Inline JavaScript modifications → Right: Maintenance nightmare; use proper API/events

See Also