File: /var/www/html/CW-techs/wp-content/plugins/wp-cerber/cerber-addons.php
<?php
/*
Copyright (C) 2015-25 CERBER TECH INC., https://wpcerber.com
Licenced under the GNU GPL.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
*========================================================================*
| |
| ATTENTION! Do not change or edit this file! |
| |
*========================================================================*
*/
// Note: these constant names may not be changed ever
const CRB_ADDON_PAGE = 'cerber-addons';
const CRB_ADDON_SIGN = '_addon';
const CRB_BOOT_ADDONS = 'boot_cerber_addons';
// WP Cerber add-ons API -----------------------------------------------------------------
/**
* @param string $file Add-on PHP file to be loaded after WP Cerber has loaded itself
* @param string $addon_id Add-on slug (unique add-on ID)
* @param string $name Name of the add-on show in the admin UI
* @param string $requires Optional version of WP Cerber required by the add-on
* @param callable $settings Optional configuration of the add-on setting fields: a callback function returning the settings fields since 9.6.2.3
* @param callable $cb Optional callback function invoked when a website admin saves add-on settings.
*
* @return bool
*/
function cerber_register_addon( $file, $addon_id, $name, $requires = '', $settings = null, $cb = null ) {
return CRB_Addons::register_addon( $file, $addon_id, $name, $requires, $settings, $cb );
}
/**
* @param string $event
* @param callable $callback
* @param string $addon_id
*
* @return bool
*/
function cerber_add_handler( $event, $callback, $addon_id = null ) {
return CRB_Events::add_handler( $event, $callback, $addon_id );
}
/**
* Returns add-on settings
*
* @param string $addon_id
* @param string $setting
* @param bool $purge_cache
*
* @return array|bool|mixed
*
* @since 9.3.4
*/
function cerber_get_addon_settings( $addon_id = '', $setting = '', $purge_cache = false ) {
$all = crb_get_settings( CRB_ADDON_STS, $purge_cache );
if ( ! $addon_id ) {
return $all;
}
$ret = crb_array_get( $all, $addon_id, false );
if ( ! $ret || ! $setting ) {
return $ret;
}
return crb_array_get( $ret, $setting, false );
}
// END of WP Cerber's add-ons API ----------------------------------------------------------
cerber_add_handler( 'update_settings', function ( $data ) {
crb_x_update_add_on_list();
} );
/**
* Creates and updates a list of files to be booted
*
*/
add_action( 'activated_plugin', 'crb_update_add_on_list' );
function crb_update_add_on_list() {
if ( ! $addons = CRB_Addons::get_all() ) {
cerber_update_set( CRB_BOOT_ADDONS, array() );
return;
}
$boot = array();
foreach ( CRB_Events::get_addons() as $event => $listeners ) {
$to_boot = array_intersect_key( $addons, array_flip( $listeners ) );
$boot[ $event ] = array_column( $to_boot, 'file' );
}
cerber_update_set( CRB_BOOT_ADDONS, $boot );
}
add_action( 'deactivated_plugin', 'crb_x_update_add_on_list' );
/**
* Postponed refreshing. This combination is used when it's not possible to correctly refresh
* the list during the current request.
*
*/
function crb_x_update_add_on_list() {
if ( ! defined( 'CRB_POSTPONE_REFRESH' ) ) {
define( 'CRB_POSTPONE_REFRESH', 1 );
}
cerber_update_set( 'refresh_add_on_list', 1, null, false );
}
register_shutdown_function( function () {
if ( ! defined( 'CRB_POSTPONE_REFRESH' )
&& cerber_get_set( 'refresh_add_on_list', null, false ) ) {
crb_update_add_on_list();
cerber_update_set( 'refresh_add_on_list', 0, null, false );
}
} );
final class CRB_Events {
private static $handlers = array();
private static $addons = array();
private static $addon_files = null;
private static $loaded = array();
/**
* Register a handler for an event
*
* @param string $event
* @param callable $callback
* @param string $addon_id
*
* @return bool
*/
static function add_handler( $event, $callback, $addon_id = null ) {
if ( $addon_id && ! CRB_Addons::is_registered( $addon_id ) ) {
return false;
}
self::$handlers[ $event ][] = $callback;
if ( $addon_id ) {
self::$addons[ $event ][] = $addon_id;
}
return true;
}
static function event_handler( $event, $data ) {
if ( ! isset( self::$addon_files ) ) {
if ( ! self::$addon_files = cerber_get_set( CRB_BOOT_ADDONS ) ) {
self::$addon_files = false;
}
}
if ( ! empty( self::$addon_files[ $event ] )
&& ! isset( self::$loaded[ $event ] ) ) {
ob_start();
self::$loaded[ $event ] = 1; //Avoid processing files for repetitive events
foreach ( self::$addon_files[ $event ] as $addon_file ) {
if ( @file_exists( $addon_file ) ) {
include_once $addon_file;
}
}
ob_end_clean();
}
if ( ! isset( self::$handlers[ $event ] ) ) {
return;
}
foreach ( self::$handlers[ $event ] as $handler ) {
if ( is_callable( $handler ) ) {
call_user_func( $handler, $data );
}
}
}
static function get_addons( $event = null ) {
if ( ! $event ) {
return self::$addons;
}
return crb_array_get( self::$addons, $event, array() );
}
}
final class CRB_Addons {
private static $addons = array();
private static $tabs = array(); // Add-on tab IDs, they are equal add-on setting screen IDs
private static $first = '';
/**
* @param string $file Add-on main PHP file to be invoked in if event occurs
* @param string $addon_id Add-on slug
* @param string $name Name of the add-on
* @param string $requires Version of WP Cerber required
* @param callable $settings Configuration of the add-on setting fields
* @param callable $cb Optional callback function invoked when a website admin saves add-on settings.
*
* @return bool
*/
static function register_addon( $file, $addon_id, $name, $requires = '', $settings = null, $cb = null ) {
$addon_id = crb_sanitize_id( $addon_id );
if ( isset( self::$addons[ $addon_id ] ) ) {
return false;
}
if ( $requires && version_compare( $requires, CERBER_VER, '>' ) ) {
crb_admin_notice_interactive( 'This add-on is not active: ' . esc_html( $name ) . '. It requires WP Cerber version ' . esc_html( $requires ) . ' or newer. To solve the issue, please install the latest version of WP Cerber or deactivate the add-on.' );
return false;
}
if ( ! self::$first ) {
self::$first = $addon_id;
}
self::$addons[ $addon_id ] = array(
'file' => $file,
'name' => $name,
'settings' => $settings,
'settings_cb' => $settings,
'callback' => $cb
);
self::$tabs[ $addon_id . CRB_ADDON_SIGN ] = $addon_id . CRB_ADDON_SIGN;
return true;
}
/**
* @return array
*/
static function get_all() {
return self::$addons;
}
/**
* Returns add-on settings config, if it generates by the specified add-on.
*
* @param $addon_id
*
* @return array
*
* @since 9.6.2.3
*/
static function get_addon_settings( $addon_id ): array {
static $cache = array();
if ( ! isset( $cache[ $addon_id ] ) ) {
$config = array();
if ( $cb = self::$addons[ $addon_id ]['settings_cb'] ?? false ) {
if ( is_callable( $cb ) ) {
$config = call_user_func( $cb ); // New way since 9.6.2.3
if ( ! is_array( $config ) ) {
$config = false;
}
}
elseif ( is_array( $cb ) ) { // Old way
$config = $cb;
}
}
$cache[ $addon_id ] = $config;
}
return $cache[ $addon_id ];
}
/**
* Add setting screens (tabs) and related setting sections for all add-ons
*
* @return array[]|false
*/
static function settings_config() {
if ( ! self::$addons ) {
return false;
}
$settings = array( 'screens' => array(), 'sections' => array() );
foreach ( self::$addons as $id => $addon ) {
if ( ! $config = self::get_addon_settings( $id ) ) {
continue;
}
$settings['screens'][ $id . CRB_ADDON_SIGN ] = array_keys( $config ); // Register a setting tab with setting sections
$settings['sections'] = array_merge( $settings['sections'], $config ); // Register setting sections
}
return $settings;
}
static function update_settings( $form_fields, $addon_id ) {
if ( ( ! $addon = self::$addons[ $addon_id ] ?? false )
|| ! $config = self::get_addon_settings( $addon_id ) ) {
return false;
}
$fields = array();
foreach ( $config as $section ) {
$fields = array_merge( $fields, array_keys( $section['fields'] ) );
}
$new_settings = array_merge( array_fill_keys( $fields, '' ), $form_fields );
$all_settings = cerber_get_addon_settings();
$save = array_merge( $all_settings, array( $addon_id => $new_settings ) );
$ret = cerber_settings_update( array( CRB_ADDON_STS => $save ) );
if ( ! empty( $addon['callback'] )
&& is_callable( $addon['callback'] ) ) {
crb_sanitize_deep( $new_settings );
call_user_func( $addon['callback'], $new_settings );
}
return $ret;
}
/**
* Returns add-on tab ID for the specified WP setting screen ID
*
* @param string $screen_id
*
* @return string
*
* @since 9.6.2.1
*/
static function get_addon_tab( $screen_id ): string {
return self::$tabs[ $screen_id ] ?? '';
}
/**
* Returns WP setting screen ID for the specified add-on tab (or the add-on page)
*
* @param string $id
*
* @return string
*
* @since 9.6.2.1
*/
static function get_setting_screen( $id ): string {
if ( ! empty( self::$tabs[ $id ] ) ) {
return self::$tabs[ $id ];
}
// If the page ID specified, it means the first tab
if ( $id == CRB_ADDON_PAGE ) {
return reset( self::$tabs );
}
return '';
}
/**
* Returns WP Cerber admin page ID for the specified add-on tab
*
* @param string $tab
*
* @return string
*
* @since 9.6.2.1
*/
static function get_addon_page( $tab ): string {
if ( ! empty( self::$tabs[ $tab ] ) ) {
return CRB_ADDON_PAGE;
}
return '';
}
/**
* @param string $addon
*
* @return bool
*/
static function is_registered( $addon ) {
return isset( self::$addons[ $addon ] );
}
/**
* Is any add-on registered?
*
* @return bool
*/
static function none() {
return empty( self::$first );
}
/**
* @return string
*/
static function get_first() {
return self::$first;
}
/**
* Load code of all active add-ons
*
*/
static function load_active() {
if ( ! $list = cerber_get_set( CRB_BOOT_ADDONS ) ) {
return;
}
foreach ( $list as $files ) {
foreach ( $files as $file ) {
if ( @file_exists( $file ) ) {
include_once $file;
}
}
}
}
/**
* Retrieves the configuration for the admin UI of the addons.
*
* @return array|false The configuration array for the admin UI, or false if no addons are available.
*/
static function get_admin_ui() {
if ( ! self::$addons ) {
return false;
}
$config = array(
'title' => __( 'Add-ons', 'wp-cerber' ),
'callback' => function ( $tab, $tab_data ) {
cerber_show_settings_form( $tab, $tab_data );
},
);
foreach ( self::$addons as $id => $addon ) {
$config['tabs'][ $id . CRB_ADDON_SIGN ] = array(
'bx-cog',
crb_generic_escape( $addon['name'] ),
'tab_data' => array(
'page_type' => 'addon-settings',
'addon_id' => $id
)
);
}
return $config;
}
}
function crb_event_handler( $event, $data ) {
CRB_Events::event_handler( $event, $data );
return;
}
/**
* Upgrade add-on settings (if any) to a new format
*
* @return void
*
* @since 9.3.4
*/
function _cerber_upgrade_addon_settings(){
$addon_settings = array();
$old_settings = get_site_option( 'cerber_tmp_old_settings' );
foreach ( CRB_Addons::get_all() as $addon_id => $addon_conf ) {
if ( ! $config = CRB_Addons::get_addon_settings( $addon_id ) ) {
continue;
}
$fields = array();
foreach ( $config as $section ) {
$fields = array_merge( $fields, array_keys( $section['fields'] ) );
}
$addon_settings[ $addon_id ] = array_intersect_key( $old_settings, array_flip( $fields ) );
}
if ( $addon_settings
&& ! cerber_settings_update( array( CRB_ADDON_STS => $addon_settings ) ) ) {
cerber_admin_notice( 'Unable to upgrade add-on settings' );
}
delete_site_option( 'cerber_tmp_old_settings' );
}