label. * * @var array */ private $tabs = array(); /** * Get the single instance. * * @return BHTK_Admin */ public static function instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Hook into WordPress. */ private function __construct() { add_action( 'admin_menu', array( $this, 'register_menu' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'assets' ) ); add_action( 'admin_notices', array( $this, 'legacy_notice' ) ); add_action( 'admin_post_bhtk_save_modules', array( $this, 'handle_save_modules' ) ); add_action( 'admin_post_bhtk_save_settings', array( $this, 'handle_save_settings' ) ); add_action( 'admin_post_bhtk_toggle_module', array( $this, 'handle_toggle_module' ) ); add_action( 'admin_post_bhtk_save_module', array( $this, 'handle_save_module' ) ); add_filter( 'plugin_action_links_' . plugin_basename( BHTK_FILE ), array( $this, 'action_links' ) ); } /** * Add the toolkit menu and the pages of the enabled modules. * * @return void */ public function register_menu() { $cap = BHTK_Plugin::capability(); $icon = include BHTK_PATH . 'includes/menu-icon.php'; add_menu_page( 'Bani Honar Toolkit', 'Bani Honar Toolkit', $cap, self::SLUG, array( $this, 'render_dashboard' ), $icon, 58 ); $this->tabs[ self::SLUG ] = __( 'Dashboard', 'bani-honar-toolkit' ); add_submenu_page( self::SLUG, __( 'Dashboard', 'bani-honar-toolkit' ), __( 'Dashboard', 'bani-honar-toolkit' ), $cap, self::SLUG, array( $this, 'render_dashboard' ) ); $plugin = BHTK_Plugin::instance(); foreach ( $plugin->get_modules() as $id => $module ) { // A module that is off keeps its tab only when the tab carries its on/off switch. if ( ! $plugin->is_enabled( $id ) && ! $module->always_show_pages() ) { continue; } foreach ( $module->admin_pages() as $page ) { if ( empty( $page['slug'] ) || empty( $page['callback'] ) || ! is_callable( $page['callback'] ) ) { continue; } $title = isset( $page['title'] ) ? $page['title'] : $module->get_name(); $this->tabs[ $page['slug'] ] = $title; add_submenu_page( self::SLUG, $title, $title, $cap, $page['slug'], $page['callback'] ); } } $this->tabs[ self::SETTINGS_SLUG ] = __( 'Settings', 'bani-honar-toolkit' ); add_submenu_page( self::SLUG, __( 'Settings', 'bani-honar-toolkit' ), __( 'Settings', 'bani-honar-toolkit' ), $cap, self::SETTINGS_SLUG, array( $this, 'render_settings' ) ); $this->tabs[ BHTK_Contact::SLUG ] = __( 'Contact us', 'bani-honar-toolkit' ); add_submenu_page( self::SLUG, __( 'Contact us', 'bani-honar-toolkit' ), __( 'Contact us', 'bani-honar-toolkit' ), $cap, BHTK_Contact::SLUG, array( 'BHTK_Contact', 'render' ) ); } /** * Load the toolkit CSS and JS on its own screens and where a module asks for it. * * @param string $hook_suffix Current admin page hook suffix. * @return void */ public function assets( $hook_suffix ) { $needed = $this->is_toolkit_screen(); if ( ! $needed ) { foreach ( BHTK_Plugin::instance()->get_enabled_modules() as $module ) { if ( $module->needs_assets( $hook_suffix ) ) { $needed = true; break; } } } if ( ! $needed ) { return; } wp_enqueue_style( 'bhtk-admin', BHTK_URL . 'assets/css/admin.css', array(), BHTK_VERSION ); wp_enqueue_script( 'bhtk-admin', BHTK_URL . 'assets/js/admin.js', array(), BHTK_VERSION, true ); wp_localize_script( 'bhtk-admin', 'bhtkAdmin', BHTK_I18n::js_strings() ); } /** * Whether the current screen is one of ours. * * @return bool */ private function is_toolkit_screen() { $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended return self::SLUG === $page || 0 === strpos( $page, 'bhtk-' ); } /** * Quick link on the plugins list. * * @param array $links Existing links. * @return array */ public function action_links( $links ) { $mine = array( '' . esc_html__( 'Settings', 'bani-honar-toolkit' ) . '', ); return array_merge( $mine, $links ); } /** * Warn when the old BHAC plugin is still active next to this one. * * @return void */ public function legacy_notice() { if ( ! $this->is_toolkit_screen() || ! class_exists( 'BHAC_Links' ) ) { return; } echo '

'; esc_html_e( 'The older "BHAC" plugin is still active. Your links and settings were copied into Bani Honar Toolkit, so please deactivate the old plugin to avoid conflicts.', 'bani-honar-toolkit' ); echo '

'; } /** * Print the opening of a toolkit screen. * * @param string $active Slug of the current tab. * @return void */ public function render_header( $active ) { ?>

Bani Honar Toolkit

v
'error' === $type ? 'error' : 'success', 'msg' => (string) $message, 'copy' => (string) $copy, ), 120 ); } /** * Print and clear the remembered message. * * @return void */ public function render_flash() { $key = 'bhtk_flash_' . get_current_user_id(); $flash = get_transient( $key ); if ( ! is_array( $flash ) ) { return; } delete_transient( $key ); $message = ( '@settings_saved' === $flash['msg'] ) ? __( 'Settings saved.', 'bani-honar-toolkit' ) : $flash['msg']; ?>
403 ) ); } $plugin = BHTK_Plugin::instance(); $this->render_header( self::SLUG ); $this->render_flash(); ?>

