: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
namespace WPForms\Admin\Addons;
const ULTIMATE = 'ultimate';
private $available_addons;
* Determine if the class is allowed to load.
public function allow_load() {
$has_permissions = wpforms_current_user_can( [ 'create_forms', 'edit_forms' ] );
$allowed_requests = wpforms_is_admin_ajax() || wpforms_is_admin_page() || wpforms_is_admin_page( 'builder' );
return $has_permissions && $allowed_requests;
if ( ! $this->allow_load() ) {
$this->cache = wpforms()->get( 'addons_cache' );
$this->addons = $this->cache->get();
protected function hooks() {
add_action( 'admin_init', [ $this, 'get_available' ] );
* Fire before admin addons init.
do_action( 'wpforms_admin_addons_init' );
* Get all addons data as array.
* @param bool $force_cache_update Determine if we need to update cache. Default is `false`.
public function get_all( $force_cache_update = false ) {
if ( $force_cache_update ) {
$this->cache->update( true );
$this->addons = $this->cache->get();
// WPForms 1.8.7 core includes Custom Captcha.
// The Custom Captcha addon will only work on WPForms 1.8.6 and earlier versions.
unset( $this->addons['wpforms-captcha'] );
return $this->get_sorted_addons();
* Get sorted addons data.
* Recommended addons will be displayed first,
* then new addons, then featured addons,
* and then all other addons.
private function get_sorted_addons(): array {
if ( empty( $this->addons ) ) {
$recommended = array_filter(
static function ( $addon ) {
return ! empty( $addon['recommended'] );
static function ( $addon ) {
return ! empty( $addon['new'] );
$featured = array_filter(
static function ( $addon ) {
return ! empty( $addon['featured'] );
return array_merge( $recommended, $new, $featured, $this->addons );
* Get filtered addons data.
* ->get_filtered( $this->addons, [ 'category' => 'payments' ] ) - addons for the payments panel.
* ->get_filtered( $this->addons, [ 'license' => 'elite' ] ) - addons available for 'elite' license.
* @param array $addons Raw addons data.
* @param array $args Arguments array.
* @return array Addons data filtered according to given arguments.
private function get_filtered( $addons, $args ) {
if ( empty( $addons ) ) {
$args = wp_parse_args( $args, $default_args );
foreach ( $addons as $addon ) {
foreach ( [ 'category', 'license' ] as $arg_key ) {
! empty( $args[ $arg_key ] ) &&
! empty( $addon[ $arg_key ] ) &&
is_array( $addon[ $arg_key ] ) &&
in_array( strtolower( $args[ $arg_key ] ), $addon[ $arg_key ], true )
$filtered_addons[] = $addon;
* Get available addons data by category.
* @param string $category Addon category.
public function get_by_category( $category ) {
return $this->get_filtered( $this->available_addons, [ 'category' => $category ] );
* Get available addons data by license.
* @param string $license Addon license.
* @noinspection PhpUnused
public function get_by_license( $license ) {
return $this->get_filtered( $this->available_addons, [ 'license' => $license ] );
* Get available addons data by slugs.
* @param array $slugs Addon slugs.
public function get_by_slugs( $slugs ) {
if ( empty( $slugs ) || ! is_array( $slugs ) ) {
foreach ( $slugs as $slug ) {
$addon = $this->get_addon( $slug );
if ( ! empty( $addon ) ) {
$result_addons[] = $addon;
* Get available addon data by slug.
* @param string $slug Addon slug, can be both "wpforms-drip" and "drip".
* @return array Single addon data. Empty array if addon is not found.
public function get_addon( $slug ) {
$slug = 'wpforms-' . str_replace( 'wpforms-', '', sanitize_key( $slug ) );
$addon = ! empty( $this->available_addons[ $slug ] ) ? $this->available_addons[ $slug ] : [];
// In case if addon is "not available" let's try to get and prepare addon data from all addons.
$addon = ! empty( $this->addons[ $slug ] ) ? $this->prepare_addon_data( $this->addons[ $slug ] ) : [];
* Check if addon is active.
* @param string $slug Addon slug.
public function is_active( string $slug ): bool {
$addon = $this->get_addon( $slug );
return isset( $addon['status'] ) && $addon['status'] === 'active';
* Get license level of the addon.
* @param array|string $addon Addon data array OR addon slug.
* @return string License level: pro | elite.
private function get_license_level( $addon ) {
$levels = [ self::BASIC, self::PLUS, self::PRO, self::ELITE, self::AGENCY, self::ULTIMATE ];
$addon_license = $this->get_addon_license( $addon );
foreach ( $levels as $level ) {
if ( in_array( $level, $addon_license, true ) ) {
if ( empty( $license ) ) {
return in_array( $license, [ self::BASIC, self::PLUS, self::PRO ], true ) ? self::PRO : self::ELITE;
* @param array|string $addon Addon data array OR addon slug.
private function get_addon_license( $addon ) {
$addon = is_string( $addon ) ? $this->get_addon( $addon ) : $addon;
return $this->default_data( $addon, 'license', [] );
* Determine if user's license level has access.
* @param array|string $addon Addon data array OR addon slug.
protected function has_access( $addon ) {
* Return array of addons available to display. All data prepared and normalized.
* "Available to display" means that addon need to be displayed as education item (addon is not installed or not activated).
public function get_available() {
if ( empty( $this->addons ) || ! is_array( $this->addons ) ) {
if ( empty( $this->available_addons ) ) {
$this->available_addons = array_map( [ $this, 'prepare_addon_data' ], $this->addons );
$this->available_addons = array_filter(
static function ( $addon ) {
return isset( $addon['status'], $addon['plugin_allow'] ) && ( $addon['status'] !== 'active' || ! $addon['plugin_allow'] );
return $this->available_addons;
* @param array $addon Addon data.
* @return array Extended addon data.
protected function prepare_addon_data( $addon ) {
$addon['title'] = $this->default_data( $addon, 'title', '' );
$addon['slug'] = $this->default_data( $addon, 'slug', '' );
// We need the cleared name of the addon, without the ' addon' suffix, for further use.
$addon['name'] = preg_replace( '/ addon$/i', '', $addon['title'] );
$addon['modal_name'] = sprintf( /* translators: %s - addon name. */
esc_html__( '%s addon', 'wpforms-lite' ),
$addon['clear_slug'] = str_replace( 'wpforms-', '', $addon['slug'] );
$addon['utm_content'] = ucwords( str_replace( '-', ' ', $addon['clear_slug'] ) );
$addon['license'] = $this->default_data( $addon, 'license', [] );
$addon['license_level'] = $this->get_license_level( $addon );
$addon['icon'] = $this->default_data( $addon, 'icon', '' );
$addon['path'] = sprintf( '%1$s/%1$s.php', $addon['slug'] );
$addon['video'] = $this->default_data( $addon, 'video', '' );
$addon['plugin_allow'] = $this->has_access( $addon );
$addon['status'] = 'missing';
$addon['action'] = 'upgrade';
$addon['page_url'] = $this->default_data( $addon, 'url', '' );
$addon['doc_url'] = $this->default_data( $addon, 'doc', '' );
$nonce = empty( $nonce ) ? wp_create_nonce( 'wpforms-admin' ) : $nonce;
$addon['nonce'] = $nonce;
* @param array $addon Addon data.
* @param string $key Key.
* @param mixed $default Default data.
* @return array|string|mixed
private function default_data( $addon, $key, $default ) {
if ( is_string( $default ) ) {
return ! empty( $addon[ $key ] ) ? $addon[ $key ] : $default;
if ( is_array( $default ) ) {
return ! empty( $addon[ $key ] ) ? (array) $addon[ $key ] : $default;