This plugin allows you to collect PayPal payments using Formidable Forms. You can send users and a total directly to PayPal after submitting a Formidable form. Your users do NOT need to have a Paypal account in order to pay with Paypal.

Download and install

  1. Download latest version of the PayPal Standard plugin
  2. In your WordPress admin, go to "Plugins" > "Add New" and click the "Upload Plugin" button at the top of the page.
  3. Upload the zip file you just downloaded in step one. Once the plugin is installed, click "Activate Plugin" or go to the "Plugins" page, find "Formidable Payment" and click "Activate".

Set up the Paypal add-on

Now that the PayPal plugin is activated you’ll need to set up Formidable Forms to integrate with your PayPal account. To do this you'll need to connect your paypal account and set up instant payment notifications.

Connect your Paypal account

  1. Now that the plugin is activated, go to "Formidable" > "Global Settings" and click the "Paypal" tab.
  2. Insert your PayPal email address and update any other settings. For live sites, make sure the "PayPal" environment is set to "Live"; otherwise, users will be prompted to set up new PayPal accounts.
    PayPal Global Settings

Set up instant payment notifications

In order for your payments to get correctly marked as paid, you must configure your PayPal account to send payment notifications. Follow the directions below to set this up.

  1. Log into your PayPal account.
  2. Go to your "Profile and settings" page and then "My Selling Tools".
  3. Click the "Update" link next to "Instant Payment Notifications".
    PayPal IPN
  4. Edit and enter a notification URL. It doesn’t matter what URL you insert since Formidable PayPal will override it.
  5. Enable IPN Messages.
  6. Click Save.
    PayPal IPN Email

Using the testing mode

Before you can use the test mode, you'll need to create both a personal and business PayPal account at Be sure to setup the IPN on your sandbox business account as well. Use your sandbox business email in your form settings, and pay using your personal sandbox email when you run through test transactions.

Set up a form to take Paypal payments

Once you have the Paypal add-on activated make sure you connect your Paypal account and set up instant payment notifications. After doing so, you can set up a form to take Paypal payments. Follow the directions below to collect Paypal payments with a Formidable form.

  1. Go into edit the form you would like to use with Paypal. Click on "Settings" → "Form Actions" → "PayPal".
    PayPal Icon
  2. Give your Paypal action a Label for easy reference. This label will only be seen on the back-end.
    PayPal Label
  3. Set the Item Name. The item name will appear on the PayPal page and on the PayPal receipt. You can either type in a static product name or select a field from your form if it will change depending on your user's selection.
    PayPal Item Name
  4. Set an Amount for the payment. You can either select a field from your form (this field should contain the payment amount) or select "Set Amount" and insert a value in the box.
    PayPal Amount
  5. If this form will be used to collect Donations, select "Payments made in this form are donations".
    Paypal Donations
  6. If you do not want the user to receive Notifications until after the payment is received, check "Hold email notifications until payment is received".
    PayPal Notifications
  7. If you would like to conditionally send users to Paypal after form submission, you will need to add Conditional Logic.
    PayPal Conditional Logic
  8. Don’t forget to hit "Update" so these settings will be saved.

Save payment status in a field

If you would like to save the status of a payment in a field in your form, follow the instructions below.

  1. Go into edit a form that has a Paypal action included.
  2. Add a dropdown field. Title it 'Payment status' and add the options 'Pending' and 'Completed'. Select 'Pending' as the default value.
  3. Go into your form's 'Settings' → 'Form Actions' and open the Paypal action.
  4. Scroll down to the After Payment section. Click the "Add" button.
  5. In the 'Payment Status' column, select 'Completed'. In the 'Field' column, select your 'Payment status' field. In the Value column, select 'Completed'.
  6. Hit Update. Now when a payment is successfully completed, your payment status field will switch to 'Completed' to reflect the status of the Paypal payment.

Additional customizations

These code examples can be added to a child theme's functions.php file or the Code Snippets plugin.

Add a currency

If you need to take a payment in a currency that is not included in the Paypal action's currency options, you may add a currency using the code below.