get_modules() as $id => $module ) : ?> is_enabled( $id ); $pages = ( $on || $module->always_show_pages() ) ? $module->admin_pages() : array(); ?>

get_name() ); ?>

get_description() ); ?>

has_settings() ) : ?>

register_module( new My_Module() );\n} );" ); ?>
render_footer(); } /** * Save the module switches. * * @return void */ public function handle_save_modules() { if ( ! current_user_can( BHTK_Plugin::capability() ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'bani-honar-toolkit' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'bhtk_save_modules', '_bhtk_nonce' ); $ids = array(); if ( isset( $_POST['bhtk_modules'] ) && is_array( $_POST['bhtk_modules'] ) ) { $ids = array_map( 'sanitize_key', array_keys( wp_unslash( $_POST['bhtk_modules'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- keys are sanitized here. } BHTK_Plugin::instance()->set_enabled_modules( $ids ); self::flash( 'success', '@settings_saved' ); wp_safe_redirect( admin_url( 'admin.php?page=' . self::SLUG ) ); exit; } /** * Big on/off switch for one module, printed at the top of the module's own tab. * The form is sent as soon as the switch is flipped. * * @param BHTK_Module $module Module whose switch is shown. * @param string $page Slug of the tab the switch is on, used to come back to it. * @param string $view Optional view inside that tab. * @return void */ public function render_module_switch( $module, $page, $view = '' ) { $id = $module->get_id(); $on = BHTK_Plugin::instance()->is_enabled( $id ); ?>
get_name() ); ?> get_description() ); ?>
'' !== $page ? $page : self::SLUG ); if ( '' !== $view ) { $args['view'] = $view; } return add_query_arg( $args, admin_url( 'admin.php' ) ); } /** * Switch one module on or off from its own tab. * * @return void */ public function handle_toggle_module() { if ( ! current_user_can( BHTK_Plugin::capability() ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'bani-honar-toolkit' ), '', array( 'response' => 403 ) ); } $id = isset( $_POST['bhtk_module'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_module'] ) ) : ''; check_admin_referer( 'bhtk_toggle_module_' . $id, '_bhtk_nonce' ); $plugin = BHTK_Plugin::instance(); $modules = $plugin->get_modules(); if ( ! isset( $modules[ $id ] ) ) { wp_die( esc_html__( 'This module does not exist.', 'bani-honar-toolkit' ), '', array( 'response' => 400 ) ); } $on = ! empty( $_POST['bhtk_state'] ); $plugin->set_module_enabled( $id, $on ); self::flash( 'success', sprintf( /* translators: %s: module name */ $on ? __( '%s is now on.', 'bani-honar-toolkit' ) : __( '%s is now off.', 'bani-honar-toolkit' ), $modules[ $id ]->get_name() ) ); $page = isset( $_POST['bhtk_page'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_page'] ) ) : self::SLUG; $view = isset( $_POST['bhtk_view'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_view'] ) ) : ''; wp_safe_redirect( self::tab_url( $page, $view ) ); exit; } /** * Save the settings of one module from its own tab. * * @return void */ public function handle_save_module() { if ( ! current_user_can( BHTK_Plugin::capability() ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'bani-honar-toolkit' ), '', array( 'response' => 403 ) ); } $id = isset( $_POST['bhtk_module'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_module'] ) ) : ''; check_admin_referer( 'bhtk_save_module_' . $id, '_bhtk_nonce' ); $modules = BHTK_Plugin::instance()->get_modules(); if ( ! isset( $modules[ $id ] ) ) { wp_die( esc_html__( 'This module does not exist.', 'bani-honar-toolkit' ), '', array( 'response' => 400 ) ); } $raw = array(); if ( isset( $_POST['bhtk_mod'][ $id ] ) && is_array( $_POST['bhtk_mod'][ $id ] ) ) { $raw = wp_unslash( $_POST['bhtk_mod'][ $id ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- the module sanitizes its own values. } $modules[ $id ]->save_settings( $raw ); self::flash( 'success', '@settings_saved' ); $page = isset( $_POST['bhtk_page'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_page'] ) ) : self::SLUG; $view = isset( $_POST['bhtk_view'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_view'] ) ) : ''; wp_safe_redirect( self::tab_url( $page, $view ) ); exit; } /** * Settings screen: general options and one card per module that has settings. * * @return void */ public function render_settings() { if ( ! current_user_can( BHTK_Plugin::capability() ) ) { wp_die( esc_html__( 'You are not allowed to open this page.', 'bani-honar-toolkit' ), '', array( 'response' => 403 ) ); } $settings = BHTK_Plugin::settings(); $this->render_header( self::SETTINGS_SLUG ); $this->render_flash(); ?>

get_enabled_modules() as $module ) : ?> has_settings() ) : ?>

