: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* WPMUDEV - Recommended Plugins Notice
* @author WPMUDEV (https://wpmudev.com)
* @package WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin
if ( ! class_exists( 'WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin' ) ) {
* Class WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin
* Hold registered plugin as object
class WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin { //phpcs:ignore
* plugin-dir/plugin-name.php
protected $basename = '';
* Screens which notice should be displayed
public $screens = array();
* Time the plugin registered to notice
public $registered_at = 0;
* Element selector which notice should be append-ed
public $selector = array();
* Current active screen being displayed
protected $active_screen = '';
* WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin constructor.
* @param string $basename Plugin basename.
public function __construct( $basename ) {
$this->basename = $basename;
public function get_basename() {
* Build object properties from array
* @param array $data Notice data.
public function from_array( $data ) {
if ( is_array( $data ) ) {
if ( isset( $data['registered_at'] ) ) {
$this->registered_at = (int) $data['registered_at'];
public function to_array() {
'registered_at' => $this->registered_at,
* Check if screen is listen on plugin screen
* @param string $screen_id Screen ID.
public function is_my_screen( $screen_id ) {
foreach ( $this->screens as $screen ) {
if ( $screen_id === $screen ) {
$this->active_screen = $screen_id;
* Get where notice should be moved
public function get_selector() {
$selector = $this->selector;
$active_screen = $this->active_screen;
* Filter selector which notice should be moved to
* @param string $active_screen
return apply_filters( "wpmudev-recommended-plugin-$this->basename-notice-selector", $selector, $active_screen );
* Check whether now is the time to display
public function is_time_to_display_notice() {
$active_screen = $this->active_screen;
$seconds_after_registered = 14 * DAY_IN_SECONDS;
* Filter how many seconds after registered before notice displayed
* This filter is globally used.
* @param int $seconds_after_registered
* @param string $active_screen
$seconds_after_registered = apply_filters( "wpmudev-recommended-plugins-notice-display-seconds-after-registered", $seconds_after_registered, $active_screen );
* Filter how many seconds after registered before notice displayed
* This filter is for plugin based, overriding global value.
* @param int $seconds_after_registered
* @param string $active_screen
$seconds_after_registered = apply_filters( "wpmudev-recommended-plugin-{$this->basename}-notice-display-seconds-after-registered", $seconds_after_registered, $active_screen );
if ( $now >= ( $this->registered_at + $seconds_after_registered ) ) {
* Get pre text on displayed notice
public function get_pre_text_notice() {
$pre_text_notice = sprintf( /* translators: %s - plugin name */
__( 'Enjoying %s? Try out a few of our other popular free plugins...', 'wpmudev_recommended_plugins_notice' ),
* Filter pre text on displayed notice
* @param string $pre_text_notice
return apply_filters( "wpmudev-recommended-plugin-$this->basename-pre-text-notice", $pre_text_notice );
if ( ! class_exists( 'WPMUDEV_Recommended_Plugins_Notice' ) ) {
* Class WPMUDEV_Recommended_Plugins_Notice
class WPMUDEV_Recommended_Plugins_Notice {//phpcs:ignore
* @var WPMUDEV_Recommended_Plugins_Notice
private static $instance = null;
* Collection of recommended plugins
protected $recommended_plugins = array();
const POINTER_NAME = 'wpmudev_recommended_plugins';
const OPTION_NAME = 'wpmudev_recommended_plugins_registered';
* Collection of registered plugins to use this notice
* @var WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin[]
protected $registered_plugins = array();
* Active registered plugin on this screen
protected $active_registered_plugin = null;
* WPMUDEV_Recommended_Plugins_Notice constructor.
public function __construct() {
// Only do things when its on admin screen.
$this->init_recommended_plugins();
$this->parse_saved_registered_plugins();
add_action( 'wpmudev-recommended-plugins-register-notice', array( $this, 'register' ), 10, 4 );
add_action( 'all_admin_notices', array( $this, 'display' ), 6 );
* Init recommended plugins
private function init_recommended_plugins() {
$recommended_plugins = array(
'name' => 'Smush Image Compression',
'desc' => __( 'Resize, optimize and compress all of your images to the max.', 'wpmudev_recommended_plugins_notice' ),
'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-smush.png',
'free_slug' => 'wp-smushit/wp-smush.php',
'pro_slug' => 'wp-smush-pro/wp-smush.php',
'install_link' => 'https://wordpress.org/plugins/wp-smushit/',
'name' => 'Hummingbird Performance',
'desc' => __( 'Add powerful caching and optimize your assets.', 'wpmudev_recommended_plugins_notice' ),
'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-hummingbird.png',
'free_slug' => 'hummingbird-performance/wp-hummingbird.php',
'pro_slug' => 'wp-hummingbird/wp-hummingbird.php',
'install_link' => 'https://wordpress.org/plugins/hummingbird-performance/',
'name' => 'Defender Security',
'desc' => __( 'Secure and protect your site from malicious hackers and bots.', 'wpmudev_recommended_plugins_notice' ),
'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-defender.png',
'free_slug' => 'defender-security/wp-defender.php',
'pro_slug' => 'wp-defender/wp-defender.php',
'install_link' => 'https://wordpress.org/plugins/defender-security/',
'name' => 'SmartCrawl SEO',
'desc' => __( 'Configure your markup for optimal page and social ranking.', 'wpmudev_recommended_plugins_notice' ),
'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-smartcrawl.png',
'free_slug' => 'smartcrawl-seo/wpmu-dev-seo.php',
'pro_slug' => 'wpmu-dev-seo/wpmu-dev-seo.php',
'install_link' => 'https://wordpress.org/plugins/smartcrawl-seo/',
'name' => 'Forminator Forms, Polls & Quizzes',
'desc' => __( 'Create dynamic forms easily and quickly with our form builder.', 'wpmudev_recommended_plugins_notice' ),
'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-forminator.png',
'free_slug' => 'forminator/forminator.php',
'install_link' => 'https://wordpress.org/plugins/forminator/',
'name' => 'Hustle Marketing',
'desc' => __( 'Generate leads with pop-ups, slide-ins and email opt-ins.', 'wpmudev_recommended_plugins_notice' ),
'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-hustle.png',
'free_slug' => 'wordpress-popup/popover.php',
'pro_slug' => 'hustle/opt-in.php',
'install_link' => 'https://wordpress.org/plugins/wordpress-popup/',
$recommended_plugins = apply_filters( 'wpmudev-all-recommended-plugins', $recommended_plugins );
$this->recommended_plugins = $recommended_plugins;
* Get recommended plugins to be displayed on notice
* This function will only return recommended plugins that `not installed` yet
* @param int $min Minimum plugins to be displayed.
* @param int $max Maximum plugins to be displayed.
protected function get_recommended_plugins_for_notice( $min = 2, $max = 2 ) {
$recommended_plugins_for_notice = array();
$recommended_plugins = $this->recommended_plugins;
foreach ( $recommended_plugins as $recommended_plugin ) {
if ( $this->is_plugin_installed( $recommended_plugin ) ) {
$recommended_plugins_for_notice[] = $recommended_plugin;
// Stop when we reached max.
if ( count( $recommended_plugins_for_notice ) >= $max ) {
if ( count( $recommended_plugins_for_notice ) < $min ) {
$recommended_plugins_for_notice = array();
* Filter recommended plugins to be displayed on notice
* @param array $recommended_plugins_for_notice recommended plugins to be displayed
* @param array $recommended_plugins all recommended plugins
* @param int $min minimum plugins to be displayed
* @param int $max maximum plugins to be displayed
return apply_filters( 'wpmudev-recommended-plugins', $recommended_plugins_for_notice, $recommended_plugins, $min, $max );
* Check whether plugin is installed
* @param array $plugin_data Plugin data.
protected function is_plugin_installed( $plugin_data ) {
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
$installed_plugins = get_plugins();
if ( isset( $plugin_data['free_slug'] ) && ! empty( $plugin_data['free_slug'] ) ) {
if ( isset( $installed_plugins[ $plugin_data['free_slug'] ] ) ) {
if ( isset( $plugin_data['pro_slug'] ) && ! empty( $plugin_data['pro_slug'] ) ) {
if ( isset( $installed_plugins[ $plugin_data['pro_slug'] ] ) ) {
* Filter is_installed status of recommended plugin
* @param bool $is_installed
* @param array $plugin_data plugin to be check
* @param array $installed_plugins current installed plugins
return apply_filters( 'wpmudev-recommended-plugin-is-installed', $is_installed, $plugin_data, $installed_plugins );
public function display() {
* Fires before displaying notice
* This action fired before any check done.
do_action( 'wpmudev-recommended-plugins-before-display' );
$is_displayable = $this->is_displayable();
* Filter whether notice is displayable
* @param bool $is_displayable
$is_displayable = apply_filters( 'wpmudev-recommended-plugins-is-displayable', $is_displayable );
if ( ! $is_displayable ) {
$active_registered_plugin = $this->active_registered_plugin;
* Filter whether notice is displayable
* @param bool $is_displayable
$active_registered_plugin = apply_filters( 'wpmudev-recommended-plugin-active-registered', $active_registered_plugin );
if ( ! $active_registered_plugin instanceof WPMUDEV_Recommended_Plugins_Notice_Registered_Plugin ) {
$recommended_plugins = $this->get_recommended_plugins_for_notice();
// no plugins to be recommended.
if ( empty( $recommended_plugins ) ) {
wp_register_style( 'wpmudev-recommended-plugins-css', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'assets/css/notice.css', array(), self::VERSION );
wp_enqueue_style( 'wpmudev-recommended-plugins-css' );
wp_register_script( 'wpmudev-recommended-plugins-js', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'assets/js/notice.js', array( 'jquery' ), self::VERSION, true );
wp_enqueue_script( 'wpmudev-recommended-plugins-js' );
$dismissed_text = __( 'Dismiss', 'wpmudev_recommended_plugins_notice' );
* @param string $dismissed_text
$dismissed_text = apply_filters( 'wpmudev-recommended-plugins-dismissed-text', $dismissed_text );
$selector = $active_registered_plugin->get_selector();