Allowing Gateway Webhooks or IPN Data into a Protected Site (for testing or development)

Many development and staging sites want to restrict total access to the site’s folder on the webserver. One of the easiest ways to do this is by setting a UNIX password at the server level.

This advanced developer recipe shows you how to set up custom .htaccess rules to allow your Webhook or IPN data through this security measure. This will allow you to properly configure and test payment gateways in Paid Memberships Pro.

About the Recipe

If your site has a UNIX password or is in Coming Soon/Maintenance Mode, your gateway will not be able to get to your site and send their data.

The recipe below will allow any of the listed IP addresses access to your website and will prompt everyone else to enter your secret UNIX username and password.

Note that this recipe specifically allows the IP addresses of the PayPal IPN Live Server and the Stripe Webhook. If you are using another gateway or using PayPal in Sandbox mode you will need a separate list of IP addresses. Please consult your payment gateway documentation to locate their active IP addresses.

This recipe will only work with sites restricted by a UNIX password. If you are using a Coming Soon plugin, you’ll need to take another approach to allow gateway access to your site (the easiest method is to disable the maintenance mode while running your tests). We’ll try to put together a similar recipe for popular plugins with this feature, or you can open topic in the members-only support forum for personal help.

The Code Recipe

This code recipe requires a Plus Account or higher.

View Membership Options

Using Page Builders to Enhance Your Site’s Membership Pages

Page builders are a popular way to create a more visually appealing user experience on your site. Many Paid Memberships Pro users are confused with how to properly use these tools alongside the required shortcodes on various pages of your membership site, such as the pricing page or membership account page.

This post covers how to resolve conflicts between plugin shortcodes and popular page builders such as SiteOrigin Page Builder, Elementor and Beaver Builder.

Ensuring Compatibility

Below are a list of common issues we see when trying to use Paid Memberships Pro with a page builder.

  1. Required page shortcodes don’t render.

    The main issue that we see related to Page Builders is that default page shortcodes, such as [pmpro_levels] or [pmpro_account], don’t render. You’ll know you are experiencing this issue if you go through the Initial Plugin Setup, then click to view your “Membership Pricing” page and see something like this:

    Not all of the Paid Memberships Pro shortcodes will render as actual content when using a live editing experience. I have seen different behavior among all of the builders I tested. The best way to ensure the page is loading properly is to save and publish your content then view the page on the frontend.

    If the shortcode still isn’t rendering, make sure you are using your builder’s standard text or shortcode widget/component/block for the page’s required shortcode. I have seen cases where the builder places your page’s shortcode in a special block type that will not render shortcodes. Here’s a list of all required shortcodes for your Membership pages.

  2. “Live Editors” don’t load or redirect to the “Membership Levels” page.

    This issue is present if you try to edit a page like the “Membership Account” page in a “Live Editor” experience, but the editor redirects you to the Membership Levels page. To resolve this, you must make sure that your administrator account has a membership level. This is due to a conflict where the builder is trying to offer a “preview” of the page, while our membership plugin is trying to restrict your access to these members-only pages. Having a membership level on your administrator account (even you create a hidden, private level that only your Admin account has) resolves this.

  3. Members-only content isn’t protected.

    Because Page Builders rely heavily on their own logic to render page layouts, sometimes the builder’s content filters run later than the Paid Memberships Pro filter. This can result in protected content being public. The solution to this issue has been covered previously in this article, which outlines how to run the Paid Memberships Pro content filters with a higher priority (after the builder has done its content-formatting magic).

    Alternately, you can use this method to redirect non-members away from members-only content. This completely bypasses the need to filter members-only content and is the most straightforward approach to tackling this issue.

  4. “Live Editor” on the checkout page doesn’t load.

    The Membership Checkout page relies on a level ID being passed through the URL (usually from the Membership Levels page) in order to display the appropriate level details at checkout. When using a live preview or editor experience, there is no level ID passed in the URL so the page either fails to load or redirects to the Membership Levels page. You can resolve this by adding a Custom Field with the key or name pmpro_default_level and value of any valid level ID. This allows the “Live Editor” to locate a level for the preview page. Now your Membership Checkout page’s live editor can draw in some level’s content and allow the preview.

  5. I don’t see the “Restrict Membership” box on the editor.

    If your page builder uses a live editing format, chances are that the “Restrict Membership” metabox is not part of this editing experience. After you have made your page design and content changes via your builder’s editor, you will need to also edit the post with the WordPress editor and select the appropriate membership levels to restrict access. Read this guide for more help on restricting content using Paid Memberships Pro.

All of the above issues have a solution, so please don’t panic. We are looking for ways to build support into our plugin for popular open source page builders. For now, we’ve tested Paid Memberships Pro compatibility with the list of Page Builders below. These were tested on a fresh WordPress site with only the core Paid Memberships Pro plugin, the Twenty Sixteen WordPress Theme and using only that specific Page Builder. If you are using another open source page builder, please post a comment below and we will test which combination of solutions are needed to make the two plugins compatible.

Page Builder by SiteOrigin

Page Builder Info: WordPress Repository | Widgets Bundle | Website

This builder is one of the most popular open source builders available via the Repository. In my testing, I have found that you need to modify a few of the ways our core plugin renders content in order to ensure compatibility with SiteOrigin’s builder. The code recipe below should be included in a plugin for PMPro Customizations.

In this recipe, we are removing some content filters we add to your site’s level descriptions and confirmation messages, as they were causing issues when the builder attempted to render the membership checkout and confirmation page shortcodes.

When editing the Membership Checkout page, you must set a Custom Field on the Membership Checkout page with the key pmpro_default_level and value of any valid level ID. This allows the “Live Editor” to locate a level for the preview page.

You must also make sure that your administrator account has a membership level in order to use the “Live Editor” experience. This is due to the fact that the Page Builder by SiteOrigin editor is trying to offer you a “preview” of the page, while our membership plugin is trying to restrict your access to these members-only pages. Having a membership level on your administrator account (even you create a hidden, private level that only your Admin account has) resolves this.


Page Builder Info: WordPress Repository | Website

