How to create a newsletter subscription form using Uniform & Mailchimp?

Tried to do what you’ve said but the problem remains… grandchildren pages gets the following error on submit:

 ! Fatal error: Uncaught No Uniform actions were given.
 thrown in /Users/me/Sites/masite/site/plugins/uniform/lib/UniForm.php on line 126

Yes, the messages are defined in the language files:

l::set('uniform-fields-required', 'Please fill in all required fields.');
l::set('uniform-fields-not-valid', 'Some fields do not contain valid data.');

This affects all forms on the whole site, though. If you have multiple forms and only one of them should have different messages you have to do a little hack: You have to change the language strings in the controller/route just before the uniform() call and then reset them again afterwards.

And this error doesn’t occur if you use the (:all)/newsletter/subscribe route? This doesn’t make sense :confused:
The route is working properly since Uniform is called but an error like that is only thrown if the actions array is misconfigured/empty. Did you change anything in the route besides the pattern?

I ended up using jquery to show these different messages… not ideal but it’ll do till I figure out how to do this… because this site isn’t multilang so I’ve modified UniForm.php to use c::get instead of l::get… and defined those text messages in the config file.


No… it works perfectly.
I also don’t know why.


Absolutely nothing… these subpages/grandchildrem… they have another form that uses Uniform… but I’ve checked their vars and no naming conflict.

Here’s the whole form/jquery and the router:



<section class="newsletter">

  <form id="newsletter" method="post">

    <input type="hidden" name="_submit" value="<?php echo uniform('newsletter-subscription')->token() ?>">
    <label class="hidden form__potty" for="website">Please leave this field blank</label>
    <input type="text" name="website" id="website" class="hidden form__potty" />


    <div class="hidden" id="feedback">
      <div class="feedback-message">Sending...</div>
    </div>  


    <p>
      <label class="hidden" for="email">Email *</label>
      <input  type="email" name="_from" id="email" value="" placeholder="Email" required />
    </p>


    <p>
      <button type="submit">Sign up</button>
    </p>


  </form>
</section>


<script>
    // AJAX FORM PROCESSING
    $('#newsletter').on('submit', function(e){

        e.preventDefault();
        var form = $(this); 
        var feedback = $('#feedback');
        feedback.removeClass('hidden').slideDown('slow');
        feedback.find('.feedback-message').html('Sending...');

        $.ajax({
            type: 'POST',
            // use the same url here as the 'pattern' in your route
            url: '<?php echo $page->url() ?>/newsletter/subscribe',
            data: form.serialize(),

            // this success means the ajax call reached the api/action
            success: function(response){ 

              if (response.success) { // show messages from mailchimp action 
                var msg = "<b>Thank you</b> <br>"; 
                msg += response.message;
                feedback.find('.feedback-message').html(msg); 

                form.find('#email, button').prop('disabled', 'disabled');

              } else { // a validation error was encountered 
                var msg = "<b>Oops</b> <br>"; 
                msg += "This email looks wrong.";
                feedback.find('.feedback-message').html(msg);
              }

            },
            // the form was unable to reach processor api
            error: function(response){
              feedback.removeClass('hidden');
              feedback.find('.feedback-message').text('An error has occurred.');
            },
            dataType: 'json'
        });

        $('html,body').animate({
            'scrollTop':   $('#newsletter').offset().top
        }, 400);
    });
</script>

The router:

array(
    // in 'pattern', enter the same url being called from your ajax javascript function
    'pattern' => '(:all)/newsletter/subscribe',
    'method' => 'POST',
    'action' => function() {

      // check whether this is an ajax request, and respond with an error if it isn't
      if (!kirby()->request()->ajax()) return site()->errorPage();

      $newsletter = uniform('newsletter-subscription', [
         'required' => [
            '_from' => 'email'
         ],
         'actions' => [[
            '_action' => 'mailchimp',
            'api_key' => 'xxxxxxxxxxxxxxxxxxxxx-us6',
            'list_id' => 'xxxxxxx', 
         ]]
      ]);

      // get the names of all erroneous fields
      $errors = array_keys(array_filter(get(), function ($field) use ($newsletter) {
         return $newsletter->hasError($field);
      }, ARRAY_FILTER_USE_KEY));


      return response::json([
         'success' => $newsletter->successful(),
         'message' => trim($newsletter->message()),
         'errors' => $errors,
      ]); 


    }
  )

1 Like

So everything works as expected now?

Yes indeed Martin… again, thanks a lot for all your help. :vulcan:

Wow, epic thread!
The resulting code would make for a great “how-to” post :slight_smile:

3 Likes

Thanks @Malvese, I’ll try to do something like @luxlogica did here.

It was hugely helpful.

2 Likes