Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/elpuas/epdc-conversations/archive/refs/heads/main.zipNo built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.
EPDC Conversations is an internal WordPress plugin focused on conversion-oriented WhatsApp calls to action. It provides a shared floating CTA, reusable inline/button renderers, anonymous click tracking, and a small analytics surface for EPDC-managed sites.
Overview
Purpose
- Increase lead generation through WhatsApp CTAs.
- Keep rendering server-side first and JavaScript minimal.
- Preserve privacy by avoiding direct personal data storage in the tracking layer.
Features
- Global floating WhatsApp button.
- Inline rendering through shortcode and Gutenberg block.
- Dynamic message variables such as
{site_name}and{current_url}. - Anonymous tracking for WhatsApp clicks.
- Optional GA4 event forwarding when
gtag()is present. - Lightweight admin analytics page.
- Public hooks for rendering, messaging, analytics, and tracking extensions.
Architecture
epdc-conversations.php: plugin bootstrap and lifecycle hooks.src/Infrastructure: plugin wiring, settings access, lifecycle, asset registration.src/Frontend: shared server-side renderer for shortcode, block, and floating button output.src/Messaging: message variable parsing.src/Tracking: REST endpoint, session cookie handling, tracking persistence.src/Admin: settings page and analytics queries/screens.blocks/conversations: Gutenberg block registration script and metadata.templates/frontend-button.php: shared CTA template.assets/css/frontend.cssandassets/js/frontend.js: minimal frontend runtime.
Requirements
- WordPress 6.6+
- PHP 8.2+
- Composer for local development
Installation
Composer install
composer install
WordPress installation
- Copy the plugin into
wp-content/plugins/epdc-conversations. - Install dependencies with Composer if the plugin was checked out from source.
Activation
- Activate EPDC Conversations from the WordPress admin.
- Activation creates the
{$wpdb->prefix}epdc_conversation_eventstable used by tracking and analytics.
Settings
All settings are stored in the epdc_conversations_options option.
Supported settings
phone_number: Default WhatsApp number. Digits only are persisted.default_message: Base CTA message template.enable_floating_button: Enables or disables the global floating CTA.show_on_mobile: Controls mobile visibility for the floating CTA.show_on_desktop: Controls desktop visibility for the floating CTA.button_position:bottom-rightorbottom-left.button_label: Visible button text.button_variant:default,compact, oricon-only.button_size:small,medium, orlarge.show_button_icon: Controls whether the floating CTA includes the WhatsApp icon.open_in_new_tab: Opens the WhatsApp URL in a new tab when enabled.enable_ga_tracking: Forwards CTA clicks to GA4 whenwindow.gtagexists.
Notes
- Settings are sanitized through the Settings API.
- Button output still passes through the shared renderer, so shortcode and block overrides inherit the same escaping and URL generation rules.
Shortcode Usage
Basic examples
[epdc_conversations]
[epdc_conversations message="Hello"]
[epdc_conversations label="Chat with sales" variant="compact"]
[epdc_conversations phone_number="50612345678" size="large" new_tab="yes" show_icon="no"]
[epdc_conversations variant="icon-only" size="small"]
Supported shortcode attributes
message: Message template override.label: Visible text override.phone_number: WhatsApp number override. Non-digits are stripped before rendering.variant:default,compact, oricon-only. Legacyinlinevalues are normalized tocompact.size:small,medium, orlarge.show_icon: Truthy/falsey string flag.no,false,off, and0disable the icon.new_tab: Truthy/falsey string flag.yes,true,on, and1enable a new tab.
Gutenberg Block
Block name
epdc/conversations
Supported attributes
messagelabelphoneNumbervariantsizeshowIconnewTab
Usage examples
- Insert the EPDC Conversations block and use plugin defaults.
- Override the label or message for a single page.
- Use the
compactvariant inside landing page content. - Use the
icon-onlyvariant for tighter floating or utility-style placements.
Dynamic rendering behavior
- The block is server-side rendered.
- Block attributes are sanitized in PHP before the shared renderer is called.
- Output is identical to the shortcode path because both use
EPDC\Conversations\Frontend\Renderer.
Dynamic Variables
Built-in variables
{site_name}{post_title}{post_url}{current_url}
Custom variable extension
Use the epdc_conversations_variables filter to register additional variables.
add_filter(
'epdc_conversations_variables',
function ( array $variables, array $context ): array {
$variables['{campaign_name}'] = 'Summer Promo';
return $variables;
},
10,
2
);
Tracking System
Architecture
- Frontend clicks are captured by
assets/js/frontend.js. - The script sends a POST request to
epdc-conversations/v1/track. EPDC\Conversations\Tracking\TrackingServicevalidates, sanitizes, and stores the event.- Analytics pages read from the custom events table through
AnalyticsRepository.
REST endpoint
- Namespace:
epdc-conversations/v1 - Route:
/track - Method:
POST
Accepted payload
event_typepage_urlreferrer_urldevice_typeutm_sourceutm_mediumutm_campaign
Database schema
Table: {$wpdb->prefix}epdc_conversation_events
idcreated_atsession_idevent_typepage_urlreferrer_urlutm_sourceutm_mediumutm_campaigndevice_typeuser_agentip_hash
Session tracking
- Anonymous visitors receive a UUIDv4 cookie named
epdc_conversations_session. - Cookie flags:
HttpOnly,SameSite=Lax, andSecureon SSL requests.
GA4 integration behavior
- GA forwarding is optional and settings-controlled.
- No GA request is attempted unless
window.gtagexists. - Default event name:
epdc_whatsapp_click
Security Review Notes
Decisions
- Tracking requests require a WordPress REST nonce (
wp_rest) even though the endpoint is public-facing. - REST arguments are sanitized and validated before use.
- UTM values and URLs are length-limited before persistence.
- URLs are restricted to
httpandhttps. - All analytics queries use
$wpdb->prepare()or$wpdb->insert()format arrays. - Output is escaped in templates and admin screens.
- The shared renderer normalizes filtered arguments after hooks run, preventing unsafe values from being echoed directly.
- Admin screens require
manage_options. - Raw IP addresses are never stored. Only
hash( 'sha256', $ip )is persisted. - The session identifier shown in analytics is truncated for privacy.
Graceful failure behavior
- Tracking failures do not block link navigation.
- Invalid tracking requests return
WP_Errorresponses with explicit HTTP status codes. - If asset files are missing, asset registration falls back to the plugin version constant.
Hooks Reference
Filters
epdc_conversations_variables
- Type: filter
- Arguments:
array $variables,array $context - Purpose: register or override dynamic message variables.
epdc_conversations_message
- Type: filter
- Arguments:
string $message,array $context - Purpose: modify the final parsed WhatsApp message before URL generation.
epdc_conversations_button_classes
- Type: filter
- Arguments:
array $classes,array $context - Purpose: modify the renderer CSS classes.
epdc_conversations_button_args
- Type: filter
- Arguments:
array $args,array $context - Purpose: change renderer arguments before final normalization.
epdc_conversations_url
- Type: filter
- Arguments:
string $url,array $args - Purpose: override the final WhatsApp URL.
epdc_conversations_should_render_floating_button
- Type: filter
- Arguments:
bool $should_render - Purpose: disable or force the global floating CTA.
epdc_conversations_tracking_payload
- Type: filter
- Arguments:
array $payload - Purpose: modify the sanitized tracking payload before insertion.
epdc_conversations_event_insertion_data
- Type: filter
- Arguments:
array $data,array $payload - Purpose: adjust the final row written to the database.
epdc_conversations_tracking_event_types
- Type: filter
- Arguments:
array $event_types - Purpose: extend the allow-list of trackable event names.
epdc_conversations_ga_event_payload
- Type: filter
- Arguments:
array $ga_event_payload - Purpose: change the GA payload localized to the frontend script.
epdc_conversations_ga_event_name
- Type: filter
- Arguments:
string $event_name - Purpose: override the frontend GA event name.
epdc_conversations_analytics_metrics
- Type: filter
- Arguments:
array $metrics - Purpose: modify dashboard metric totals before rendering.
epdc_conversations_top_pages_query_args
- Type: filter
- Arguments:
array $args - Purpose: adjust the top-pages analytics query arguments.
epdc_conversations_recent_events_query_args
- Type: filter
- Arguments:
array $args - Purpose: adjust the recent-events analytics query arguments.
Actions
epdc_conversations_event_tracked
- Type: action
- Arguments:
int $event_id,array $payload - Purpose: react after a tracking row is stored successfully.
epdc_conversations_analytics_page_sections
- Type: action
- Arguments:
string $selected_range,array $metrics,array $top_pages,array $recent_events - Purpose: append extra sections to the analytics screen.
Hook examples
add_filter(
'epdc_conversations_message',
function ( string $message, array $context ): string {
if ( ! empty( $context['is_floating'] ) ) {
return $message . ' - floating CTA';
}
return $message;
},
10,
2
);
add_action(
'epdc_conversations_event_tracked',
function ( int $event_id, array $payload ): void {
do_action( 'my_analytics_bridge_track_whatsapp_click', $event_id, $payload );
},
10,
2
);
Developer Notes
Architectural decisions
- The plugin keeps a small service-based architecture without introducing container complexity.
- The shared renderer avoids divergent output paths between the floating button, shortcode, and block.
Shared renderer approach
Renderer::render_button()is the single HTML generation path.- Block and shortcode inputs are normalized before they reach the renderer.
- Filtered renderer args are normalized again before template output as a final safety pass.
SSR behavior
- The floating CTA, shortcode, and block all render on the server.
- JavaScript is only responsible for click tracking and optional GA forwarding.
Accessibility philosophy
- CTA markup includes explicit
aria-labeltext. - Focus-visible styles are present in the frontend stylesheet.
- Motion effects are reduced when
prefers-reduced-motionis enabled. - Admin settings controls now include stable IDs and description associations.
Performance philosophy
- Rendering stays server-side.
- Frontend JavaScript is small and event-driven.
- Shared assets are only enqueued when a button instance is actually rendered.
- Asset versions use file modification times for cache busting.
Validation
PHPCS
Run:
composer phpcs
PHP syntax
Run:
find . -name '*.php' -print0 | xargs -0 -n1 php -l
Plugin Check
Recommended:
- Install the WordPress Plugin Check plugin in a local development site.
- Run the EPDC Conversations plugin through the standard Plugin Check scan.
Remaining warnings and intentional deviations
- The Composer PHPCS script excludes
WordPress.Files.FileNamebecause the plugin intentionally uses PSR-4 class filenames instead of WordPressclass-*.phpnaming. - The Composer PHPCS script excludes
Universal.Arrays.DisallowShortArraySyntaxbecause short array syntax is a project convention. - The Composer PHPCS script excludes
WordPress.DB.PreparedSQLbecause the custom table name derived from$wpdb->prefixproduces false positives in otherwise prepared queries. - Plugin Check is an external WordPress runtime review and may not be available from this repository alone.
- The analytics admin page still uses inline CSS for a very small, screen-specific layout. This is intentional to avoid introducing another admin-only asset for a narrow internal screen.