: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Abstract class for Smush view: Abstract_Page
if ( ! defined( 'WPINC' ) ) {
abstract class Abstract_Page {
protected $meta_boxes = array();
protected $modals = array();
protected $tabs = array();
* Settings instance for faster access.
* @var string $upgrade_url
protected $upgrade_url = 'https://wpmudev.com/project/wp-smush-pro/';
* Abstract_Page constructor.
* @param string $slug Page slug.
* @param string $title Page title.
* @param bool $parent Does a page have a parent (will be added as a sub menu).
* @param bool $nextgen Is that a NextGen subpage.
public function __construct( $slug, $title, $parent = false, $nextgen = false, $is_upsell_link = false ) {
$this->settings = Settings::get_instance();
$this->page_id = add_menu_page(
$this->page_id = add_submenu_page(
$nextgen ? 'NextGEN Manage gallery' : 'manage_options',
$is_upsell_link ? null : array( $this, 'render' )
// No need to load these action on parent pages, as they are just placeholders for sub pages.
add_filter( 'load-' . $this->page_id, array( $this, 'on_load' ) );
add_action( 'load-' . $this->page_id, array( $this, 'register_meta_boxes' ) );
add_filter( 'load-' . $this->page_id, array( $this, 'add_action_hooks' ) );
* Common hooks for all screens
public function add_action_hooks() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'admin_notices', array( $this, 'smush_deactivated' ) );
add_action( 'network_admin_notices', array( $this, 'smush_deactivated' ) );
add_action( 'wp_smush_header_notices', array( $this, 'settings_updated' ) );
// Check for any stored API message and show it.
add_action( 'wp_smush_header_notices', array( $this, 'show_api_message' ) );
add_action( 'admin_notices', array( $this, 'smush_dash_required' ) );
add_action( 'network_admin_notices', array( $this, 'smush_dash_required' ) );
add_action( 'wp_smush_render_setting_row', array( $this, 'render_row' ), 10, 4 );
add_filter( 'admin_body_class', array( $this, 'smush_body_classes' ) );
// Filter query args to remove from the URL.
add_filter( 'removable_query_args', array( $this, 'add_removable_query_args' ) );
* @param string $hook Hook from where the call is made.
public function enqueue_scripts( $hook ) {}
* Return the admin menu slug
public function get_slug() {
* @param string $name View name = file name.
* @param array $args Arguments.
* @param string $dir Directory for the views. Default: views.
public function view( $name, $args = array(), $dir = 'views' ) {
$file = WP_SMUSH_DIR . "app/{$dir}/{$name}.php";
if ( is_file( $file ) ) {
if ( isset( $args['id'] ) ) {
$args['orig_id'] = $args['id'];
$args['id'] = str_replace( '/', '-', $args['id'] );
$content = ob_get_clean();
// Everything escaped in all template files.
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
* Display an admin notice about plugin deactivation.
public function smush_deactivated() {
// Display only in backend for administrators.
if ( ! is_admin() || ! is_super_admin() || ! get_site_option( 'smush_deactivated' ) ) {
<?php esc_html_e( 'Smush Free was deactivated. You have Smush Pro active!', 'wp-smushit' ); ?>
delete_site_option( 'smush_deactivated' );
* Show notice when Smush Pro is installed only with a key.
public function smush_dash_required() {
if ( WP_Smush::is_pro() || ! is_super_admin() || ( class_exists( 'WPMUDEV_Dashboard' ) && WPMUDEV_Dashboard::$api->has_key() ) ) {
// Do not show on free versions of the plugin.
if ( false !== strpos( WP_SMUSH_DIR, 'wp-smushit' ) ) {
$function = is_multisite() ? 'network_admin_url' : 'admin_url';
$function( 'update.php?action=install-plugin&plugin=install_wpmudev_dash' ),
'install-plugin_install_wpmudev_dash'
<div class="notice smush-notice">
<div class="smush-notice-logo">
src="<?php echo esc_url( WP_SMUSH_URL . 'app/assets/images/incsub-logo.png' ); ?>"
srcset="<?php echo esc_url( WP_SMUSH_URL . 'app/assets/images/incsub-logo@2x.png' ); ?> 2x"
alt="<?php esc_html_e( 'Smush CDN', 'wp-smushit' ); ?>"
<div class="smush-notice-message">
<?php esc_html_e( 'Smush Pro requires the WPMU DEV Dashboard plugin to unlock pro features. Please make sure you have installed, activated and logged into the Dashboard.', 'wp-smushit' ); ?>
<div class="smush-notice-cta">
<?php if ( class_exists( 'WPMUDEV_Dashboard' ) && ! WPMUDEV_Dashboard::$api->has_key() ) : ?>
<a href="<?php echo esc_url( network_admin_url( 'admin.php?page=wpmudev' ) ); ?>" class="smush-notice-act button-primary" target="_blank">
<?php esc_html_e( 'Log In', 'wp-smushit' ); ?>
<a href="<?php echo esc_url( $url ); ?>" class="smush-notice-act button-primary">
<?php esc_html_e( 'Install Plugin', 'wp-smushit' ); ?>
* @param string $classes Classes string.
public function smush_body_classes( $classes ) {
// Exit if function doesn't exists.
if ( ! function_exists( 'get_current_screen' ) ) {
// If not on plugin page.
if ( ! in_array( get_current_screen()->id, Admin::$plugin_pages, true ) && false === strpos( get_current_screen()->id, 'page_smush' ) ) {
// Remove old wpmud class from body of smush page to avoid style conflict.
$classes = str_replace( 'wpmud ', '', $classes );
$classes .= ' ' . WP_SHARED_UI_VERSION;
* Filters the query args to remove from the URL.
* @param array $args Removable query args.
public function add_removable_query_args( $args ) {
* Allows to register meta boxes for the page.
public function register_meta_boxes() {}
* @param string $id Meta box ID.
* @param string $title Meta box title.
* @param callable $callback Callback for meta box content.
* @param callable $callback_header Callback for meta box header.
* @param callable $callback_footer Callback for meta box footer.
* @param string $context Meta box context.
* @param array $args Arguments.
public function add_meta_box( $id, $title, $callback = null, $callback_header = null, $callback_footer = null, $context = 'main', $args = array() ) {
'box_class' => 'sui-box',
'box_header_class' => 'sui-box-header',
'box_content_class' => 'sui-box-body',
'box_footer_class' => 'sui-box-footer',
$args = wp_parse_args( $args, $default_args );
if ( ! isset( $this->meta_boxes[ $this->slug ] ) ) {
$this->meta_boxes[ $this->slug ] = array();
if ( ! isset( $this->meta_boxes[ $this->slug ][ $context ] ) ) {
$this->meta_boxes[ $this->slug ][ $context ] = array();
if ( ! isset( $this->meta_boxes[ $this->slug ][ $context ] ) ) {
$this->meta_boxes[ $this->slug ][ $context ] = array();
'callback_header' => $callback_header,
'callback_footer' => $callback_footer,
$this->meta_boxes[ $this->slug ][ $context ][ $id ] = $meta_box;
public function render() {
// Shared UI wrapper with accessible color option.
$classes = $this->settings->get( 'accessible_colors' ) ? 'sui-wrap sui-color-accessible' : 'sui-wrap';
echo '<div class="' . esc_attr( $classes ) . ' wrap-' . esc_attr( $this->slug ) . '">';
$this->render_page_header();
$this->render_inner_content();
wp_nonce_field( 'save_wp_smush_options', 'wp_smush_options_nonce', '' );
// Close shared ui wrapper.
* Renders all the modals to be used in the page.
private function render_modals() {
foreach ( $this->modals as $modal_file => $args ) {
$this->view( $modal_file, $args, 'modals' );
private function prepare_modals() {
$this->prepare_onboarding_modal();
$this->prepare_upgrade_modal();
* Onboarding Modal (show onload).
* List bulk smush features, and the related settings.
* => Expect to show it for the fresh installation.
* And we will show it when users can access bulk smush page.
* 1. Show it on single site.
* 2. For MU site, it depends on Sub-site Controls:
* 2.1. IF disable bulk smush page for sub-sites
* => Only show it on network side.
* 2.2. IF enable bulk smush page for sub-sites:
* - Show it for sub-sites.
* - Now we do not show it for network side since we do not show bulk smush page there.
* TODO: Maybe show it when we support bulk smush page on network side, @see: SMUSH-369
private function prepare_onboarding_modal() {
$skip_quick_setup = ! empty( get_option( 'skip-smush-setup' ) );
|| $this->has_onload_modal()
|| ! $this->settings->has_bulk_smush_page()
$this->modals['onboarding'] = array(
'cta_url' => Helper::get_recheck_images_link(),
private function has_onload_modal( $modal = false ) {
|| ( $modal && ! isset( $this->modals[ $modal ] ) )
$rendered_onload_modals = array_intersect( $onload_modals, array_keys( $this->modals ) );
return ! empty( $rendered_onload_modals );
* Upgrade/New Feature modal (show onload).
* Show it when users can access bulk smush page, and network admin.
private function prepare_upgrade_modal() {
$whitelabel_hide_doc_link = apply_filters( 'wpmudev_branding_hide_doc_link', false );
$hide_upgrade_modal = empty( get_site_option( 'wp-smush-show_upgrade_modal' ) );
$is_on_subsite_screen = ! is_network_admin();
$this->has_onload_modal()
|| $whitelabel_hide_doc_link
|| ( $is_on_subsite_screen && ! $this->settings->has_webp_page() )
$should_ignore_upgrade_modal = $whitelabel_hide_doc_link || $this->has_onload_modal( 'onboarding' );
if ( $should_ignore_upgrade_modal ) {
delete_site_option( 'wp-smush-show_upgrade_modal' );
$cta_url = Helper::get_page_url( 'smush-webp' );
$this->modals['updated'] = array(
* Get the current screen tab
public function get_current_tab() {
$tabs = $this->get_tabs();
$view = filter_input( INPUT_GET, 'view', FILTER_SANITIZE_SPECIAL_CHARS );
if ( $view && array_key_exists( $view, $tabs ) ) {
* Display tabs navigation
public function show_tabs() {
'tabs' => $this->get_tabs(),