This builder is gaining popularity very quickly and its easy to see why. Because Elementor is a drag & drop live editor, there are some special considerations you need to make specifically when attempting to use the builder to edit your Membership Checkout page. When editing the Membership Checkout page, you must set a Custom Field on the Membership Checkout page with the key pmpro_default_level and value of any valid level ID. This allows the live preview editor to locate a level for the preview page. This step must be done before you convert to editing the page with the live preview.

You must also make sure that your administrator account has a membership level in order to use the “Edit with Elementor” experience. This is due to the fact that the Elementor editor is trying to offer you a “preview” of the page, while our membership plugin is trying to restrict your access to these members-only pages. Having a membership level on your administrator account (even you create a hidden, private level that only your Admin account has) resolves this.

You must also add a custom code recipe that filters your content later as well as removes the default content filters our plugin uses on your site’s level description and confirmation messages. The code recipe below should be included in a plugin for PMPro Customizations.

Beaver Builder

Page Builder Info: WordPress Repository | Website

Beaver Builder offers a live editing experience for WordPress and premium versions offer pre-built templates and layouts which make it simple to design well thought out content. In my testing it was one of the most intuitive builders in this list. There are a few steps to take to ensure compatibility with Beaver Builder. The code recipe below should be included in a plugin for PMPro Customizations.

When editing the Membership Checkout page, you must first set a Custom Field with the key pmpro_default_level and value of any valid level ID. This step must be done before you convert to editing the page with Beaver Builder. This allows the live preview editor to locate a level for the preview page.

You must also make sure that your administrator account has a membership level in order to use the live editor experience. This is due to the fact that the Beaver Builder editor is trying to offer you a “preview” of the page, while our membership plugin is trying to restrict your access to these members-only pages. Having a membership level on your administrator account (even you create a hidden, private level that only your Admin account has) resolves this.

You must also add a custom code recipe that filters your content later. This allows Beaver Builder to process all the layout-related filters on your content, then allows Paid Memberships Pro to apply appropriate membership restrictions. The code recipe below should be included in a plugin for PMPro Customizations.

More about Page Builder Compatibility

I have also seen some funny behavior specifically if you had generated the PMPro pages prior to activating the Page Builder. If your builder isn’t playing nicely with our shortcodes, try to open the page in the builder’s editor then save the page. For some reason this occasionally resolves the issue and then your shortcode will render.

  1. Edit each Page under Memberships > Page Settings.
  2. Swap to your builder’s rich page editing experience.
  3. Make sure the appropriate page’s shortcode is in the editor.
  4. Save the page.

Using another Page Builder?

If we didn’t cover the builder you are using or if you have Page Builder-like features as part of your theme, post a comment below and we will try to test it and work out a solution. We are only able to offer compatibility testing if the builder you are using is also open source, like Paid Memberships Pro and the page builders mentioned in this post.

Recent updates to the Theme My Login plugin and how they will affect your membership site.

We have long recommended Theme My Login as a very useful plugin for sites running Paid Memberships Pro. With features including themed login, frontend user profiles, and simple redirection rules, we found TML to be a great addition for any membership site. We recommended it to 100% of our users and included it in our WordPress bundle.

With the release of version 7.0+ of Theme My Login, several key features that were once included in the repository version of the plugin are now offered as premium extensions. This post details some short and long term options for membership site owners concerned about the changes and the best steps to take.

Themed login pages are still part of the free plugin.

If you were only using Theme My Login to show your login form on the frontend of your website and not using any of the “modules” that came with the plugin, then you are fine and can continue to use Theme My Login as you were before. Make sure that you are upgraded to the latest version of Paid Memberships Pro as well, which included a fix so PMPro will still redirect the registration page to the PMPro levels page and handle login redirects properly.

If you can afford it, purchase the Theme My Login extensions bundle after upgrading.

Theme My Login is a solid plugin maintained by a great developer, Jeff Farthing. Support Jeff and your site by purchasing the premium extensions you need.

Currently you can purchase extensions a la carte for $10 each or a bundle of all 6 legacy extensions for $49.99. Jeff has kindly given us a discount code to share with our members to receive 20% off any extension purchase, including the bundle. Just type in “PMPRO” on the checkout page to apply the 20% discount. This code will work through the end of July 2018.

You can purchase the Theme My Login extensions here.

After upgrading you may have to redo some settings.

We purchased the bundle ourselves and were able to get our themed login and profile pages back online in a few minutes. We did have to redo a few of the settings though. Here are a few notes we took during the upgrade that might help:

  1. When we installed the Redirections extension, all of our redirection rules all migrated properly upon upgrade.
  2. When we installed the Themed Profiles extension, our settings were reset to the default. We typically recommend checking the box to theme profiles for the Subscriber role and checking the box to keep Subscribers out of the dashboard.
  3. The default Login, Register, Password Reset, and Profile pages are no longer editable as pages. However, we were able to take our “your-profile” page, keep the [theme-my-login] shortcode on the page, and then change the slug in the main TML settings to “your-profile”. Now the profile page has the template, sidebar, and other settings we want for that page.

The PMPro Member Homepages add on is a good substitute for the TML login redirect module.

One of the TML modules allowed you to select a different page to be redirected to after logging in based on the user’s role. This way you could have subscribers redirected to one page and admins redirected to another.

If you don’t need to redirect users based on roles, you can redirect them based on their membership level instead using our Member Homepages add on.

In the short term, you can keep using version 6.4 of TML

While its always smart to keep your WordPress plugins up to date for security considerations, in the short term you can keep version 6.4 of TML active. The plugin won’t allow you to update in the WP dashboard unless you read the notice on the settings page and change a setting to approve the upgrade to version 7.0.

Version 6.4 TML is likely to work for a while until a core update to WordPress changes something about the login system that breaks it. We highly recommend upgrading to TML 7.0+ as soon as possible, but you have some time to figure things out.

Improving Paid Memberships Pro with Added Profile Features

The new business model for Theme My Login is a good move for Jeff and will help him to build a business around the plugin that will ensure the plugin continues to be maintained and supported. We like plugins that do their one thing really well, and we’ve been happy with Theme My Login over the years. I’d rather not use our limited development time to build functionality covered by other competent plugins. On the other hand, the cost of the extensions are going to keep some PMPro users from installing Theme My Login. This factors into our decisions around what features we build into the core PMPro plugin, build into our Add Ons, or reserve for third party plugins.