get_name() ); ?>

render_settings(); ?>

render_footer(); } /** * Save the general settings and the settings of every enabled module. * * @return void */ public function handle_save_settings() { if ( ! current_user_can( BHTK_Plugin::capability() ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'bani-honar-toolkit' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'bhtk_save_settings', '_bhtk_nonce' ); $settings = BHTK_Plugin::settings(); $language = isset( $_POST['bhtk_language'] ) ? sanitize_key( wp_unslash( $_POST['bhtk_language'] ) ) : 'auto'; $settings['language'] = in_array( $language, array( 'auto', 'fa', 'en' ), true ) ? $language : 'auto'; $settings['delete_data'] = empty( $_POST['bhtk_delete_data'] ) ? 0 : 1; BHTK_Plugin::update_settings( $settings ); $raw_modules = array(); if ( isset( $_POST['bhtk_mod'] ) && is_array( $_POST['bhtk_mod'] ) ) { $raw_modules = wp_unslash( $_POST['bhtk_mod'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- every module sanitizes its own values. } foreach ( BHTK_Plugin::instance()->get_enabled_modules() as $id => $module ) { if ( $module->has_settings() ) { $module->save_settings( isset( $raw_modules[ $id ] ) && is_array( $raw_modules[ $id ] ) ? $raw_modules[ $id ] : array() ); } } self::flash( 'success', '@settings_saved' ); wp_safe_redirect( admin_url( 'admin.php?page=' . self::SETTINGS_SLUG ) ); exit; } }