Sendy.co + Bricks Form Custom Action Integration (FINALLY)

Hello there!

After my last post outlining our arduous efforts at creating a Sendy.co + native Bricks Forms integration via custom actions and then resorting to a custom element, and also after a week or so of learning the most basic of PHP basics, I am glad to let you know that I finally developed a Bricks Forms Custom Action that integrates the self-hosted mailing platform Sendy.

I used the Subscribe via AJAX example API provided here which allowed me to avoid Sendy’s redirects altogether and just subscribe a user to a given list.

I also extensively read the Bricks documentation on Custom Actions in order to understand Bricks form functions and the structure of the arrays they provide. The method I ended up using was calling the different form fields needed by their name attribute rather than ID, in order for the Custom Action to be easily transferable from website to website. Essentially if the name HTML attribute of your Name field is ‘name’, and the name HTML attribute of your email field is ‘email’ your form should work, but here’s the kicker.

I also made the Sendy list ID dynamic, so you can use this custom action with multiple fields. All you need to do is create a hidden field like below and give it a name attribute of ‘sendy-list-id’ then pass your list ID as the value of the field, and voila: A real Bricks Builder Sendy.co multi mailing list integration.

WhatsApp Image 2024-05-29 at 00.51.43

I didn’t write any error checking for now, but this is definitely on my to do list now that I got this working. Hope this helps somebody, although I realise not many people self-host their mailing campaign software. Here’s the code for the custom action, which can be plugged in a child theme’s functions.php. Of course, you would need to replace the placeholders with your Sendy API key and your Sendy installation link.

Maybe this could even lay the groundworks for a Sendy.co integration with vanilla Bricks in the future, in the same way we have a Mailchimp and a Sendgrid integration, since the process doesn’t look that hard.

Cheers,
Tudor.

add_action( 'bricks/form/custom_action', 'sendy_subscription_form', 10, 1 );

function sendy_subscription_form( $form ) {

	$form_settings = $form->get_settings();

  	$form_fields   = $form_settings['fields'];

  	$form_completed_fields = $form->get_fields();

  	foreach ($form_fields as $field_number => $field_values) {

  		switch ($field_values['name']) {

  			case 'name':
				$name_field_id = $field_values['id'];
  				break;

  			case 'email':
				$email_field_id = $field_values['id'];
  				break;

  			case 'sendy-list-id':
				$sendy_list_field_id = $field_values['id'];
  				break;
  		}

  	}

  	$name = $form_completed_fields['form-field-'.$name_field_id];
  	$email = $form_completed_fields['form-field-'.$email_field_id];
  	$sendy_list_id = $form_completed_fields['form-field-'.$sendy_list_field_id];

	//-------------------------- You need to set these --------------------------//
	$sendy_url = 'Your Sendy installation link'; //Your Sendy installation (without the trailing slash)
	$api_key = 'Your Sendy API key'; //Can be retrieved from your Sendy's main settings
	//---------------------------------------------------------------------------//

	//POST variables
	// $name = $_POST['name'];
	// $email = $_POST['email'];
	
	//subscribe
	$postdata = http_build_query(
	    array(
	    'name' => $name,
	    'email' => $email,
	    'list' => $sendy_list_id,
	    'api_key' => $api_key,
	    'boolean' => 'true'
	    )
	);
	$opts = array('http' => array('method'  => 'POST', 'header'  => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata));
	$context  = stream_context_create($opts);
	$result = file_get_contents($sendy_url.'/subscribe', false, $context);
	//--------------------------------------------------//
	
	echo $result;
}
5 Likes

Thank you for this. I modified the code to be more robust, but this was amazing starting point. TY!

1 Like

What did you changed? Can you share ut with us?

1 Like

Just few things that AI (Claude) recommended, including the fallback list, debuging. Here is the full code. Don’t forget to replace Sendy URL, API Key, Fallback list and as @blureogroup said, add “sendy-list-id” in the name attribute of the form.

<?php