In the long term, we are looking into moving the themed login and profile page features into the core PMPro plugin or possibly an Add On of our own. We are in the early stages of discussion and will start from first principles to figure out what kind of solution will be best for our users.

In the short term, you can purchase the extensions you need using the PMPro discount code, use some of the workarounds mentioned in this post, or continue to use TML 6.4 until a core WordPress update breaks the plugin.

How to enable debugging on your WordPress site.

Enable Debugging on Your WordPress SiteIs your site no longer working? Has your WordPress site been replaced with a blank white screen, the infamous White Screen of Death? Maybe you are experiencing styling issues, your footer is not loading correctly, or you are having a tough time checking out of your site. This is not unique to Paid Memberships Pro and can occur on any website, using any theme or any plugin(s). Knowing what is causing the problem can give you or a developer the relevant information needed to help fix these issues.

Whatever the reason, this article will explain how to enable debugging mode in WordPress to uncover any PHP errors or warning messages that are on your site.

Turning WP_DEBUG Mode on.

WP_DEBUG is a PHP constant (a permanent global variable) that can be used to trigger the “debug” mode throughout WordPress. It is assumed to be false by default and is usually set to true in the wp-config.php file on development copies of WordPress.”  WP DEBUG, WordPress Codex

  1. Before getting started you will need to be able to access your WordPress site files by means of an FTP Client or your website’s control panel.
  2. To turn WP_Debug mode on, navigate to your wp-config.php file (found in your WordPress install directory), edit the file using a text editor of your choice. Once the file is open, search for the following line of code define( 'WP_DEBUG', false ); and change the value from false to true. If you do not find the WP_DEBUG line of code in your wp-config.php file, you can simply add it toward the bottom of the file. It is usually placed below the table prefix, but certainly above the /* That's all, stop editing! Happy blogging. */ line.

With WP_DEBUG turned on, errors will be displayed right on your homepage, so your site may appear broken (or more broken). Copy the entire error message down to share with the support team or developer working on your site.

Fatal Error Example

To hide the errors again, change WP_DEBUG mode back to false. It is often acceptable to turn on WP_DEBUG, navigate to your site and copy the error, and finally navigate back to your wp-config.php file and turn off WP_DEBUG. When dealing with a live site, any visitors who were browsing your site would be interrupted by the error/message notification. It’s important to hide those errors again as quickly as possible or use the instructions below to send the errors to a log file that only you can see.

Turning off errors that would otherwise display on-screen.

By default, WP_DEBUG will display all errors and notification to your screen. This is not ideal in many cases as the notification/errors will replace the actual webpages of your site with the error messages. To stop errors and messages from displaying on your screen, you can add the following line of code to your wp-config.php file, just under the WP_DEBUG line: define( 'WP_DEBUG_DISPLAY', false )

With this constant set to false, errors are not displayed on screen but are still saved to your web server’s PHP error log. You can set a specific error log for WordPress errors using the steps below.

Making a Debug log file.

Along with WP_DEBUG, you can use WP_DEBUG_LOG , this will save all errors and notifications to a debug.log file that you can use as a reference of any errors/php notifications. You can also use this file to send to any developer or support engineer who is working on your site. In the event that there were no errors found, a debug.log file will not be created.

Simply add the following line of code to your wp-config.php file under the other WP_DEBUG constants: define( 'WP_DEBUG_LOG', true )

Accessing the Debug.log File

Once you have added the define( 'WP_DEBUG_DISPLAY', false ) line of code to your wp-config.php file , you will find the debug.log by navigating to your wp-content folder found in the WordPress install directory. You will need to access this part of your website by using a FTP client or through your websites control manager.

Important: Once done with your debug.log file, disable WP_DEBUG mode and delete the debug.log file from your site immediately. Not doing so may result in compromising the security of your site or exposing sensitive information to unwanted parties.


What it looks like all together.

Now that you have added all the lines of code to your wp-config.php file, you should have something similar to the below coding example:

WordPress Debugging – Summarized

  1. Login to your site via FTP or your host’s File Manager.
  2. Navigate to your WordPress install directory and enter it (usually public_html or www).
  3. Find the wp-config.php file and edit with a text editor of your choice. Some popular text editors to use are: Atom, Sublime 3 and PHPStorm
  4. Search the file for the following line of code: define( ‘WP_DEBUG’, false );
  5. Change this value from false to true. This will now output errors to your site by displaying them right on your homepage, so instead of your site you will see any underlying errors. To get your website back, change WP_DEBUG mode back to false.
  6. Directly below this you can enter two new lines of code to send errors to a log file:
    • define( ‘WP_DEBUG_DISPLAY’, false );
    • define( ‘WP_DEBUG_LOG’, true );
  7. Save your file and re-upload to the same directory – overwrite the file when prompted. (Do not close your FTP client just yet).
  8. Go back to your website using your browser and recreate the issue.
  9. Head back on over to your FTP client and navigate to wp-content and expand the folder, your debug.log file will be loaded into this directory if there are any PHP errors.
  10. Download the debug.log file. Feel free to send this log file onto your support engineer.
  11. For a more detailed guide on debugging in WordPress, have look at the WordPress codex.

This looks tough – I need help.

If you are uncomfortable editing your wp-config.php file or are otherwise having trouble following these instructions, reach out to your hosting company for help. You can ask them the following in a support ticket or through email:

Can you tell me how to find the PHP error log for my website at and send me a list of the last 20 errors that have occurred?

Exactly how to access error logs varies depending on your host and server setup. Any good host should be able to respond to request above.

If you would like our help fixing a PMPro-related error on your site, we have a team of Support Engineers that are equipped to help you with your debugging questions. Feel free to get in touch with our team over on our Members Support Forum.

Access to Member Support Forums requires a PMPro Plus Account or higher.

View Membership Options

Setting up a Developer Account to Test Your Payment Gateway

Using Paid Memberships Pro in your selected payment gateway’s “testing/sandbox” mode allows you to test membership checkout without processing real payments. Sandbox mode requires unique credentials that vary based on the active payment gateway.

