namespace WPForms\Requirements;
* Requirements management.
* Whether deactivate addon if requirements not met.
* @since 1.9.2 Keep addons active.
private const DEACTIVATE_IF_NOT_MET = false;
* Whether to show PHP version notice.
private const SHOW_PHP_NOTICE = true;
* Whether to show a PHP extension notice.
private const SHOW_EXT_NOTICE = true;
* Whether to show WordPress version notice.
private const SHOW_WP_NOTICE = true;
* Whether to show WPForms version notice.
private const SHOW_WPFORMS_NOTICE = true;
* Whether to show license level notice.
private const SHOW_LICENSE_NOTICE = false;
* Whether to show addon version notice.
private const SHOW_ADDON_NOTICE = true;
* Keys of the requirements' arrays.
private const PHP = 'php';
private const EXT = 'ext';
private const WPFORMS = 'wpforms';
private const LICENSE = 'license';
private const PRIORITY = 'priority';
private const ADDON = 'addon';
private const ADDON_VERSION_CONSTANT = 'addon_version_constant';
private const VERSION = 'version';
private const COMPARE = 'compare';
private const COMPARE_DEFAULT = '>=';
* Development version of WPForms. Can be specified in an addon.
private const WPFORMS_DEV_VERSION_IN_ADDON = '{WPFORMS_VERSION}';
* Plus, Pro and Top level licenses.
* Must be a list separated by comma and space.
private const PLUS_PRO_AND_TOP = [ 'plus', 'pro', 'elite', 'agency', 'ultimate' ];
* Pro and Top level licenses.
* Must be a list separated by comma and space.
private const PRO_AND_TOP = [ 'pro', 'elite', 'agency', 'ultimate' ];
* Must be a list separated by comma and space.
private const TOP = [ 'elite', 'agency', 'ultimate' ];
* Default minimal addon requirements.
self::WPFORMS => self::WPFORMS_DEV_VERSION_IN_ADDON,
self::LICENSE => self::PRO_AND_TOP,
* @todo Add custom message for form-templates-pack.
// phpcs:disable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned, WordPress.Arrays.MultipleStatementAlignment.LongIndexSpaceBeforeDoubleArrow
* Array has the format 'addon basename' => 'addon requirements array'.
* The requirement array can have the following keys:
* self::PHP ('php') for the minimal PHP version required,
* self::EXT ('ext') for the PHP extensions required,
* self::WP ('wp') for the minimal WordPress version required,
* self::WPFORMS ('wpforms') for the minimal WPForms version required,
* self::LICENSE ('license') for the license level required,
* self::ADDON ('addon') for the minimal addon version required,
* self::ADDON_VERSION_CONSTANT ('addon_version_constant') for the addon version constant.
* self::PRIORITY ('priority') for the priority of the current requirements.
* The requirement array can have the following values:
* The 'php' value can be string like '5.6' or an array like 'php' => [ 'version' => '7.2', 'compare' => '=' ].
* The 'ext' value can be a string like 'curl' or an array like 'ext' => [ 'curl', 'mbstring' ].
* The 'wp' value can be string like '5.5' or an array like 'wp' => [ 'version' => '6.4', 'compare' => '=' ].
* The 'wpforms' value can be string like '1.8.2' or an array like 'wpforms' => [ 'version' => '1.7.5', 'compare' => '=' ].
* When the 'wpforms' value is '{WPFORMS_VERSION}', it is not checked and should be used for development.
* The 'license' value can be string like 'elite, agency, ultimate' or an array like 'license' => [ 'elite', 'agency', 'ultimate' ].
* When the 'license' value is empty like null, false, [], it is not checked.
* The 'addon' value can be a string like '2.0.1' or an array like 'addon' => [ 'version' => '2.0.1', 'compare' => '<=' ].
* The 'addon_version_constant' must be a string like 'WPFORMS_ACTIVECAMPAIGN_VERSION'.
* The 'priority' must be an integer like 20. By default, it is 10.
* By default, 'compare' is '>='.
* The default addon version constant is formed from the addon directory name like this:
* wpforms-activecampaign -> WPFORMS_ACTIVECAMPAIGN_VERSION.
* Requirements can be specified here or in the addon as a parameter of wpforms_requirements().
* The priorities from lower to higher (if PRIORITY is not set or equal):
* 1. Default parameters from $this->defaults.
* 2. Current array $this->requirements.
* 3. Parameter of wpforms_requirements() call in the addon.
* Settings with a higher priority overwrite lower priority settings.
* The minimal-required version of WPForms should be specified in the addons.
* The minimal-required version of addons should be specified here, in the `$this->requirements` array.
* We do not plan to restrict the lower addon version so far.
* However, if in the future we may need to do so,
* we should add to the addon-related requirement array the line like
* self::ADDON => '1.x.x' or
* self::ADDON => '{WPFORMS_ACTIVECAMPAIGN_VERSION}'.
* Here 1.x.x is the specific addon version, and
* WPFORMS_ACTIVECAMPAIGN_VERSION is the addon version constant name.
* The script will replace the addon version constant name during the addon release.
private $requirements = [
'wpforms/wpforms.php' => [
self::EXT => 'curl, dom, json, libxml',
'wpforms-lite/wpforms.php' => [
self::EXT => 'curl, dom, json, libxml',
'wpforms-activecampaign/wpforms-activecampaign.php' => [
self::LICENSE => self::TOP,
'wpforms-authorize-net/wpforms-authorize-net.php' => [
self::LICENSE => self::TOP,
'wpforms-aweber/wpforms-aweber.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-calculations/wpforms-calculations.php' => [
'wpforms-campaign-monitor/wpforms-campaign-monitor.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-captcha/wpforms-captcha.php' => [
self::LICENSE => 'basic, plus, pro, elite, agency, ultimate',
self::VERSION => [ '1.8.3', '1.8.7' ],
self::COMPARE => [ '>=', '<' ],
'wpforms-conversational-forms/wpforms-conversational-forms.php' => [],
'wpforms-convertkit/wpforms-convertkit.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-coupons/wpforms-coupons.php' => [
'wpforms-drip/wpforms-drip.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-dropbox/wpforms-dropbox.php' => [
'wpforms-entry-automation/wpforms-entry-automation.php' => [
self::LICENSE => self::TOP,
'wpforms-form-abandonment/wpforms-form-abandonment.php' => [],
'wpforms-form-locker/wpforms-form-locker.php' => [
'wpforms-form-pages/wpforms-form-pages.php' => [],
'wpforms-form-templates-pack/wpforms-form-templates-pack.php' => [
self::VERSION => '1.6.8',
'wpforms-geolocation/wpforms-geolocation.php' => [],
'wpforms-getresponse/wpforms-getresponse.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-google-calendar/wpforms-calendar.php' => [],
'wpforms-google-drive/wpforms-google-drive.php' => [
'wpforms-google-sheets/wpforms-google-sheets.php' => [
'wpforms-hubspot/wpforms-hubspot.php' => [
self::LICENSE => self::TOP,
'wpforms-lead-forms/wpforms-lead-forms.php' => [],
'wpforms-mailchimp/wpforms-mailchimp.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-mailerlite/wpforms-mailerlite.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-mailpoet/wpforms-mailpoet.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-offline-forms/wpforms-offline-forms.php' => [],
'wpforms-paypal-commerce/wpforms-paypal-commerce.php' => [],
'wpforms-paypal-standard/wpforms-paypal-standard.php' => [],
'wpforms-pdf/wpforms-pdf.php' => [
self::LICENSE => self::PRO_AND_TOP,
'wpforms-pipedrive/wpforms-pipedrive.php' => [
self::LICENSE => self::TOP,
'wpforms-post-submissions/wpforms-post-submissions.php' => [],
'wpforms-salesforce/wpforms-salesforce.php' => [
self::LICENSE => self::TOP,
'wpforms-save-resume/wpforms-save-resume.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-sendinblue/wpforms-sendinblue.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-signatures/wpforms-signatures.php' => [
'wpforms-slack/wpforms-slack.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-square/wpforms-square.php' => [
'wpforms-stripe/wpforms-stripe.php' => [],
'wpforms-surveys-polls/wpforms-surveys-polls.php' => [
'wpforms-twilio/wpforms-twilio.php' => [
self::LICENSE => self::PLUS_PRO_AND_TOP,
'wpforms-user-journey/wpforms-user-journey.php' => [],
'wpforms-user-registration/wpforms-user-registration.php' => [],
'wpforms-webhooks/wpforms-webhooks.php' => [
self::LICENSE => self::TOP,
'wpforms-zapier/wpforms-zapier.php' => [],
'wpforms-zoho-crm/wpforms-zoho-crm.php' => [
self::LICENSE => self::TOP,
// phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned, WordPress.Arrays.MultipleStatementAlignment.LongIndexSpaceBeforeDoubleArrow
private $addon_requirements = [];
private $not_validated = [];
* Get a single instance of the addon.
public static function get_instance(): Requirements {
private function init(): void {
foreach ( $this->requirements as $basename => $requirement ) {
$this->init_addon_requirements( $basename );
private function hooks(): void {
add_action( 'admin_init', [ $this, 'deactivate' ] );
add_action( 'admin_notices', [ $this, 'show_notices' ] );
add_action( 'network_admin_notices', [ $this, 'show_notices' ] );
* @param array $addon_requirements Addon requirements.
public function validate( array $addon_requirements ): bool {
$this->addon_requirements = $addon_requirements;
$file = $this->addon_requirements['file'];
// Requirements' array must contain the addon main filename.
if ( ! isset( $file ) ) {
$this->basename = plugin_basename( $file );
if ( $this->basename === 'wpforms/wpforms.php' && ! wpforms_is_pro() ) {
$this->basename = 'wpforms-lite/wpforms.php';
$this->init_addon_requirements( $this->basename );
$this->addon_requirements = $this->merge_requirements(
$this->requirements[ $this->basename ],
$this->addon_requirements
$php_valid = $this->validate_php();
$ext_valid = $this->validate_ext();
$wp_valid = $this->validate_wp();
$wpforms_valid = $this->validate_wpforms();
$license_valid = $this->validate_license();
$addon_valid = $this->validate_addon();
if ( $php_valid && $ext_valid && $wp_valid && $wpforms_valid && $license_valid && $addon_valid ) {
$this->validated[] = $this->basename;
$this->requirements[ $this->basename ] = $this->addon_requirements;
return empty( $this->not_validated[ $this->basename ] );
* Determine if addon is validated.
* @param string $basename Addon basename.
public function is_validated( string $basename ): bool {
if ( ! file_exists( WP_PLUGIN_DIR . '/' . $basename ) ) {
// No more actions if the plugin file does not exist.
if ( ! $this->is_wpforms_addon( $basename ) ) {
// No more actions if it is not a wpforms addon.
// We didn't check the addon before.
if ( ! isset( $this->not_validated[ $basename ] ) && ! in_array( $basename, $this->validated, true ) ) {
$addon_load_function = $this->get_addon_load_function( $basename );
if ( ! is_callable( $addon_load_function ) ) {
// Invoke the addon loading function, which checks requirements.
return in_array( $basename, $this->validated, true );
* Merge requirements by priority.
* @param array $defaults Default requirements.
* @param array $requirements Requirements.
* @param array $addon_requirements Addon requirements.