FLBuilderService base class. This allows you to integrate any email service provider with Beaver Builder’s subscribe and contact form modules.
Overview
Custom service integrations require:- A PHP class extending
FLBuilderService - Implementation of three abstract methods
- Registration with Beaver Builder
- Optional: Custom API wrapper class
Basic Service Structure
File Location
Create your service file in your plugin or theme:your-plugin/
├── includes/
│ └── class-bb-service-custom.php
└── your-plugin.php
Minimal Service Class
<?php
/**
* Custom Email Service Integration
*/
final class FLBuilderServiceCustom extends FLBuilderService {
/**
* Service ID - must be unique
*/
public $id = 'custom';
/**
* Test API connection
*/
public function connect($fields = array()) {
$response = array(
'error' => false,
'data' => array(),
);
// Validate fields
if (empty($fields['api_key'])) {
$response['error'] = __('Please enter an API key.', 'your-plugin');
return $response;
}
try {
// Test connection to your service
$api = new CustomEmailAPI($fields['api_key']);
$result = $api->testConnection();
if ($result) {
$response['data'] = array(
'api_key' => $fields['api_key'],
);
} else {
$response['error'] = __('Invalid API key.', 'your-plugin');
}
} catch (Exception $e) {
$response['error'] = $e->getMessage();
}
return $response;
}
/**
* Render connection settings form
*/
public function render_connect_settings() {
ob_start();
FLBuilder::render_settings_field('api_key', array(
'row_class' => 'fl-builder-service-connect-row',
'class' => 'fl-builder-service-connect-input',
'type' => 'text',
'label' => __('API Key', 'your-plugin'),
'help' => __('Enter your API key from your account settings.', 'your-plugin'),
'preview' => array(
'type' => 'none',
),
));
return ob_get_clean();
}
/**
* Render service-specific fields (lists, tags, etc.)
*/
public function render_fields($account, $settings) {
$account_data = $this->get_account_data($account);
$response = array(
'error' => false,
'html' => '',
);
if (!$account_data) {
$response['error'] = __('Account not found.', 'your-plugin');
return $response;
}
try {
$api = new CustomEmailAPI($account_data['api_key']);
$lists = $api->getLists();
// Render list selection
$response['html'] = $this->render_list_field($lists, $settings);
} catch (Exception $e) {
$response['error'] = $e->getMessage();
}
return $response;
}
/**
* Subscribe a user
*/
public function subscribe($settings, $email, $name = false) {
$account_data = $this->get_account_data($settings->service_account);
$response = array(
'error' => false,
);
if (!$account_data) {
$response['error'] = __('Account not connected.', 'your-plugin');
return $response;
}
try {
$api = new CustomEmailAPI($account_data['api_key']);
$subscriber_data = array(
'email' => $email,
'list_id' => $settings->list_id,
);
if ($name) {
$names = explode(' ', $name, 2);
$subscriber_data['first_name'] = $names[0];
if (isset($names[1])) {
$subscriber_data['last_name'] = $names[1];
}
}
$result = $api->subscribe($subscriber_data);
if (!$result) {
$response['error'] = __('Subscription failed.', 'your-plugin');
}
} catch (Exception $e) {
$response['error'] = $e->getMessage();
}
return $response;
}
/**
* Render list selection field
*/
private function render_list_field($lists, $settings) {
ob_start();
$options = array(
'' => __('Choose...', 'your-plugin'),
);
foreach ($lists as $list) {
$options[$list['id']] = $list['name'];
}
FLBuilder::render_settings_field('list_id', array(
'row_class' => 'fl-builder-service-field-row',
'class' => 'fl-builder-service-list-select',
'type' => 'select',
'label' => __('List', 'your-plugin'),
'options' => $options,
'preview' => array(
'type' => 'none',
),
), $settings);
return ob_get_clean();
}
}
Registration
Register Your Service
Register your custom service with Beaver Builder:/**
* Register custom email service
*/
function register_custom_email_service() {
if (!class_exists('FLBuilder')) {
return;
}
// Load your service class
require_once plugin_dir_path(__FILE__) . 'includes/class-bb-service-custom.php';
}
add_action('init', 'register_custom_email_service');
Make Service Available
Beaver Builder automatically detects service classes that extendFLBuilderService. Ensure your class:
- Extends
FLBuilderService - Has a unique
$idproperty - Is loaded before services are initialized
Advanced Features
API Wrapper Class
Create a separate API wrapper for cleaner code:<?php
/**
* Custom Email Service API Wrapper
*/
class CustomEmailAPI {
private $api_key;
private $api_url = 'https://api.customservice.com/v1/';
public function __construct($api_key) {
$this->api_key = $api_key;
}
/**
* Test connection
*/
public function testConnection() {
$response = $this->request('GET', 'account');
return isset($response['id']);
}
/**
* Get lists
*/
public function getLists() {
return $this->request('GET', 'lists');
}
/**
* Subscribe user
*/
public function subscribe($data) {
return $this->request('POST', 'subscribers', $data);
}
/**
* Make API request
*/
private function request($method, $endpoint, $data = array()) {
$url = $this->api_url . $endpoint;
$args = array(
'method' => $method,
'headers' => array(
'Authorization' => 'Bearer ' . $this->api_key,
'Content-Type' => 'application/json',
),
);
if (!empty($data)) {
$args['body'] = json_encode($data);
}
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
$code = wp_remote_retrieve_response_code($response);
if ($code >= 400) {
$message = isset($result['message']) ? $result['message'] : 'API Error';
throw new Exception($message);
}
return $result;
}
}
Supporting Multiple Fields
Add support for tags, custom fields, or other features:public function render_fields($account, $settings) {
$account_data = $this->get_account_data($account);
$response = array(
'error' => false,
'html' => '',
);
try {
$api = new CustomEmailAPI($account_data['api_key']);
// Render list field
$lists = $api->getLists();
$response['html'] .= $this->render_list_field($lists, $settings);
// Render tags field
$response['html'] .= $this->render_tags_field($settings);
// Render custom fields
if (isset($settings->list_id)) {
$custom_fields = $api->getCustomFields($settings->list_id);
$response['html'] .= $this->render_custom_fields($custom_fields, $settings);
}
} catch (Exception $e) {
$response['error'] = $e->getMessage();
}
return $response;
}
private function render_tags_field($settings) {
ob_start();
FLBuilder::render_settings_field('tags', array(
'row_class' => 'fl-builder-service-field-row',
'type' => 'text',
'label' => __('Tags', 'your-plugin'),
'help' => __('Comma-separated list of tags.', 'your-plugin'),
'preview' => array('type' => 'none'),
), $settings);
return ob_get_clean();
}
OAuth Authentication
Implement OAuth flow like AWeber:public function render_connect_settings() {
ob_start();
?>
<p><?php _e('Click the button below to connect your account:', 'your-plugin'); ?></p>
<a href="<?php echo $this->get_oauth_url(); ?>" class="fl-builder-button" target="_blank">
<?php _e('Connect Account', 'your-plugin'); ?>
</a>
<div style="margin-top: 20px;">
<?php
FLBuilder::render_settings_field('auth_code', array(
'row_class' => 'fl-builder-service-connect-row',
'type' => 'text',
'label' => __('Authorization Code', 'your-plugin'),
'help' => __('Paste the authorization code here.', 'your-plugin'),
'preview' => array('type' => 'none'),
));
?>
</div>
<?php
return ob_get_clean();
}
private function get_oauth_url() {
$params = array(
'client_id' => 'your-client-id',
'redirect_uri' => admin_url('admin.php?page=fl-builder-settings'),
'response_type' => 'code',
'scope' => 'read write',
);
return 'https://oauth.service.com/authorize?' . http_build_query($params);
}
public function connect($fields = array()) {
if (empty($fields['auth_code'])) {
return array(
'error' => __('Please provide authorization code.', 'your-plugin'),
'data' => array(),
);
}
// Exchange auth code for access token
$token = $this->exchange_auth_code($fields['auth_code']);
if (!$token) {
return array(
'error' => __('Invalid authorization code.', 'your-plugin'),
'data' => array(),
);
}
return array(
'error' => false,
'data' => array(
'access_token' => $token,
),
);
}
Caching API Responses
Cache expensive API calls:public function render_fields($account, $settings) {
$cache_key = 'custom_service_lists_' . md5($account);
$lists = get_transient($cache_key);
if (false === $lists) {
try {
$account_data = $this->get_account_data($account);
$api = new CustomEmailAPI($account_data['api_key']);
$lists = $api->getLists();
// Cache for 1 hour
set_transient($cache_key, $lists, HOUR_IN_SECONDS);
} catch (Exception $e) {
return array(
'error' => $e->getMessage(),
'html' => '',
);
}
}
return array(
'error' => false,
'html' => $this->render_list_field($lists, $settings),
);
}
Webhook Support
Add webhook functionality:public function subscribe($settings, $email, $name = false) {
$account_data = $this->get_account_data($settings->service_account);
$response = array('error' => false);
try {
$api = new CustomEmailAPI($account_data['api_key']);
$result = $api->subscribe($subscriber_data);
// Trigger webhook
do_action('fl_builder_custom_service_subscribed', array(
'email' => $email,
'name' => $name,
'list_id' => $settings->list_id,
'result' => $result,
));
} catch (Exception $e) {
$response['error'] = $e->getMessage();
// Log error
do_action('fl_builder_custom_service_error', array(
'email' => $email,
'error' => $e->getMessage(),
));
}
return $response;
}
Testing Your Service
Manual Testing
- Activate your plugin/theme
- Go to Settings > Beaver Builder > Services
- Add a new account for your service
- Test the connection
- Create a subscribe form module
- Select your service and configure settings
- Test form submission
Automated Testing
// PHPUnit test example
class CustomServiceTest extends WP_UnitTestCase {
public function test_connection() {
$service = new FLBuilderServiceCustom();
$result = $service->connect(array(
'api_key' => 'test-key',
));
$this->assertFalse($result['error']);
$this->assertArrayHasKey('api_key', $result['data']);
}
public function test_subscribe() {
$service = new FLBuilderServiceCustom();
$settings = new stdClass();
$settings->service_account = 'test-account';
$settings->list_id = '123';
$result = $service->subscribe(
$settings,
'[email protected]',
'Test User'
);
$this->assertFalse($result['error']);
}
}
Error Handling Best Practices
try {
$api = new CustomEmailAPI($account_data['api_key']);
$result = $api->subscribe($data);
if (!$result) {
throw new Exception(__('Subscription failed', 'your-plugin'));
}
} catch (Exception $e) {
// Log error for debugging
error_log('Custom Service Error: ' . $e->getMessage());
// User-friendly error message
$response['error'] = sprintf(
__('Unable to subscribe: %s', 'your-plugin'),
$e->getMessage()
);
}