This post covers how to set up your test or sandbox account so that you can run tests on a membership checkout.

Testing your Payment Gateway.

Technically, all you need to do to start accepting payments on your site is sign up for a payment gateway and paste the appropriate API information into the Memberships > Payment Settings page in the WordPress admin of your site.

However, taking some time out to test your payment gateway first will not only give you peace of mind that the gateway is properly set up and ready to start receiving payments but it also gives you a good idea of how the gateway works and whether or not this gateway will be right for you and your members.

Setup Example: Stripe

Setting up a Stripe testing account is really quite simple. All you need to do is navigate to the Stripe Registration page, fill in the appropriate fields and click on the “Create your Stripe Account”.

Once your account is set up , you will be redirected to your Stripe Dashboard and an email will be sent to you asking you to verify your email address. Your Stripe testing account is now set up and you are (almost) ready to start testing it out on your website.

Note – in order to start using this account to accept actual payments, you will need to “Activate your account” from within the Stripe Dashboard.

Adding the test API keys to your website.

To add the relevant Stripe API keys to your website, you will need to navigate to the “API” tab in your Stripe Dashboard and copy both the “Publishable” and “Secret” API key and paste them into your Paid Memberships Pro payment gateway settings. This can be found by navigating to your WordPress Dashboard > Memberships > Payment Settings.

Note: Remember to set the payment gateway in your payment settings to Stripe and your “Gateway Environment” to “Sandbox/Testing”.

Once you have added your API keys, save your settings.

Processing a test checkout.

It is now time to do a test checkout. Log out of your website completely and proceed to purchase a membership level just as one of your potential customers would. You should eventually be redirected to your checkout page.

Fill out the checkout form as a normal user would and when you get to the “Payment Information” section, you will need to input a Stripe Testing Card number in order to process the test payment. If you do not use a Stripe testing card, you will receive a “Your card number is incorrect” error message.

Back to the Stripe Dashboard.

Once you have successfully processed the membership checkout, you will be able to navigate back to your Stripe Dashboard and see the test data as if it was an actual user who checked out of your site. Feel free to browse through the different menu options to get an overall feel for how this payment gateway works. The more you explore the gateway’s capabilities and limitations, the better idea you will have of whether or not a payment gateway will work for you.

Time to go live.

When you have done enough testing and you are now ready change over to a live environment, make sure that you change your “Gateway Environment” to “Live/Production” and complete the fields with your gateway’s appropriate information.

If you have not yet activated your Stripe account, you will need to do this before you can get your “Live” API keys. Live payments cannot be processed if your integration is still using your test API keys. Once you paste in your live API keys, save your changes.

Some useful links to get you started.

On Time Zones and Off By One Day Errors

Some sites report “off by one day” errors when calculating end dates on new orders and memberships. What this looks like on the front end is setting someone’s end date to January 31, 2017 and then having it show up as January 30, 2017. Or expiration is set to happen at 12:00am, but it happens at 10:00pm instead.

This post covers some common reasons why this is happening and a collection of ways to set the various time stamp settings in your web stack.

What’s really going on?

In most cases, “off by one day” errors occur when your web server, database server, and/or WordPress install are disagreeing about which timezone to use for calculating dates.

Getting everyone to “agree” on the time zone varies depending on your setup, specifically if you are on shared hosting and have limited access to your server. In this case you may not be able to configure the time zone for one or more of the services listed below. That being said, making some or all of the suggested updates can help to resolve these time zone errors.

Settings In WordPress

To change the timezone in WordPress go to Settings –> General in the admin dashboard. You can also set the date format here, which is used by PMPro when displaying dates.

Settings In CentOS/Linux