add_action('bricks/form/custom_action', 'sendy_subscription_form', 10, 1);
function sendy_subscription_form($form) {
    // Get form data
    $form_settings = $form->get_settings();
    $form_fields = $form_settings['fields'];
    $form_completed_fields = $form->get_fields();

    // Debug (uncomment if needed)
    // error_log('Form Fields: ' . print_r($form_fields, true));
    // error_log('Completed Fields: ' . print_r($form_completed_fields, true));

    // Sendy Configuration
    $sendy_url = 'SENDY INSTALLATION'; // Your Sendy URL (without trailing slash)
    $api_key = 'API KEY '; // Your API key
    $fallback_list_id = 'FALL BACK LIST ID'; // Your fallback list ID

    // Initialize variables
    $email = '';
    $sendy_list_id = '';

    // Loop through form fields to match field types with values
    foreach ($form_fields as $field) {
        $field_id = !empty($field['id']) ? $field['id'] : '';
        $field_key = 'form-field-' . $field_id;

        // Get email from email type field
        if ($field['type'] === 'email' && isset($form_completed_fields[$field_key])) {
            $email = $form_completed_fields[$field_key];
        }

        // Get Sendy List ID from hidden field with name 'sendy-list-id'
        if ($field['type'] === 'hidden' && 
            isset($field['name']) && 
            $field['name'] === 'sendy-list-id' && 
            isset($form_completed_fields['sendy-list-id'])) {
            $sendy_list_id = $form_completed_fields['sendy-list-id'];
        }
    }

    // Use fallback list ID if none found
    if (empty($sendy_list_id)) {
        $sendy_list_id = $fallback_list_id;
    }

    // Validate email
    if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return [
            'success' => false,
            'error' => 'Invalid email address'
        ];
    }

    // Prepare data for Sendy
    $postdata = array(
        'email' => $email,
        'list' => $sendy_list_id,
        'api_key' => $api_key,
        'boolean' => 'true'
    );

    // Make API request to Sendy
    $response = wp_remote_post($sendy_url . '/subscribe', array(
        'body' => $postdata,
        'timeout' => 15,
        'headers' => array(
            'Content-Type' => 'application/x-www-form-urlencoded'
        )
    ));

    // Handle response
    if (is_wp_error($response)) {
        $error_message = $response->get_error_message();
        error_log('Sendy API Error: ' . $error_message);
        return [
            'success' => false,
            'error' => 'Connection error: ' . $error_message
        ];
    }

    $body = wp_remote_retrieve_body($response);
    $http_code = wp_remote_retrieve_response_code($response);

    // Check HTTP response code
    if ($http_code !== 200) {
        error_log('Sendy API HTTP Error: ' . $http_code);
        return [
            'success' => false,
            'error' => 'Server error: ' . $http_code
        ];
    }

    // Handle Sendy response
    switch ($body) {
        case '1':
            return [
                'success' => true,
                'message' => 'Successfully subscribed!'
            ];
        case 'Already subscribed.':
            return [
                'success' => false,
                'error' => 'This email is already subscribed'
            ];
        case 'Invalid email address.':
            return [
                'success' => false,
                'error' => 'Invalid email address'
            ];
        case 'Invalid list ID.':
            return [
                'success' => false,
                'error' => 'Invalid list ID'
            ];
        case 'Invalid API key.':
            error_log('Sendy API Error: Invalid API key');
            return [
                'success' => false,
                'error' => 'Authentication failed'
            ];
        default:
            error_log('Sendy API Unknown Response: ' . $body);
            return [
                'success' => false,
                'error' => 'An unexpected error occurred'
            ];
    }
}
3 Likes

I’m so happy it served as a starting point for your integration on your project, and I’m really glad you improved upon it!

I’ve since moved on to using WS Form which has a Webhook integration by default so I can integrate it easily with Sendy, Listmonk, etc.

But the hours I spent watching PHP tutorials and reading documentation to make this happen were definitely worth it, since I got a better understanding of how these things work.

Happy holidays and very glad that this Sendy integration is helpful to people since I definitely suffered in the beginning trying to make it work :))

1 Like

[SOLVED]Hey,

so I am finally trying to set this up but it just send email with sendy list instead of adding subscriber.

  1. I put code in child theme functions.

  2. I changed this:
    https://mypage.com/sendy
    'API KEY ’
    ‘FALL BACK LIST ID’

  3. Set up hidden field with:
    value: “my sendy list”
    attribute: sendy-list-id

But it doesnt work at all.

Edit: Had to set “custom” in action.

1 Like