: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @copyright Copyright (c) 2023, Code Atlantic LLC
class PUM_Utils_Prerequisites {
* Cache accessible across instances.
public static $cache = [];
* Array of checks to perform.
* Array of detected failures.
protected $failures = [];
* Instantiate prerequisite checker.
* @param array $requirements Array of requirements.
public function __construct( $requirements = [] ) {
foreach ( $requirements as $arguments ) {
switch ( $arguments['type'] ) {
$this->checks[] = wp_parse_args(
$this->checks[] = wp_parse_args(
'check_installed' => false,
* @param boolean $return_on_fail Whether it should stop processing if one fails.
public function check( $return_on_fail = false ) {
foreach ( $this->checks as $check ) {
$result = $this->check_handler( $check );
if ( false === $result ) {
if ( true === $return_on_fail ) {
* Render notices when appropriate.
public function setup_notices() {
add_action( 'admin_notices', [ $this, 'render_notices' ] );
* Handle individual checks by mapping them to methods.
* @param array $check Requirement check arguments.
public function check_handler( $check ) {
return method_exists( $this, 'check_' . $check['type'] ) ? $this->{'check_' . $check['type']}( $check ) : false;
* Report failure notice to the queue.
* @param array $check_args Array of check arguments.
public function report_failure( $check_args ) {
$this->failures[] = $check_args;
* Get a list of failures.
public function get_failures() {
* Check PHP version against args.
* @param array $check_args Array of args.
public function check_php( $check_args ) {
if ( false === version_compare( phpversion(), $check_args['version'], '>=' ) ) {
$this->report_failure( $check_args );
* Check plugin requirements.
* @param array $check_args Array of args.
public function check_plugin( $check_args ) {
$active = $this->plugin_is_active( $check_args['slug'] );
* The following checks are performed in this order for performance reasons.
* We start with most cached option, to least in hopes of a hit early.
* 1. If active and not checking version.
* 2. If active and outdated.
* 3. If not active and installed.
if ( true === $active ) {
// If required version is set & plugin is active, check that first.
if ( isset( $check_args['version'] ) ) {
$version = $this->get_plugin_data( $check_args['slug'], 'Version' );
// If its higher than the required version, we can bail now > true.
if ( version_compare( $version, $check_args['version'], '>=' ) ) {
// If not updated, report the failure and bail > false.
// Report not_updated status.
// If the plugin is active, with no required version, were done > true.
if ( $check_args['check_installed'] ) {
// Check if installed, if so the plugin is not activated.
if ( $check_args['name'] === $this->get_plugin_data( $check_args['slug'], 'Name' ) ) {
// Report not_activated status.
// Report not_installed status.
* Internally cached get_plugin_data/get_file_data wrapper.
* @param string $slug Plugins `folder/file.php` slug.
* @param string $header Specific plugin header needed.
private function get_plugin_data( $slug, $header = null ) {
if ( ! isset( static::$cache['get_plugin_data'][ $slug ] ) ) {
$headers = \get_file_data(
WP_PLUGIN_DIR . '/' . $slug,
static::$cache['get_plugin_data'][ $slug ] = $headers;
$plugin_data = static::$cache['get_plugin_data'][ $slug ];
if ( empty( $header ) ) {
return isset( $plugin_data[ $header ] ) ? $plugin_data[ $header ] : null;
* Check if plugin is active.
* @param string $slug Slug to check for.
protected function plugin_is_active( $slug ) {
$active_plugins = get_option( 'active_plugins', [] );
return in_array( $slug, $active_plugins, true );
* @param array $failed_check_args Check arguments.
public function get_php_message( $failed_check_args ) {
/* translators: 1. PHP Version */
$message = __( 'This plugin requires <b>PHP %s</b> or higher in order to run.', 'popup-maker' );
return sprintf( $message, $failed_check_args['version'] );
* Get plugin error message.
* @param array $failed_check_args Get helpful error message.
public function get_plugin_message( $failed_check_args ) {
$slug = $failed_check_args['slug'];
$short_slug = explode( '/', $slug );
$short_slug = $short_slug[0];
$name = $failed_check_args['name'];
$dep_label = $failed_check_args['dep_label'];
if ( isset( $failed_check_args['not_activated'] ) ) {
$url = esc_url( wp_nonce_url( admin_url( 'plugins.php?action=activate&plugin=' . $slug ), 'activate-plugin_' . $slug ) );
$link = '<a href="' . $url . '">' . __( 'activate it', 'popup-maker' ) . '</a>';
/* translators: 1. Plugin Name, 2. Required Plugin Name, 4. `activate it` link. */
__( 'The plugin "%1$s" requires %2$s! Please %3$s to continue!', 'popup-maker' ),
'<strong>' . $name . '</strong>',
} elseif ( isset( $failed_check_args['not_updated'] ) ) {
$url = esc_url( wp_nonce_url( admin_url( 'update.php?action=upgrade-plugin&plugin=' . $slug ), 'upgrade-plugin_' . $slug ) );
$link = '<a href="' . $url . '">' . __( 'update it', 'popup-maker' ) . '</a>';
/* translators: 1. Plugin Name, 2. Required Plugin Name, 3. Version number, 4. `update it` link. */
__( 'The plugin "%1$s" requires %2$s v%3$s or higher! Please %4$s to continue!', 'popup-maker' ),
'<strong>' . $name . '</strong>',
'<strong>' . $failed_check_args['version'] . '</strong>',
$url = esc_url( wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $short_slug ), 'install-plugin_' . $short_slug ) );
$link = '<a href="' . $url . '">' . __( 'install it', 'popup-maker' ) . '</a>';
/* translators: 1. Plugin Name, 2. Required Plugin Name, 3. `install it` link. */
__( 'The plugin "%1$s" requires %2$s! Please %3$s to continue!', 'popup-maker' ),
'<strong>' . $name . '</strong>',
* Render needed admin notices.
public function render_notices() {
foreach ( $this->failures as $failure ) {
$class = 'notice notice-error';
$message = method_exists( $this, 'get_' . $failure['type'] . '_message' ) ? $this->{'get_' . $failure['type'] . '_message'}( $failure ) : false;
/* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */
echo sprintf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), $message );