Creating a Payment Method

NOTE: We integrate with two separate API's for authorize.net, one that takes your credit card details on your own website and one that sends you to authorize.net to fill in your details.

Before you Begin

You'll need to create a directory named "core_commerce" in the models/ directory, at the root of your concrete5 install. Within this directory, create a "payment" directory, and within this, create a "methods" directory. From the root of your concrete5 install, the path to this directory should be

models/core_commerce/payment/methods/

This is your website's local payment methods directory, and will be referred to as such from within this tutorial.

Creating the Payment Method Directory

Before you can write code for your payment method, you will need to:

Choose a handle for your payment method. This is a short name that will match the directory that your payment method resides in. This should be descriptive, but be all lowercase and contain no spaces. For example, the handle of our Paypal Website Payments Standard payment method is "paypal_website_payments_standard."

Create a directory with the same name as your payment method's handle in the local payment methods directory (referenced above.)

The Components of a Payment Method

There are several items that comprise a payment method. Some are required. These are all files that exist within the directory you created for your specific payment method.

The controller file, named "controller.php" This file is required. It should contain one PHP class. Like blocks or other items in concrete5, the controller class must be named appropriately. It must begin with "CoreCommerce", then contain the camel-cased name of the payment method, and finish ith "Payment MethodController." If your payment method is named "my_website", your class would be CoreCommerceMyWebsitePaymentMethodController. The class must extend the CoreCommercePaymentController class.

The checkout form for this payment method. This is named "form.php" and is displayed to the user after they have chosen this payment method for checkout (or, in the case that this is the only payment method available, when the user has entered their shipping information.) This file is required.

The additional details form for this payment method. If it exists, it is named "method_form.php" This is displayed to site administrators when they wish to enable or disable the payment method, if the payment method requires additional information. This form is optional.

Rather than go through these one by one, it's easiest to look at how all three components interact, by going through two examples of payment gateways that come with the eCommerce addon.

Example: The Default Payment Gateway

The default payment gateway is simply a way to checkout easily through your concrete5 eCommerce installation. It does not send any information to any third parties or validate a payment request in any way.

When configuring the default gateway through the dashboard, you'll see the contents of the additional details form, which are simply some concrete5 configuration form elements with names like "PAYMENT_METHOD_DEFAULT_EMAIL_RECEIPT" and "PAYMENT_METHOD_DEFAULT_TRANSACTION_TYPE". You won't see any form tags or submit buttons in the additional details form, however, because this is handled autmomatically by concrete5, by a method in the controller file.

The checkout form for the default gateway is even simpler. It simply contains text that indicates that submitting the form will complete the order (note: older versions of the eCommerce addon might be slightly more complicated than this, with a reference to a $fields variable, but this is cruft and is unnecessary.)

Finally, the controller file for the default gateway contains several methods.

method_form()

This method is automatically run when additional details form is displayed in the dashboard. These lines of code simply retrieve the two bits of data we're saving with this method form.

validate()

This is automatically run when the additional details form is submitted. If you need any specific errors to return when users are configuring your payment method through the dashboard, use the concrete5 validation error handler here. If you return an error object that has errors (e.g. you have added at least one error using ValidationErrorHelper::add()) the save will fail.

save()

This method is run when the additional details form successfully passes the validate task. This method in the default gateway simply saves the two parameters that the default gateway uses.

form()

This method is automatically run when the checkout form field is rendered. In the default gateway you'll see that we're using this method to override the submit action in the checkout form. Instead, we're changing the checkout method to run the submit action, which means when the form is posted back, it will run the action_submit() method in the payment method.

Additional Action Parameters

Any methods within a payment method that begin with action_ are special methods used by the gateway. These are typically called from within a front-end view using the $this->action('method_name').

Finishing a Transaction

There are two actions every payment method must perform after it has verified a payment transaction:

Set the order status to one of the status values defined in the CoreCommerceOrder class (packages/core_commerce/models/order/model.php). Usually this will either be STATUS_PENDING or STATUS_AUTHORIZED. Set it to STATUS_PENDING if the payment was authorized by the gateway but not captured, and STATUS_AUTHORIZED if it was captured (yes, the terminology is a little different).

Call the CoreCommercePaymentController::finishOrder() (packages/core_commerce/libraries/payment/controller.php) method. CoreCommercePaymentController is the parent class for all payment methods. This function initiates the work that needs to be performed for every order once the payment has been verified, regardless of the payment method used. This includes sending certain emails, adding users to groups (when applicable), etc. Examples of this method in use should be available in every payment method that ships with the eCommerce addon.

Further Examples

Once you understand how the default payment gateway works, it will be useful to check out something like the Paypal Website Payments Standard gateway, and then the Authorize.net AIM gateway. These will give you an idea about how to validate real credit card transactions, send users to third party payment providers, and integrate with real gateways.

Install and Activate the Payment Method on your Site

Finally, when your payment method is written and the various files present within the directory are completed (or at the very least ready to be tested) you'll need to install your payment method to make the eCommerce addon aware of it. Head to Dashboard > eCommerce > Payments. Within the "Custom Payment Methods" section of the page, you should see your new gateway listed. Click install. Then click the "Edit" button next to your gateway, and enable your gateway to test it on youyr site.

Converting the payment into a package

If you'd like to offer the payment gateway to someone else, or on the concrete5 marketplace, you'll need to package it up. You can read more about the package format in the concrete5 developer documentation. To package up your payment method, simply create a package (complete with a controller script and an icon.png graphic), then create a models/ directory within the package. Within this directory create a "core_commerce" directory. Then create a "payment" and then a "methods" directory beneath this directory. Finally, move your payment method directory (which contains the PHP files) into this directory.

This will install the payment method when the package is installed (but it will not enable it by default.)

Other Tips

The Authorize.Net Advanced Integration Method (AIM) payment method is a good example to look at if you want to build a payment method that handles all of the payment processing on the Concrete5 site without redirecting to a gateway.

The core payment methods do not use all of the product and order data that is available. Take a look at the finishOrder function method mentioned above to see some of the other information that is available.