A modern WordPress plugin for managing custom GA4-style DataLayer events. EventLayer provides a user-friendly interface for creating sophisticated event tracking rules that automatically inject JavaScript for Google Tag Manager and Google Analytics 4 integration.
- Native WordPress Integration: Uses custom post types for event rules with full revision history
- Advanced Event Configuration: Define event types, triggers, and parameters
- Dynamic Parameter Extraction: Extract values from element text or attributes (URL parameters in Pro)
- Debug Mode: Comprehensive logging for troubleshooting
- Modern Architecture: PHP 8.1, PSR-4 autoloading, WordPress coding standards compliant
- Performance Optimized: Efficient JavaScript injection and event handling
- Extensible: Gating provider + hook API for add-ons (EventLayer Pro)
Pro features (via the EventLayer Pro add-on): site location targeting, trigger delays, stop propagation, child selectors, per-instance element control, URL parameter extraction, scheduling, import/export, and unlimited rules (free is capped at 5). See PRO-GATING.md for the full split.
- WordPress 6.4 or higher
- PHP 8.1 or higher
- Modern browser with JavaScript enabled
- Download the plugin zip file
- Go to Plugins → Add New in your WordPress admin
- Click Upload Plugin and select the zip file
- Click Install Now and then Activate Plugin
- Upload the
eventlayerfolder to/wp-content/plugins/ - Activate the plugin through the Plugins menu in WordPress
composer require spotfin/eventlayer- Navigate to EventLayer in your WordPress admin menu
- Click "Add New" to create your first event rule
- Configure your event:
- Event Type: GA4 event name (e.g.,
button_click) - Parent Selector: CSS selector for trigger element (e.g.,
.cta-button) - Parameters: Data to send with the event
- Event Type: GA4 event name (e.g.,
- Publish the event rule to activate it
- Test by enabling debug mode in EventLayer → Settings
Event Type: button_click
Parent Selector: .download-button
Parameters:
- button_text: Element Text → (uses clicked element's text)
- section: Static Value → "hero"
Event Type: form_submit
Parent Selector: form.contact-form
Parameters:
- form_name: Element Attribute → data-form-name
- page_section: URL Parameter → section
Event Type: link_click
Parent Selector: a[href*="external"]
Site Location: All Pages (Pro)
Trigger Delay: 100ms (Pro)
Stop Propagation: Yes (Pro)
Parameters:
- link_url: Element Attribute → href
- link_text: Element Text
- click_source: Static Value → "navigation"
For a button like this:
<aclass="test-button" href="https://google.com" target="_blank">Button Text</a>EventLayer Configuration:
- Event Type:
link_click - Parent Selector:
a.test-button - Site Location: All Pages (Pro)
- Trigger Delay: 100ms (Pro)
- Stop Propagation: Yes (Pro)
Parameters:
| Parameter Name | Target Type | Target Selector | Default Value |
|---|---|---|---|
button_text | Element Text | (clicked element) | - |
button_url | Element Attribute | href | - |
button_target | Element Attribute | target | - |
button_class | Static Value | - | test-button |
Result in dataLayer:
{event: 'link_click',button_text: 'Change This',button_url: 'https://google.com',button_target: '_blank',button_class: 'test-button'}Track all external links:
Parent Selector: a[href^="http"]:not([href*="yourdomain.com"])
Track specific URL:
Parent Selector: a[href="https://google.com"]
Track by multiple attributes:
Parent Selector: a.test-button[target="_blank"]
- Event Type: The GA4 event name sent to dataLayer
- Site Location(Pro): Where the event should be active
- Trigger Delay(Pro): Delay before event fires (in milliseconds)
- Stop Propagation(Pro): Prevent event bubbling
- Schedule(Pro): Only fire between a start and end datetime
- Parent Selector: CSS selector for the trigger element; events fire on all matching elements
- Multiple Elements(Pro): Per-instance control over matched elements
- Child Selectors(Pro): Additional selectors for more specific targeting
Each parameter can extract values using different target types:
- Static Value: Uses the default value
- Element Text: Extracts text content from target element
- Element Attribute: Extracts attribute value (e.g.
href,data-*) - URL Parameter(Pro): Extracts value from query string
Access plugin settings via EventLayer → Settings:
- Debug Mode: Enable console logging for troubleshooting
- Auto Page View Tracking: Automatically track page views
- PHP 8.1+
- Composer (assets are plain CSS/JS; no Node or build step required)
# Clone the repository
git clone https://github.com/Spotfin/EventLayer.git
cd EventLayer
# Install PHP dependencies
composer install
# Install and configure coding standards
composer run phpcs:setupThe project follows WordPress coding standards. Use these commands for code quality:
# Check all files
composer run phpcs
# Fix all auto-fixable issues
composer run phpcbf
# Check just the src/ directory
composer run phpcs:src
# Fix just the src/ directory
composer run phpcbf:src
# Get a summary report
composer run lintcomposer run phpcs # Run PHP CodeSniffer
composer run phpcbf # Run PHP Code Beautifier and Fixer
composer run phpcs:src # Check src/ directory only
composer run phpcbf:src # Fix src/ directory only
composer run phpcs:main # Check main plugin file only
composer run phpcbf:main # Fix main plugin file only
composer run lint # Quick summary report
composer run fix # Fix all issueseventlayer/
├── eventlayer.php # Main plugin file
├── composer.json # Composer configuration
├── phpcs.xml # PHP CodeSniffer rules
├── README.md # This file
├── readme.txt # WordPress plugin readme
├── src/ # Source code
│ ├── Plugin.php # Main plugin class
│ ├── Admin/ # CPT, meta boxes, menu, settings, gating UI
│ │ └── Views/ # Admin templates
│ ├── Data/ # EventRuleRepository (all meta/query access)
│ ├── Frontend/ # Script injection
│ ├── Gating/ # GatingProvider seam (free/pro)
│ ├── Model/ # EventRule, Parameter, enums
│ ├── Assets/ # CSS and JavaScript
│ └── Tests/ # Test files
├── languages/ # Translation files
└── vendor/ # Composer dependencies
EventLayer uses a modern architecture with:
- PSR-4 Autoloading: Organized namespace structure
- Custom Post Types: Native WordPress data storage
- Meta Boxes: Rich admin interface
- Hook-based System: Extensible via WordPress actions/filters
- Singleton Pattern: Single plugin instance
- Repository Pattern: Clean data access layer
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run code quality checks (
composer run lint) - Fix any issues (
composer run fix) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow WordPress Coding Standards
- Use PHP 8.1+ features appropriately (typed properties, promoted constructors, enums, readonly)
- Maintain backwards compatibility
- Add inline documentation for all public methods
- Write unit tests for new functionality
Enable debug mode in EventLayer → Settings to see console output:
- Event initialization messages
- Trigger confirmations
- Parameter extraction details
- Error messages
Events not firing:
- Check CSS selectors are correct
- Verify elements exist on the page
- Ensure event rule is published
- Check browser console for errors
Parameters not working:
- Verify target selectors
- Check parameter target types
- Test with static values first
JavaScript errors:
- Enable debug mode
- Check browser console
- Verify jQuery is loaded
This is the extension API used by EventLayer Pro; third-party plugins can use it too.
// Replace the gating provider (must implement EventLayer\Gating\GatingProvider).$provider = apply_filters( 'eventlayer_gating_provider', $default_free_provider );
// Add or modify parameter target types.$target_types = apply_filters(
'eventlayer_parameter_target_types',
array(
'static' => __( 'Static Value', 'eventlayer' ),
'element_text' => __( 'Element Text', 'eventlayer' ),
'element_attribute' => __( 'Element Attribute', 'eventlayer' ),
)
);
// Whether a rule is injected on the current request.$active = apply_filters( 'eventlayer_rule_is_active', $active, $rule );
// The settings object pushed to JS (eventLayerSettings).$settings = apply_filters( 'eventlayer_frontend_settings', $settings );
// The full rule config pushed to JS (eventLayerConfig).$rules = apply_filters( 'eventlayer_frontend_config', $rules );// Add rows to the Event Settings meta box.do_action( 'eventlayer_event_settings_fields', $rule, $post );
// Add rows to the Trigger Elements meta box.do_action( 'eventlayer_trigger_elements_fields', $rule, $post );Note: debug mode is controlled by the eventlayer_debug_modeoption (Settings → Debug Mode), not a filter.
This project is licensed under the GPL-2.0+ License - see the LICENSE file for details.
EventLayer is developed by Spotfin Creative, a WordPress development agency specializing in custom solutions and performance optimization.
Made with ❤️ by Spotfin Creative