add_filter('frm_currencies', 'add_custom_currency');
function add_custom_currency( $currencies ) {
    $currencies['USD'] = array(
        'name' => __('U.S. Dollar', 'frmpp'),
        'symbol_left' => '$', 'symbol_right' => '', 'symbol_padding' =>  '',
        'thousand_separator' => ',', 'decimal_separator' => '.', 'decimals' => 2,

    return $currencies;

Limit number of recurring payments

Setting an end date for recurring payments is not currently an option, but you may use the code below to only have a certain number of recurring payments. Replace 5 with your form ID. Replace 4 with the number of recurring payments that you want to take.

add_filter( 'formidable_paypal_url', 'set_recurring_payment_limit', 10, 3 );
function set_recurring_payment_limit( $paypal_url, $entry_id, $form_id ) {
	if ( $form_id == 5 ) { //change 5 to the ID of your form
		$paypal_url .= '&srt=4';
	return $paypal_url;

Automatically publish a post after payment.

Please Note: This feature is built into the PayPal Standard plugin. If you have a post status field in your form, you can set it to change after payment using the "After payment" settings section inside your form action.
If your entry is set up to create WordPress posts, you can prevent the post from being created until payment is successful:

add_action('frm_payment_paypal_ipn', 'publish_paid_post');
function publish_paid_post($args){
   return; //don't publish if the payment was not completed
   return; //don't publish if not linked to a post
wp_update_post(array('ID' => $args['entry']->post_id, 'post_status' => 'publish'));

Change the user role after payment

The only change needed in the example is the user role the user should have: $new_role = 'contributor';

add_action('frm_payment_paypal_ipn', 'change_paid_user_role');

function change_paid_user_role($args){
    $new_role = 'contributor'; //change this to the role paid users should have
       return; //don't continue if the payment was not completed

    if(!$args['entry']->user_id or !is_numeric($args['entry']->user_id))
       return; //don't continue if not linked to a user

    $user = get_userdata($args['entry']->user_id);
        return; //don't continue if user doesn't exist

    $updated_user = (array)$user;

    // Get the highest/primary role for this user  
    $user_roles = $user->roles;
    $user_role = array_shift($user_roles);
    if ( $user_role == 'administrator' ) 
        return; //make sure we don't downgrade any admins

    $updated_user['role'] = $new_role;

Save transaction ID in field

If you would like to save the transaction ID in a field after the payment is complete, you may use the code below. You can add it to a child theme's functions.php file or the Code Snippets plugin. Replace 10 with the ID of your form and replace 123 with the ID of the field that will store the transaction ID. Make sure the field is blank by default or you will get extra data added to your database when this code is triggered.

add_action('frm_payment_paypal_ipn', 'save_frmpaypal_transaction_id');
function save_frmpaypal_transaction_id( $vars ){

    if ( ! $vars['pay_vars']['completed'] ) {
        return; //don't change value if the payment was not completed

    if ( $vars['entry']->form_id == 10 ) {
        $field_id = 123;
        $transaction_id = $vars['pay_vars']['receipt_id'];
        if ( $transaction_id ) {
            FrmEntryMeta::add_entry_meta( $vars['entry']->id, $field_id, null, $transaction_id );

Change return URL

Please Note: The Return URL option has been added to the PayPal action since version 3.0.

add_filter('formidable_paypal_url', 'formidable_paypal_url', 10, 3);
function formidable_paypal_url($paypal_url, $entry_id, $form_id){
  if($form_id == 5) //change 5 to the ID of your form
    $paypal_url .= '&return='. urlencode('');
  return $paypal_url;

If the one-time payment fails the first time, you can generate a link to allow users to pay again without filling out the form a second time. This shortcode can be used in a number of different ways, but the most likely would be in a view where you can add filters like "User ID is equal to current user", and the shortcode would be [pay_again id=[id]]. You can also set a specific entry id here if you would like [pay_again id=60].

Note: This isn't setup to work with recurring payments.

add_shortcode('pay_again', 'pay_frm_again');
function pay_frm_again($atts) {
    if ( ! class_exists('FrmPaymentsController') ) {
    $atts = shortcode_atts(array('id' => '', 'form_id' => ''), $atts);
    $entry_id = $atts['id'];
    $entry = FrmEntry::getOne($entry_id, true);
    if ( empty($atts['form_id']) ) {
      $atts['form_id'] = $entry->form_id;

    $form = FrmForm::getOne($atts['form_id']);
    global $frm_pay_form_settings;
    if ( empty($frm_pay_form_settings) ) {
        $frm_pay_form_settings = $form->options;
        if ( ( ! isset($form->options['paypal']) || empty($form->options['paypal']) ) && class_exists('FrmFormActionsHelper') ) {
            // get the 2.0 form action settings
            $action_control = FrmFormActionsHelper::get_action_for_form($form->id, 'paypal', 1);
            if ( ! $action_control ) {
            $frm_pay_form_settings = $action_control->post_content;
            $frm_pay_form_settings['paypal'] = 1;

    $amount_field = isset($frm_pay_form_settings['paypal_amount_field']) ? $frm_pay_form_settings['paypal_amount_field'] : '';
    $_POST['item_meta'][$amount_field] = $entry->metas[$amount_field]; // set the POST for the amount
    $amount = FrmPaymentsController::get_amount($form, $frm_pay_form_settings);
    if ( empty($amount) ) {

    global $wpdb;
    $invoice = $wpdb->get_var($wpdb->prepare('SELECT id FROM '. $wpdb->prefix .'frm_payments WHERE item_id=%d AND amount=%s AND paysys=%s', $entry_id, (float) $amount, 'paypal'));
    if ( ! $invoice ) {

    $frm_payment_settings = new FrmPaymentSettings();

    $paypal_url = '';
    $paypal_url .= '?cmd='. (( isset($frm_pay_form_settings['paypal_type']) && ! empty($frm_pay_form_settings['paypal_type']) ) ? $frm_pay_form_settings['paypal_type'] : '_xclick');
    $paypal_url .= '&notify_url='. FrmPaymentsHelper::format_for_url(admin_url('admin-ajax.php') . "?action=frm_payments_paypal_ipn");
    $paypal_url .= '&business='. FrmPaymentsHelper::format_for_url($frm_payment_settings->settings->business_email);
    $paypal_url .= '&currency_code='. FrmPaymentsHelper::format_for_url($frm_payment_settings->settings->currency);
    $paypal_url .= '&return='. FrmPaymentsHelper::format_for_url($frm_payment_settings->settings->return_url); 
    $paypal_url .= '&cancel_return='. FrmPaymentsHelper::format_for_url($frm_payment_settings->settings->cancel_url); 
    $paypal_url .= '&invoice='. FrmPaymentsHelper::format_for_url($invoice .'-'. FrmPaymentsHelper::get_rand(3));
    $paypal_url .= '&custom='. $entry_id.'|'. wp_hash($entry_id);
    $paypal_url .= '&amount='. urlencode($amount);
    if ( defined('ICL_LANGUAGE_CODE') ) {
      $paypal_url .= '&lc='. FrmPaymentsHelper::format_for_url(ICL_LANGUAGE_CODE);
    $item_name = apply_filters('frm_content', $frm_pay_form_settings['paypal_item_name'], $form, $entry_id);
    $paypal_url .= "&item_name=". urlencode($item_name);

    return '<a href="'. $paypal_url .'">Pay Now</a>';


Instant payment notifications

If Paypal is not notifying your site when a payment is complete, please go through each of the steps below.

  1. Double-check that instant payment notifications are enabled in your Paypal account.
  2. Check if you have a firewall plugin that may prevent Paypal from reaching your site. If you're not sure, visit while logged out. If you see a blank page, that's good.
  3. If your Paypal environment is set to "Testing", try switching to "Live". You can switch from Testing to Live in your Formidable Global Settings > Paypal.
  4. Check to see if you have any custom code on your site that could interfere. If you have custom code that uses the frm_payment_paypal_ipn hook or that modifies any entry values in the Paypal form, please remove the code and submit a new payment.
  5. Turn on the debug log. Go into Formidable Global Settings > Paypal and check the "Log results from IPN notifications" option. Hit Update. Then submit a new payment and open the debug log. Create a new ticket in our help desk and paste the log data in the ticket.
  6. If you see "IPN Response from Paypal Server: INVALID" in your debug log, please log into your PayPal account and review your IPN history page. Check if there are any notifications logged there and check their status. Report your findings in a new help desk ticket.