Here is an article explaining how to change your timezone in CentOS. Use the correct timezone file (browse around the /usr/share/zoneinfo directory), but generally you should run these two commands when logged in as root. (Note: don’t copy the #)

# mv /etc/localtime /etc/localtime.bak
# ln -s /usr/share/zoneinfo/America/New_York /etc/localtime

Settings In Apache/PHP

Typically you need to add or edit a line in your php.ini document. Here is a list of timezones at

date.timezone = “America/New_York”

Settings In MySQL

Log into MySQL as root and run this query: (More information on time zones in MySQL.)

SET time_zone = ‘America/New_York’;


Making sure that all of these settings are in sync will usually fix any “off by one day” errors going forward. Some issues will be fixed immediately after changing these settings. Other issues will still happen since the timestamps in the database were set when time zones were out of sync. You’ll have to run queries in your database to update time/date fields after your time zones have been set correctly.

Some hosts or server setups will have different methods for changing the time zones as above. Searching the knowledge base of your host or opening a support ticket there may help. If you find a new solution related to above, feel free to comment and we’ll try to expand on the information here to cover as many scenarios as we can.

If you are still having issues related to dates and time stamps, please post to our member forums and we can help you fix things for your specific setup.

Configuring WordPress to Always Use HTTPS/SSL

SSL encryption adds a layer of security to your website that makes it harder for malicious actors to collect personal information submitted through forms on your website.

This post will walk you through obtaining an SSL certificate (Let’s Encrypt or Other Providers), installing it on your web server (Let’s Encrypt or Other Providers), setting up your WordPress site to use HTTPS URLs, and fixing any “mixed content” type errors that come up when a page served over HTTPS links to non-HTTPS content.

Yes, you should use an SSL.

Setting your site up with an SSL certificate to serve pages over HTTPS doesn’t make you 100% secure against all of the kinds of attacks that can befall a website, but it should be done on nearly every site using Paid Memberships Pro.

The use of an SSL certificate is required by the PCI Security Standards Council on any site accepting credit cards [more] and is required by most gateways even if the checkout is completed “offsite”.

Starting this year, search engines like Google will begin to penalize the search rankings of sites without SSL certificates and web browsers like Chrome will start to show more severe warnings on pages with password or credit card fields if an SSL certificate is not active.

Step 0. Backup Everything

Before you get started, perform a full backup of your website. The steps outlined in this tutorial touch on your WordPress files, database, and even your server configuration. So be sure to back up your website at all levels: files, database, and server configuration.

More About Site Backups

Step 1. Get an SSL Certificate

Quick Note: When we refer to “SSL Certificates” in this post, we mean specifically a “third-party” SSL certificate. These are certificates that are validated by a trusted third party. You can also use what are called “self-signed” SSL certificates or “shared” SSL certificates, but only a third-party SSL certificate will avoid all browser warnings and fulfill all SSL-related gateway/PCI requirements.

The easiest way to get an SSL Certificate purchased and installed is to ask your web host to do it for you.

The details and cost of this are different for each host, but they will know exactly how to get your site served over HTTPS with a proper SSL certificate. Again, ignore “shared” or “self-signed” SSL options and make sure that you obtain a full trusted third-party SSL certificate.

If you manage your own server or otherwise want to do it yourself, you have a couple of options.

1a. Generate a Let’s Encrypt SSL Certificate

In 2016, a new (and free) way to obtain “third party” SSL certificates was introduced called Let’s Encrypt. From the Let’s Encrypt about page:

Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit. It is a service provided by the Internet Security Research Group (ISRG).

We give people the digital certificates they need in order to enable HTTPS (SSL/TLS) for websites, for free, in the most user-friendly way we can. We do this because we want to create a more secure and privacy-respecting Web.

Many web hosts are starting to offer Let’s Encrypt SSL certificates for free or at a reduced cost. If your host supports Let’s Encrypt, ask if they will set up the certificate for you. If your host won’t set it up, but you have SSH access to your web server (typical of dedicated or VPS-level hosting plans), you can generate the certificate yourself and setup your web server to use it.

The easiest way to generate and manage Let’s Encrypt SSL certificates is through a command line tool called Certbot.

The Certbot homepage allows you to choose your web server software (e.g. Apache) and your server’s operating system (e.g. Ubuntu Linux) and will give you instructions for using Certbot to setup a Let’s Encrypt SSL. Here are some instructions for using Certbot with Apache on Ubuntu 16.10:

  1. Make sure that your web server is setup with SSL support. For Apache, the module is called mod_ssl. On recent versions of Ubuntu, you can enable this by typing the following into your command line: (restart Apache when finished)
    $ sudo a2enmod ssl

    If this doesn’t work, you’ll want to talk with your host or search their docs for “enabling mod_ssl for Apache”.

  2. Second, use apt-get to install Certbot:
    $ sudo apt-get install python-certbot-apache
  3. Third, generate the certificate. (In my experience, Certbot has often failed to configure Apache properly after generating the certificate. So I’ve only used it with the “certonly” option. If you are confident, you can try without that option and it try to automatically update your Apache configuration to use the new certificate.)
    $ certbot --apache certonly

    Your terminal should then look something like this:

    Don’t be alarmed by the border of random letters (I was the first time!). It’s just an ASCII representation of a bounding box. Cerbot tries to detect what domains are setup on your server. If you see your domain, use the arrows keys to highlight it and hit enter to check it, then follow the instructions. If you don’t see the domain you want a certificate for, you can specify the domain in the Certbot command:

    $ certbot --apache certonly --domains

    When Certbot is finished, it will generate a cert.pem and privkey.pem file, typically at the following locations:

    • /etc/letsencrypt/live/
    • /etc/letsencrypt/live/
  4. Fourth, you need to update your Apache configuration to use the new certificate. The exact steps for this will depend on your Apache setup, but you may have an /etc/httpd/conf.d/vhost-ssl.conf file that looks like this or similar code in another Apache config file: (Note the SSLCertificateFile and SSLCertificateKeyFile lines.)

    This is a fairly typical Apache setup. This configuration says to detect traffic coming in via port 443 for the host and redirects that traffic to the …/httpdocs/ folder. This is the same folder as for port 80/regular HTTP traffic. Sometimes your site may be setup to use a different directory for HTTPS traffic. If so, you can have that directory “sym linked” to the regular directory or update your settings per the above. With WordPress, it’s best to serve both HTTP and HTTPS traffic from the same directory.

Now restart Apache to have the new settings go live. It’s a good idea to have backups of your Apache configuration files in case something goes wrong. Then you can switch your files back to the backups and restart Apache to have your site fixed ASAP. Find the error in the Apache (or other web server) error logs and see what might be wrong.

Let’s Encrypt SSL certificates only last 90 days.

To simplify the renewal process, you will want to setup a cron job to renew the certificate regularly. The command to do that is:

$ certbot renew --quiet

You can test it like this:

$ certbot renew --dry-run

And the cron job line to run this daily at 4:17am might look like this:

17 4 * * * certbot renew --quiet --post-hook "systemctl reload httpd"

1b. Purchase an SSL Certificate

If you don’t have SSH access to your web server, but do have a way to install SSL certificates (e.g. through a control panel), then you can purchase an SSL certificate from a “certificate authority” for use on your site. You may also want to purchase from a certificate authority if you want a Wildcard SSL, SAN SSL or other advanced SSL.

You will sometimes need to generate a Certificate Signing Request (CSR). You will have to validate that you control the domain through a standard email address like, an update to the site’s homepage, or a special DNS update. Once purchased and validated, you will be given one or more certificate files to install the SSL certificate. How you exactly install that certificate again depends on your host and/or your control panel software. Most control panels have easy to follow instructions for how to do so.

Here are some place where you can purchase and download SSL certificates:

  • SSL For Free (Uses Let’s Encrypt. Free but must be manually renewed every 90 days.)
  • GoDaddy (Expensive, but lots of options. Affiliate link.)
  • RapidSSL
  • AlphaSSL (Sign up for a reseller account for discounts if you plan to purchase many certificates for clients/etc.


Step 2. Tell WordPress Your Site URL is HTTPS://…

Once you have your SSL certificate installed on your web server, you can test it by going to https:// followed by your website URL.

If you get an error message, then your Apache configuration is probably incorrect. Make sure that you have mod_ssl installed, a valid SSL certificate, and the Apache VHOST configuration setup properly. See the notes above and check with your host.

When you visit the https:// URL of your site, you may be redirected to the http:// version of that URL. There are many systems that will try to force a website to use a certain “scheme” (HTTP or HTTPS). For example, if the “Force SSL” option in Paid Memberships Pro is turned on it will actually redirect away from the HTTPS version of a page for non-checkout pages. Other plugins may do similar redirects. And WordPress itself will sometimes try to force a “canonical” redirect to make sure that each page on your website has exactly one URL (this is good for SEO).

If you are using the Force SSL redirect option of PMPro or other plugins like WooCommerce, disable those features as they may interfere with your global SSL settings. When your full site is served over SSL, you won’t need them.

To get everything in WordPress to load over HTTPS is actually fairly straight forward. You simply navigate to the Settings -> General page in your admin, and then change both the “WordPress Address URL” and “Site Address URL” to have an https:// in front instead of an http://.

Important Note: After making this change, many things will happen. Many things may break. For starters, you will be logged out. This is because the cookie created when you login is usually specific to the HTTP or HTTPS “version” of your page. After WordPress is updated to use the HTTPS URL, you will have to login again to generate a new authentication cookie.

Many other things can break once your site is updated to server over HTTPS. Step 3 goes over the most common ones we’ve run into.

Step 3. Fix Everything That Broke

Here we’ll try to document some of the most common things that can break on a site that is being served over HTTPS.

Users can still access the http:// version of the site.

If your site is setup to serve all pages over HTTPS, you will need to redirect http:// URLs to https://. There are a few ways to do this, but we recommend adding a rule through your web server.

If you are using Apache, you can add this snippet to redirect any http traffic to the https version of the URL. Make sure to place this under your Rewrite Engine On and Rewrite Base lines:

If you are using the NGINX web server, here is the configuration you can use to redirect all HTTP traffic to HTTPS across all hosts. See Bjørn Johansen’s blog post on this topic for more details.

Pages timeout with “too many redirects” errors.

If you get a too many redirects error, what’s happening is some code somewhere is telling the browser to redirect to the HTTP version of the page. Then some other code is telling the browser to redirect to the HTTPS version of the page. What you need to do is figure out what code is trying to redirect to the HTTP version and then disable that.

  • Bad Plugin Settings

    We’ve already mentioned that you should disable the “Force SSL” option on the payment settings page of PMPro if your site is fully served over HTTPS, and PMPro should detect this anyway. Other ecommerce plugins or login/redirect plugins may have similar features that need to be disabled.

  • Bad PHP Server Values

    Another common issue is that some hosts or proxies (like Cloudflare or Sucuri CloudProxy) can sometimes make your traffic appear to be coming over HTTP instead of HTTPS. It’s pretty subtle, but basically WordPress has a function is_ssl() that checks if the PHP value $_SERVER[‘HTTPS’] is set to “on”. When using a proxy, this value might be set to “off” or not set at all.

    Here is some code you can add to your wp-config.php temporarily to test the $_SERVER values to see if they are setup correctly. Add this code to wp-condig.php and then navigate to https://

    The output should be something like this:

    Note the HTTPS value. If you are loading an HTTPS URL, but this value is set to “off”, “false”, or blank. Look for another value indicating the scheme being used. Many proxies will set the HTTP_X_FORWARDED_PROTO value and you add this code to your wp-config.php to copy that value into the HTTPS

  • Bad Plugin Code

    If you can’t even get into the admin to change this feature, you can disable plugins one by one by renaming the folders on the server to plugin-name-o or something similar. This will hide it from WP and that plugin won’t be loaded. If disabling a plugin fixes the issue, then you know that plugin is (at least partly) to blame for the redirect. You can read more about how to disable all plugins when locked out of the admin at WPBeginner here.

    What to do next depends on the plugin at fault. Whether it’s PMPro, one of our addons, or any other plugin, we will help you in our member forums to fix the issue. Note that sometimes these issues aren’t as straight forward as just programming things correctly the first time. Issues can arise due to conflicts between plugins, themes, or specific server settings. Be understanding with us and any plugin or theme developer you reach out to for help.

  • Bad Web Server Redirect Rules

    Consult section 3a above for some examples on how to redirect all traffic to the HTTPS URLs. If this redirect code is not correct or there is similar but conflicting code in your configuration, then infinite redirect loops can occur. Disable the redirect rules to see if that fixes things. Then try to figure out the correct rules for what you need.

Mixed Content Errors

When you load a web page over HTTPS, your web browser will block any content linked through an HTTP (non-secure) URL. WordPress and any properly coded plugins or themes will use “relative URLs” or otherwise attempt to detect whether a site is using SSL before outputting a URL and so will avoid this issue. However, if a URL is “hard coded” with a starting http:// in your blog posts, or a stylesheet, or a JavaScript file, or somewhere else… then these URLs will get blocked when a page is loaded over HTTPS.

You can notice mixed content errors because:

  • Your page may look funny as certain stylesheets, JavaScript scripts, images, or other files aren’t being loaded.
  • The green/gold/etc padlock in the upper left corner (or lower right corner) of your browser may appear red or yellow instead of green or as an ! instead of a padlock.
  • The Chrome/Safari/Firefox/Firebug debug bar “Console” will show errors.

In Chrome, you can view mixed content (and other errors) in the debug tools console by holding Ctrl + Shift + J on PCs or Cmd + Option + J on Macs. Other browsers have similar features. It will look like this:

Note the “Mixed Content” error at the bottom. The error message will tell you what resource/URL is being blocked. You can use context clues in the resource URL to figure out where that bad URL is coming from. If the file is located within your theme, then the problem is probably in your theme. If the file is located within a plugin folder, then the problem is probably in that plugin. If the file is in the uploaded folder, it might be hard coded into the post content. Another common situation is when theme settings, e.g. a header image, are saved into options. Some theme’s and plugins that save options like this save the full URL. You can usually clear out and reset these options to get a new HTTPS URL saved.

There are some plugins that can be used to fix most of these mixed content issues. On the PMPro payment settings page, you can check the “Extra HTTPS URL Filter” setting and PMPro will attempt to correct any non-HTTPS URLs being used on the site. You can also try the Really Simple SSL plugin or the WP Force SSL plugin, which have more complicated methods of fixing mixed content errors.

If you still see errors even after activating one of the above plugins, then you’ll have to fix the issues “manually”. Again, you can reach out to us in our member forums or reach out to the applicable plugin or theme developer to try to get a mixed-content issue fixed. Sometimes, it’s as easy as changing a URL. Sometimes a resource may be loaded from another server that doesn’t serve files over HTTPS at all. In these cases, you’ll need to stop using that service or find a work around.


I hope this document helps some of you out there newly taksed with moving a site to full on HTTPS. I tried to share as much detail as possible without getting bogged down too much in the technical details. If you have any questions about this or run into other issues while making the move to HTTPS that you think we could address here, let us know in the comments.

If you need help transitioning to HTTPS, we will help our PMPro customers as much as possible in our member forums. Note that sometimes your host and/or SSL provider will need to be involved, so be ready for that. At the very least, we will need to get access information from you and find the time to carefully access your site to debug and fix anything we can.

Debug IPN and Webhook Activity for Integrated Gateways

This post shows you how to enable debugging for when your PMPro-powered site communicates with the payment gateway (via webhook, IPN, or silent post).

This is helpful not only when you are experiencing issues, but if you want to have a more detailed view of all the information your gateway transmits about orders and subscriptions.

Choose the Appropriate Debug Statement for your Gateway

The debug lines are listed below for each gateway we integrate with. To enable, just add the appropriate lines to your site’s wp-config.php file. An email will be sent to the site’s admin email as set under Settings > General.

If you have a lot of activity on your membership site, it may be smart to set up a rule in your email account to automatically archive or move these emails to a separate folder.

For PayPal [more info]

define('PMPRO_IPN_DEBUG', true);

For Stripe




For Braintree


For 2Checkout

define('PMPRO_INS_DEBUG', true);

If you are using our Add PayPal Express Add On, you can define both the onsite gateway debug as well as the PayPal debug.

Sending Debug Information to Other Emails

You can set specific email addresses to receive the debug information by changing the lines above as follows:

define('PMPRO_IPN_DEBUG', ',');

Logging Debug Information (instead of emailing)

You can also set the debug to save to a log file if you’d prefer NOT to receive an email for each piece of activity on your IPN/webhook/silent post URL. Change the line for your gateway as follows:

define('PMPRO_IPN_DEBUG', 'log');

Update on TLS 1.2 Requirements for Gateways

Earlier this year, we shared information on upcoming requirements for using PayPal APIs.

In this post, I’ll update the status of those changes for PayPal and for other gateways and introduce a plugin we’ve developed to help site owners navigate through the required changes.

What’s happening?

All payment gateways, including PayPal, Stripe, Braintree, and (and really any service that uses an API) are updating their API servers to only accept requests made using the new TLS 1.2 protocol for encryption.

What do I need to do?

Ask your web host or server admin to make sure your server supports TLS 1.2. Specifically your web server should:

  • Run OpenSSL 1.0.1 or higher, or another cryptographic library that supports TLS 1.2
  • Run PHP version 5.5.19 or higher.
  • Run cURL version 7.34.0 or higher.

What if I can’t upgrade my server?

The optimal fix for this issue is to upgrade your server software, and you must be running OpenSSL 1.0.1+ or the latest version of an alternative cryptographic library. The TLS 1.2 protocol is defined within the cryptographic library.

There are other reasons to upgrade PHP and cURL, including security reasons, but with respect to TLS 1.2, the versions recommended above mostly just tell the software to use the TLS 1.2 protocol. You may be able to get a lower version of PHP and cURL to use TLS 1.2 by adding the following code to your active theme’s functions.php or a custom plugin. Note that if the TLS 1.2 protocol becomes compromised in the future, you’ll need to adjust this code to force whatever new protocol takes its place.

That’s pretty complicated?

I’m trying to write this all out as clear as possible, but it is confusing. To help with things we’ve developed a plugin to help diagnose if TLS 1.2 is enabled on your site and what steps to take, including an option to force TLS 1.2 in cURL similar to the code gist above.

Get the TLS 1.2 Compatibility Test Plugin from the


When do I need to make these changes?

Ideally, you should make these changes as soon as possible to make sure your site is as secure as possible. Other than that, the main driver behind this change is the PCI Security Standards Council and they have set a deadline of June 30th, 2018, after which time you would risk losing PCI Compatibility status. This is an extension of the previous deadline of June 30th, 2016.

Your payment gateway will likely require the change sooner. PayPal was going to force TLS 1.2 today (June 17th, 2016), but has since extended their own deadline to June 30th 2017.

Other gateways were set to start requiring TLS 1.2 after June 30th, 2016 and may or may have extended that deadline because of the PCI SSC extension. You should check with your gateway to get the exact date… or just upgrade ASAP.

What might go wrong?

Whenever you upgrade your server, especially PHP, things might break. So it’s important to do these updates under the guidance of a trained sysop or with your host. Make any and all backups you can of your server, your files, and your database before starting the upgrade.

WordPress and most popular plugins, like Paid Memberships Pro, will work with newer versions of PHP. However some custom code of yours might rely on earlier PHP versions. I’m hesitant to say this, but generally you can upgrade PHP, then test things to see if anything broke, and then fix any code that is no longer working properly. Or you can consult with the developer who built the custom code and ask them if they expect any problems running the code under the newer version of PHP.

When upgrading PHP, you may also need to upgrade or reinstall some “PHP modules” that are used by your site. These might include the cURL library itself, the Multibyte String library, or others.

Some third party APIs outside the major gateways and name brand web companies may not have updates the web servers their APIs are running on to support TLS 1.2. If you upgrade your server to use TLS 1.2 and specifically if you use the gist above or our compatibility plugin to force TLS 1.2, API requests to these servers may fail. In these cases, you really should ask the entity managing the API to upgrade their servers to support the latest security protocols.

Why are these changes necessary?

When computers talk with each other and they want to keep the communication secret, encryption is used. In practice this means that visitors to the HTTPS version of your site use encryption so information like credit card numbers and billing addresses are kept secret when being entered into a form.

To make all of this work, standard “encryption protocols” are used so web browsers and web servers can communicate in a secure way. Previously, the SSL protocol was the standard, which is why you likely purchased something called an “SSL certificate” for your site. Third party SSL certificates authenticate that you are the true owner of your domain so browsers can confidently engage in SSL encrypted communication with the web server.

Encryption is also used when software like Paid Memberships Pro communicates with payment gateways like PayPal through its APIs. The same encryption protocols used when you visit a website in your browser are used when your web server makes a request to an API. Again, the SSL protocol was most popular for this.

However, several vulnerabilities have been found with SSL (most notably the Heartbleed and POODLE attacks) and a new protocol has been adopted called TLS (Transport Layer Security). This requires a number of updates to both browsers and web servers.

  • Upgrades to servers to use TLS 1.2 when connecting to outside APIs (the topic of this post)
  • Upgrades to API servers to use TLS 1.2 (what the gateways are doing)
  • Upgrades to web browsers to use TLS 1.2 when connecting over HTTPS
  • Upgrades to SSL/TLS certificates and web servers to use TLS 1.2 to serve sites over HTTPS

In Summary

Use the TLS 1.2 Compatibility Test plugin to diagnose if your site is already using TLS 1.2 and to get recommendations for how to upgrade your server to enable TLS 1.2.

While the PCI SSC and gateways have decided to extend the deadline for migrating to exclusive TLS 1.2 usage, you really should make this change as soon as possible to make sure your site is secure.

I’ve tried my best to make this post as clear as possible, but this is a technical issue. Let me know if there is something we can do to be more clear or helpful. If in doubt, forward this post to your host or web master to work through on your site.

Avoiding Undefined Function Errors In Hooks, Filters, Actions, and Custom Code

The dreaded “undefined function” error is a common PHP error that comes up when developing in PHP. We see it specifically come up when using custom code gists from this site.

This post will describe why this error comes up, how to debug it, and how to avoid this error when writing code of your own. You’ll learn how to test if a certain function or plugin is active before using that function or a feature of that plugin.

The error I’m talking about looks something like this:

Fatal error: Call to undefined function somefunctionname() in /var/www/vhosts/ on line 163

On live sites, errors like this might be hidden and/or logged to a file on the server, and so you will only see a blank “whitescreen of death”.

Why this error happens.

Put simply, PHP will throw this fatal error if you attempt to use a function that hasn’t been defined yet.

As an example, here is some PHP code that will cause an error like this if the PMPro Register Helper plugin is deactivated since the function pmprorh_add_registration_field() is defined by that plugin.

function my_pmprorh_init()
    $field = new PMProRH_Field(
        "company",              // input name, will also be used as meta key
        "text",                 // type of field
            "size"=>40,         // input size
            "class"=>"company", // custom class
            "profile"=>true,    // show in user profile
            "required"=>true    // make this field required
        "checkout_boxes", // location on checkout page
        $field            // PMProRH_Field object
add_action("init", "my_pmprorh_init");

Even if you have the Register Helper Add On activated, it will be temporarily deactivated during updates. The customization plugin above runs the pmpro_add_registration_field() function during init, and so your site will crash with a fatal error:undefined function when the Register Helper Add On gets deactivated during update.

How to fix or avoid undefined function errors.

The way to avoid undefined function errors is to make sure the function is defined before it gets used. The best way to do this is with the function_exists() PHP function.

Using function_exists()

At the very top of your function, add some code like this:

//rest of your function code

These two lines will stop the function from executing any code below if the pmprorh_add_registration_field is not available, and this is exactly what we do in our register helper example code.

If your function expects a return parameter, you’ll have to return the value expected

Some functions (e.g. callback methods for WP filters) expect a certain return value. Here is how you would do that if you were filtering on the the_content hook:

function my_the_content_filter($content) {
    //bail if PMPRo is not active
        return $content;  //return the original content
    //... the rest of your code to filter the_content ...
    return $content;

When using plugin functions in a theme file or template, use function_exists() right before the call

In the example above, we used the function_exists() call at the top of a function as a test to see if a plugin is activated before executing the rest of the function. Similarly, if you are using a plugin’s function in your theme’s files or templates, you should use a function_exists() test right before the call just in case that plugin is not activated.

For example, here is how we recommend using the pmpro_hasMembershipLevel() function in your theme code:

if(function_exists('pmpro_hasMembershipLevel') && pmpro_hasMembershipLevel()) {
    //this is a member, do something cool

Other ways to check if a plugin is loaded

Besides checking if a functions exists, you can also check if a class exists, a method exists for a certain class, or a constant is defined. Here are a couple other ways to test if PMPro is activated.


if(class_exists('MemberOrder')) {
    //do something with the MemberOrder class, e.g. $order = new MemberOrder();


if(method_exists('MemberOrder', 'getEmptyMemberOrder')) {
    //getEmptyMemberOrder method added in v1.8.6.8 is available


if(defined('PMPRO_VERSION')) {
    //PMPro has been loaded

We avoid using the TGM Plugin Activation library

There is a nifty library you can use to make plugins require other plugins called TGM Plugin Activation. We’ve used this in the past, but have removed it from some addons and avoid using it now because we found including the library caused more issues that it solved. If another plugin was using an older version of the TGM library, then there could be conflicts. If we simply test for a plugin by looking for a class, function, or constant definition, then there is no chance for a conflict there.

Make sure your check is always at the top of the function

When editing our gists or other code on this site, make sure that your edits go below any function/plugin tests. So…

function my_function() {
    //don't put any code up here
    //test for PMPro
    //put your edits below here

If you are writing a callback for a hook added by a certain plugin, you don’t have to test if that plugin is active

When you define a callback function via add_action() or add_filter() for a hook or filter added by a specific plugin, you don’t have to check that that plugin is active. The fact that the hook fires at all is proof that the plugin is active. So for instance, the PMPRO_VERSION check at the top of this callback is redundant and not needed.

function my_pmpmro_checkout_level($level) {
    //this check if redundant because the pmpro_checkout_level is only used by PMPro
        return $level;
    //... filters here ...
    return $level;
add_filter('pmpro_checkout_level', 'my_pmpro_checkout_level');

Let us know if you found this useful or if you have other questions around this or similar errors.