: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @copyright Copyright (c) 2023, Code Atlantic LLC
if ( ! defined( 'ABSPATH' ) ) {
public static $cache_dir;
* Suffix for minified assets.
public static $asset_url;
* Should we disable asset caching?
public static $disabled = true;
* Should we output debug information?
* Check to see if the cache has been initialized.
public static $initialized = false;
* Initialize asset cache.
public static function init() {
if ( ! self::$initialized ) {
self::$cache_dir = self::get_cache_dir();
self::$debug = Popup_Maker::debug_mode() || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG );
self::$suffix = self::$debug ? '' : '.min';
self::$asset_url = Popup_Maker::$URL . 'assets/';
self::$js_url = self::$asset_url . 'js/';
self::$css_url = self::$asset_url . 'css/';
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
self::$disabled = pum_get_option( 'disable_asset_caching', false );
add_action( 'pum_extension_updated', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_extension_deactivated', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_extension_activated', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_regenerate_asset_cache', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_save_settings', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_save_popup', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_save_theme', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_update_core_version', [ __CLASS__, 'reset_cache' ] );
add_action( 'pum_update_core_version', [ __CLASS__, 'maybe_reset_asset_cache_notices' ] );
if ( isset( $_GET['flush_popup_cache'] ) && check_admin_referer( 'flush_popup_cache' ) ) {
add_action( 'init', [ __CLASS__, 'reset_cache' ] );
add_filter( 'pum_alert_list', [ __CLASS__, 'cache_alert' ] );
add_action( 'pum_styles', [ __CLASS__, 'global_custom_styles' ] );
if ( null === get_option( 'pum_files_writeable', null ) ) {
add_option( 'pum_files_writeable', true );
add_option( '_pum_writeable_notice_dismissed', true );
if ( is_admin() && current_user_can( 'edit_posts' ) ) {
add_action( 'init', [ __CLASS__, 'admin_notice_check' ] );
// Prevent reinitialization.
self::$initialized = true;
* Checks if Asset caching is possible and enabled.
public static function enabled() {
if ( defined( 'PUM_ASSET_CACHE' ) && ! PUM_ASSET_CACHE ) {
return self::writeable() && ! self::$disabled;
* Is the cache directory writeable?
* @return bool True if directory is writeable
public static function writeable() {
// If we have already determined files to not be writeable, go ahead and return.
if ( true !== (bool) get_option( 'pum_files_writeable', true ) ) {
* @var \WP_Filesystem_Base $wp_filesystem
if ( ! function_exists( 'WP_Filesystem' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
$results = WP_Filesystem();
if ( true !== $results ) {
// Prevents this from running again and set to show the admin notice.
update_option( 'pum_files_writeable', false );
update_option( '_pum_writeable_notice_dismissed', false );
if ( ! is_null( $results ) && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$error = $wp_filesystem->errors->get_error_message();
pum_log_message( sprintf( 'Cache directory is not writeable due to filesystem error. Error given: %s', esc_html( $error ) ) );
pum_log_message( 'Cache directory is not writeable due to incorrect filesystem method.' );
// Checks and create cachedir.
if ( false !== self::$cache_dir && ! is_dir( self::$cache_dir ) ) {
$wp_filesystem->mkdir( self::$cache_dir );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
return false !== self::$cache_dir && $wp_filesystem->is_writable( self::$cache_dir ) && ! isset( $_POST['wp_customize'] );
* Regenerate cache on demand.
public static function regenerate_cache() {
* Gets the directory caching should be stored in.
* Accounts for various adblock bypass options.
public static function get_cache_dir() {
$upload_dir = PUM_Helpers::get_upload_dir_path();
if ( false === $upload_dir ) {
if ( ! pum_get_option( 'bypass_adblockers', false ) ) {
return trailingslashit( $upload_dir ) . 'pum';
* Generates a cache filename based on the current adblock bypass settings.
* @param string $filename Filename.
public static function generate_cache_filename( $filename ) {
if ( ! pum_get_option( 'bypass_adblockers', false ) ) {
$is_multisite = ( is_multisite() ) ? '-' . $blog_id : '';
return $filename . $is_multisite;
$site_url = get_site_url();
switch ( pum_get_option( 'adblock_bypass_url_method', 'random' ) ) {
$filename = md5( $site_url . $filename );
$filename = preg_replace( '/[^a-z0-9]+/', '-', pum_get_option( 'adblock_bypass_custom_filename', 'pm-' . $filename ) );
* Generate JS cache file.
public static function cache_js() {
if ( false === self::$cache_dir ) {
$js_file = self::generate_cache_filename( 'pum-site-scripts' ) . '.js';
$js .= " * Do not touch this file! This file created by the Popup Maker plugin using PHP\n";
$js .= ' * Last modified time: ' . wp_date( 'M d Y, h:i:s' ) . "\n";
$js .= self::generate_js();
if ( ! self::cache_file( $js_file, $js ) ) {
update_option( 'pum-has-cached-js', false );
update_option( 'pum-has-cached-js', strtotime( 'now' ) );
* Generate CSS cache file.
public static function cache_css() {
if ( false === self::$cache_dir ) {
$css_file = self::generate_cache_filename( 'pum-site-styles' ) . '.css';
$css .= " * Do not touch this file! This file created by the Popup Maker plugin using PHP\n";
$css .= ' * Last modified time: ' . wp_date( 'M d Y, h:i:s' ) . "\n";
$css .= self::generate_css();
if ( ! self::cache_file( $css_file, $css ) ) {
update_option( 'pum-has-cached-css', false );
update_option( 'pum-has-cached-css', strtotime( 'now' ) );
public static function generate_js() {
* @var \WP_Filesystem_Base $wp_filesystem
// Load core scripts so we can eliminate another stylesheet.
$core_js = $wp_filesystem->get_contents( Popup_Maker::$DIR . 'assets/js/site' . self::$suffix . '.js' );
$popups = pum_get_all_popups();
if ( ! empty( $popups ) ) {
foreach ( $popups as $popup ) {
// Set this popup as the global $current.
pum()->current_popup = $popup;
// Allow per popup JS additions.
do_action( 'pum_generate_popup_js', $popup->ID );
$popup_js = ob_get_clean();
if ( ! empty( $popup_js ) ) {
$js[ 'popup-' . $popup->ID ] = [
// Clear the global $current.
pum()->current_popup = null;
$js = apply_filters( 'pum_generated_js', $js );
foreach ( $js as $key => $code ) {
$js[ $key ] = wp_parse_args(
uasort( $js, [ 'PUM_Helpers', 'sort_by_priority' ] );
foreach ( $js as $key => $code ) {
if ( ! empty( $code['content'] ) ) {
$js_code .= $code['content'] . "\n\n";
* @param string $filename Filename of file to generate.
* @param string $contents Contents to put into file.
public static function cache_file( $filename, $contents ) {
* @var \WP_Filesystem_Base $wp_filesystem
if ( false === self::$cache_dir ) {
if ( ! function_exists( 'WP_Filesystem' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
$file = trailingslashit( self::$cache_dir ) . $filename;
$results = $wp_filesystem->put_contents( $file, $contents, defined( 'FS_CHMOD_FILE' ) ? FS_CHMOD_FILE : false );
// If the file is generated and is accessible...
if ( true === $results && self::is_file_accessible( $filename ) ) {
// ... else, let's set our flags to prevent cache running again for now.
update_option( 'pum_files_writeable', false );
update_option( '_pum_writeable_notice_dismissed', false );
public static function generate_css() {
* @var \WP_Filesystem_Base $wp_filesystem
// Include core styles so we can eliminate another stylesheet.
$core_css = $wp_filesystem->get_contents( Popup_Maker::$DIR . 'assets/css/pum-site' . ( is_rtl() ? '-rtl' : '' ) . self::$suffix . '.css' );
'content' => self::generate_font_imports(),
'content' => self::generate_popup_theme_styles(),
'content' => self::generate_popup_styles(),
'content' => self::custom_css(),
$css = apply_filters( 'pum_generated_css', $css );
foreach ( $css as $key => $code ) {
$css[ $key ] = wp_parse_args(
uasort( $css, [ 'PUM_Helpers', 'sort_by_priority' ] );
foreach ( $css as $key => $code ) {
if ( ! empty( $code['content'] ) ) {
$css_code .= $code['content'] . "\n\n";
* Render global custom styles.
public static function global_custom_styles() {
if ( pum_get_option( 'adjust_body_padding' ) ) {
echo 'html.pum-open.pum-open-overlay.pum-open-scrollable body > *:not([aria-modal="true"]) { padding-right: ' . esc_attr( pum_get_option( 'body_padding_override', '15px' ) ) . '!important; }';
public static function generate_popup_styles() {
$popups = pum_get_all_popups();
if ( ! empty( $popups ) ) {
foreach ( $popups as $popup ) {
// Set this popup as the global $current.
pum()->current_popup = $popup;