set_config( $plugin, $plugin_id, $text_domain, $label_transl ); $this->add_wp_callbacks(); } public function set_textdomain( $text_domain = null ) { if ( null !== $text_domain ) { $this->text_domain = $text_domain; } elseif ( ! empty( $this->p->cf[ 'plugin' ][ $this->plugin_id ][ 'text_domain' ] ) ) { $this->text_domain = $this->p->cf[ 'plugin' ][ $this->plugin_id ][ 'text_domain' ]; } } public function set_label_transl( $label_transl = false ) { if ( false !== $label_transl ) { $this->label_transl = $label_transl; } elseif ( ! empty( $this->p->cf[ 'notice' ][ 'title' ] ) ) { $this->label_transl = sprintf( __( '%s Notice', $this->text_domain ), _x( $this->p->cf[ 'notice' ][ 'title' ], 'notice title', $this->text_domain ) ); } else { $this->label_transl = __( 'Notice', $this->text_domain ); } } public function is_enabled() { return $this->enabled ? true : false; } public function enable( $state = true ) { $prev_state = $this->is_enabled(); $this->enabled = $state; return $prev_state; // Return the previous state to save and restore. } public function disable( $state = false ) { return $this->enable( $state ); // Return the previous state to save and restore. } /* * Note that only a single nag message is shown at a time. */ public function nag( $msg_text, $user_id = null, $notice_key = false, $dismiss_time = false, $payload = array() ) { $this->add_notice( 'nag', $msg_text, $user_id, $notice_key, $dismiss_time, $payload ); } public function err( $msg_text, $user_id = null, $notice_key = false, $dismiss_time = false, $payload = array() ) { $this->add_notice( 'err', $msg_text, $user_id, $notice_key, $dismiss_time, $payload ); } public function warn( $msg_text, $user_id = null, $notice_key = false, $dismiss_time = false, $payload = array() ) { $this->add_notice( 'warn', $msg_text, $user_id, $notice_key, $dismiss_time, $payload ); } public function inf( $msg_text, $user_id = null, $notice_key = false, $dismiss_time = false, $payload = array() ) { $this->add_notice( 'inf', $msg_text, $user_id, $notice_key, $dismiss_time, $payload ); } public function upd( $msg_text, $user_id = null, $notice_key = false, $dismiss_time = false, $payload = array() ) { $this->add_notice( 'upd', $msg_text, $user_id, $notice_key, $dismiss_time, $payload ); } /* * Clear a message type, message text, notice key from the notice cache, or clear all notices. */ public function clear( $msg_type = '', $notice_key = false, $user_id = null ) { $cur_uid = get_current_user_id(); // Always returns an integer. if ( is_array( $user_id ) ) { $clear_uids = $user_id; } else { $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. if ( empty( $user_id ) ) { // User ID is 0 (cron user, for example). return false; } $clear_uids = array( $user_id ); } unset( $user_id ); // A reminder that we are re-using this variable name below. $clear_types = empty( $msg_type ) ? $this->all_types : array( (string) $msg_type ); foreach ( $clear_uids as $user_id ) { $this->load_notice_cache( $user_id ); // Read and merge notices from transient cache. foreach ( $clear_types as $msg_type ) { if ( ! isset( $this->notice_cache[ $user_id ][ $msg_type ] ) ) { // Just in case. continue; } foreach ( $this->notice_cache[ $user_id ][ $msg_type ] as $msg_key => $payload ) { if ( empty( $notice_key ) || ( ! empty( $payload[ 'notice_key' ] ) && $notice_key === $payload[ 'notice_key' ] ) ) { $this->unload_notice_cache( $user_id, $msg_type, $msg_key ); } } } /* * Save the notice cache now. */ if ( $cur_uid !== $user_id ) { $this->update_notice_cache( $user_id ); } } } /* * Clear a single notice key from the notice cache. */ public function clear_key( $notice_key, $user_id = null ) { $this->clear( $msg_type = '', $notice_key, $user_id ); } /* * Set reference values for admin notices. */ public function set_ref( $url = null, $mod = false, $context_transl = null ) { $this->notice_info[] = array( 'url' => $url, 'mod' => $mod, 'context_transl' => $context_transl, ); return $url; } /* * Restore previous reference values for admin notices. */ public function unset_ref( $url = null ) { if ( null === $url || $this->is_ref_url( $url ) ) { array_pop( $this->notice_info ); return true; } return false; } public function get_ref( $ref_key = false, $text_prefix = '', $text_suffix = '' ) { $refs = end( $this->notice_info ); // Get the last reference added. if ( 'edit' === $ref_key ) { $link = ''; if ( ! empty( $refs[ 'mod' ] ) ) { if ( ! empty( $refs[ 'mod' ][ 'id' ] ) && is_numeric( $refs[ 'mod' ][ 'id' ] ) ) { if ( $refs[ 'mod' ][ 'is_comment' ] ) { $link = get_edit_comment_link( $refs[ 'mod' ][ 'id' ] ); } elseif ( $refs[ 'mod' ][ 'is_post' ] ) { $link = get_edit_post_link( $refs[ 'mod' ][ 'id' ], $display = false ); } elseif ( $refs[ 'mod' ][ 'is_user' ] ) { $link = get_edit_user_link( $refs[ 'mod' ][ 'id' ] ); } elseif ( $refs[ 'mod' ][ 'is_term' ] ) { $link = get_edit_term_link( $refs[ 'mod' ][ 'id' ], $refs[ 'mod' ][ 'tax_slug' ] ); } } } return empty( $link ) ? '' : $text_prefix . $link . $text_suffix; } elseif ( false !== $ref_key ) { if ( isset( $refs[ $ref_key ] ) ) { return $text_prefix . $refs[ $ref_key ] . $text_suffix; } return null; } return $refs; } public function get_ref_url_html() { $ref_html = ''; if ( $url = $this->get_ref( $ref_key = 'url' ) ) { /* * Show a shorter relative URL, if possible. */ $pretty_url = strtolower( str_replace( home_url(), '', $url ) ); $context_transl = $this->get_ref( $ref_key = 'context_transl' ); $context_transl = empty( $context_transl ) ? '' . $pretty_url . '' : '' . $context_transl . ''; /* * Returns an empty string or a clickable (Edit) link. */ $edit_html = $this->get_ref( $ref_key = 'edit', $text_prefix = ' (' . __( 'Edit', $this->text_domain ) . ')' ); $ref_html .= '

' . sprintf( __( 'Reference: %s', $this->text_domain ), $context_transl . $edit_html ) . '

'; } return $ref_html; } public function is_ref_url( $url = null ) { if ( null === $url || $url === $this->get_ref( $ref_key = 'url' ) ) { return true; } return false; } public function is_admin_pre_notices( $notice_key = false, $user_id = null ) { if ( is_admin() ) { if ( ! empty( $notice_key ) ) { /* * If notice is dismissed, say that we've already shown the notices. */ if ( $this->is_dismissed( $notice_key, $user_id ) ) { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( 'returning false: ' . $notice_key . ' is dismissed' ); } return false; } } if ( $this->has_shown ) { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( 'returning false: notices have been shown' ); } return false; } } else { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( 'returning false: is not admin' ); } return false; } return true; } public function clear_dismissed( $notice_key = false, $user_id = null ) { $this->is_dismissed( $notice_key, $user_id, $force_expire = true ); } public function reset_dismissed( $user_id = null ) { $cur_uid = get_current_user_id(); // Always returns an integer. $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. if ( $user_id ) { delete_user_option( $user_id, $this->dismiss_name, $global = false ); } } public function is_dismissed( $notice_keys = false, $user_id = null, $force_expire = false ) { if ( empty( $notice_keys ) || ! $this->can_dismiss() ) { // Just in case. return false; } $cur_uid = get_current_user_id(); // Always returns an integer. $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. if ( empty( $user_id ) ) { // User ID is 0 (cron user, for example). return false; } $user_dismissed = get_user_option( $this->dismiss_name, $user_id ); // Note that $user_id is the second argument. $update_dismissed = false; if ( ! is_array( $user_dismissed ) ) { // Nothing to do. return false; } if ( ! is_array( $notice_keys ) ) { $notice_keys = array( $notice_keys ); } foreach ( $notice_keys as $notice_key ) { if ( isset( $user_dismissed[ $notice_key ] ) ) { // Notice has been dismissed. $current_time = time(); $dismiss_time = $user_dismissed[ $notice_key ]; if ( ! $force_expire && ( empty( $dismiss_time ) || $dismiss_time > $current_time ) ) { return true; } unset( $user_dismissed[ $notice_key ] ); // Dismiss time has expired. $update_dismissed = true; } } if ( $update_dismissed ) { if ( empty( $user_dismissed ) ) { delete_user_option( $user_id, $this->dismiss_name, $global = false ); } else update_user_option( $user_id, $this->dismiss_name, $user_dismissed, $global = false ); } return false; } public function can_dismiss() { global $wp_version; if ( version_compare( $wp_version, '4.2', '>=' ) ) { return true; } return false; } /* * Hooked to the 'in_admin_header' action. * * The 'in_admin_header' action executes at the beginning of the content section in an admin page. */ public function admin_header_notices() { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->mark(); } add_action( 'all_admin_notices', array( $this, 'show_admin_notices' ), -1000 ); } public function show_admin_notices() { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->mark(); } $user_id = get_current_user_id(); // Always returns an integer. $notice_types = $this->all_types; echo $this->get_notice_style(); // Always include the notice styles in all admin webpages. /* * If toolbar notices are being used, exclude these from being shown. */ $toolbar_types = $this->get_toolbar_types(); // Returns false or array. if ( is_array( $toolbar_types ) ) { // Admin toolbar is available. if ( ! empty( $toolbar_types ) ) { $notice_types = array_diff( $notice_types, $toolbar_types ); } } elseif ( is_admin() ) { // Just in case. /* * SucomNotice->get_toolbar_types() will always return false for these types of requests. * * See is_admin_bar_showing() in wordpress/wp-includes/admin-bar.php for details. */ if ( defined( 'XMLRPC_REQUEST' ) || defined( 'DOING_AJAX' ) || defined( 'IFRAME_REQUEST' ) || wp_is_json_request() || is_embed() ) { return; } $msg_text = sprintf( __( 'The WordPress admin toolbar appears to be disabled (ie. the WordPress %s function returned false).', $this->text_domain ), 'is_admin_bar_showing()' ) . ' '; $msg_text .= __( 'As a consequence, showing discreet notices in the admin toolbar is not possible.', $this->text_domain ) . ' '; $msg_text .= __( 'Please diagnose the issue to re-enable the admin toolbar.', $this->text_domain ) . ' '; $notice_key = 'is_admin-is_admin_bar_showing-returned-false'; /* * Clear all notices and show only this error. */ $this->clear(); $this->err( $msg_text, $user_id, $notice_key ); } if ( empty( $notice_types ) ) { // Just in case. return; } /* * An alternative to the 'admin_head' action hook to add notices. */ $action_name = 'sucom_show_admin_notices'; if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( 'doing action \'' . $action_name . '\'' ); } do_action( 'sucom_show_admin_notices', $user_id ); /* * Exit early if this is a block editor page. The notices will be retrieved using an ajax call on page load * and post save. */ if ( SucomUtilWP::doing_block_editor() ) { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( 'exiting early: doing block editor is true' ); } return; } if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( 'doing block editor is false' ); } $nag_html = ''; $msg_html = ''; $user_dismissed = $user_id ? get_user_option( $this->dismiss_name, $user_id ) : false; // Note that $user_id is the second argument. $update_dismissed = false; $this->has_shown = true; $this->load_notice_cache( $user_id ); // Read and merge notices from transient cache. $this->load_update_notices( $user_id ); /* * Loop through all the msg types and show them all. */ foreach ( $notice_types as $msg_type ) { if ( ! isset( $this->notice_cache[ $user_id ][ $msg_type ] ) ) { // Just in case. continue; } foreach ( $this->notice_cache[ $user_id ][ $msg_type ] as $msg_key => $payload ) { $this->unload_notice_cache( $user_id, $msg_type, $msg_key ); if ( empty( $payload[ 'msg_text' ] ) ) { // Nothing to show. continue; } /* * Make sure the notice has not exceeded its TTL. * * A 'notice_ttl' value of 0 disables the notice message expiration. */ if ( ! empty( $payload[ 'notice_time' ] ) && ! empty( $payload[ 'notice_ttl' ] ) ) { if ( time() > $payload[ 'notice_time' ] + $payload[ 'notice_ttl' ] ) { continue; } } if ( ! empty( $payload[ 'dismiss_time' ] ) ) { // True or seconds greater than 0. /* * Check for automatically hidden errors and/or warnings. */ if ( ! empty( $payload[ 'notice_key' ] ) && isset( $user_dismissed[ $payload[ 'notice_key' ] ] ) ) { $current_time = time(); $dismiss_time = $user_dismissed[ $payload[ 'notice_key' ] ]; // Get time for key. if ( empty( $dismiss_time ) || $dismiss_time > $current_time ) { // 0 or time in future. $payload[ 'hidden' ] = true; } else { // Dismiss has expired. unset( $user_dismissed[ $payload[ 'notice_key' ] ] ); $update_dismissed = true; // Update the user meta when done. } } } if ( 'nag' === $msg_type ) { if ( empty( $nag_html ) ) { // Only show a single nag message at a time. $nag_html .= $this->get_notice_html( $msg_type, $payload ); } } else $msg_html .= $this->get_notice_html( $msg_type, $payload ); } } /* * Don't save unless we've changed something. */ if ( $user_id && $update_dismissed ) { if ( empty( $user_dismissed ) ) { delete_user_option( $user_id, $this->dismiss_name, $global = false ); } else update_user_option( $user_id, $this->dismiss_name, $user_dismissed, $global = false ); } echo "\n" . '' . "\n"; echo '
' . "\n"; echo $nag_html . "\n"; echo $msg_html . "\n"; echo '' . "\n"; if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->log( $this->plugin_id . ' admin notices end' ); } } public function ajax_get_notices_json() { $doing_ajax = SucomUtilWP::doing_ajax(); if ( ! $doing_ajax ) { // Just in case. return; } elseif ( SucomUtil::get_const( 'DOING_AUTOSAVE' ) ) { die( -1 ); } /* * Check nonce value before using $_REQUEST. */ check_ajax_referer( $this->nonce_name, '_ajax_nonce', $die = true ); $notice_types = $this->all_types; if ( ! empty( $_REQUEST[ '_notice_types' ] ) ) { if ( is_array( $_REQUEST[ '_notice_types' ] ) ) { $notice_types = $_REQUEST[ '_notice_types' ]; } else $notice_types = explode( ',', $_REQUEST[ '_notice_types' ] ); } if ( ! empty( $_REQUEST[ '_exclude_types' ] ) ) { if ( is_array( $_REQUEST[ '_exclude_types' ] ) ) { $exclude_types = $_REQUEST[ '_exclude_types' ]; } else $exclude_types = explode( ',', $_REQUEST[ '_exclude_types' ] ); $notice_types = array_diff( $notice_types, $exclude_types ); } if ( empty( $notice_types ) ) { // Just in case. die( -1 ); } $user_id = get_current_user_id(); // Always returns an integer. $user_dismissed = $user_id ? get_user_option( $this->dismiss_name, $user_id ) : false; // Note that $user_id is the second argument. $update_dismissed = false; $json_notices = array(); $ajax_context = empty( $_REQUEST[ 'context' ] ) ? '' : $_REQUEST[ 'context' ]; // 'block_editor' or 'toolbar_notices' $this->has_shown = true; $this->load_notice_cache( $user_id ); // Read and merge notices from transient cache. $this->load_update_notices( $user_id ); /* * Loop through all the msg types and show them all. */ foreach ( $notice_types as $msg_type ) { if ( ! isset( $this->notice_cache[ $user_id ][ $msg_type ] ) ) { // Just in case. continue; } foreach ( $this->notice_cache[ $user_id ][ $msg_type ] as $msg_key => $payload ) { $this->unload_notice_cache( $user_id, $msg_type, $msg_key ); if ( empty( $payload[ 'msg_text' ] ) ) { // Nothing to show. continue; } /* * Make sure the notice has not exceeded its TTL. * * A 'notice_ttl' value of 0 disables the notice message expiration. */ if ( ! empty( $payload[ 'notice_time' ] ) && ! empty( $payload[ 'notice_ttl' ] ) ) { if ( time() > $payload[ 'notice_time' ] + $payload[ 'notice_ttl' ] ) { continue; } } if ( ! empty( $payload[ 'dismiss_time' ] ) ) { // True or seconds greater than 0. /* * Check for automatically hidden errors and/or warnings. */ if ( ! empty( $payload[ 'notice_key' ] ) && isset( $user_dismissed[ $payload[ 'notice_key' ] ] ) ) { $current_time = time(); $dismiss_time = $user_dismissed[ $payload[ 'notice_key' ] ]; // Get time for key. if ( empty( $dismiss_time ) || $dismiss_time > $current_time ) { // 0 or time in future. $payload[ 'hidden' ] = true; } else { // Dismiss has expired. unset( $user_dismissed[ $payload[ 'notice_key' ] ] ); $update_dismissed = true; // Update the user meta when done. } } } $payload[ 'msg_html' ] = $this->get_notice_html( $msg_type, $payload, $notice_alt = true ); $json_notices[ $msg_type ][ $msg_key ] = $payload; } } /* * Don't save unless we've changed something. */ if ( $user_id && $update_dismissed ) { if ( empty( $user_dismissed ) ) { delete_user_option( $user_id, $this->dismiss_name, $global = false ); } else update_user_option( $user_id, $this->dismiss_name, $user_dismissed, $global = false ); } $json_encoded = wp_json_encode( $json_notices ); die( $json_encoded ); } public function ajax_dismiss_notice() { $doing_ajax = SucomUtilWP::doing_ajax(); if ( ! $doing_ajax ) { // Just in case. return; } $user_id = get_current_user_id(); // Always returns an integer. $dismiss_info = array(); if ( empty( $user_id ) || ! current_user_can( 'edit_user', $user_id ) ) { die( -1 ); } check_ajax_referer( __FILE__, 'dismiss_nonce', $die = true ); /* * Quick sanitation of input values. */ foreach ( array( 'notice_key', 'dismiss_time' ) as $key ) { $dismiss_info[ $key ] = sanitize_text_field( filter_input( INPUT_POST, $key ) ); } if ( empty( $dismiss_info[ 'notice_key' ] ) ) { // Just in case. die( -1 ); } $user_dismissed = get_user_option( $this->dismiss_name, $user_id ); // Note that $user_id is the second argument. if ( ! is_array( $user_dismissed ) ) { $user_dismissed = array(); } if ( empty( $dismiss_info[ 'dismiss_time' ] ) || ! is_numeric( $dismiss_info[ 'dismiss_time' ] ) ) { $user_dismissed[ $dismiss_info[ 'notice_key' ] ] = 0; } else { $user_dismissed[ $dismiss_info[ 'notice_key' ] ] = time() + $dismiss_info[ 'dismiss_time' ]; } update_user_option( $user_id, $this->dismiss_name, $user_dismissed, $global = false ); die( '1' ); } /* * Returns false or an array of notice types to include in the toolbar menu. * * Called by WpssoScript->get_admin_page_script_data() to define the types shown for ajax calls. */ public function get_toolbar_types() { /* * is_admin_bar_showing() should always return true in the back-end for a standard request (ie. not xmlrpc, ajax, iframe). */ $toolbar_types = is_admin_bar_showing() ? $this->toolbar_types : false; $toolbar_types = apply_filters( 'sucom_toolbar_notice_types', $toolbar_types ); return $toolbar_types; } public function admin_footer_script() { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->mark(); } echo $this->get_notice_script(); } /* * Called by the WordPress 'shutdown' action. Save notices for all user IDs in the notice cache. */ public function shutdown_notice_cache() { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->mark(); } foreach ( $this->notice_cache as $user_id => $msg_types ) { $this->update_notice_cache( $user_id ); } } /* * Set property values for text domain, notice label, etc. */ private function set_config( $plugin = null, $plugin_id = null, $text_domain = null, $label_transl = false ) { if ( null !== $plugin ) { $this->p =& $plugin; if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->mark(); } } /* * Set the lower and upper case acronyms. */ if ( null !== $plugin_id ) { $this->plugin_id = $plugin_id; } elseif ( ! empty( $this->p->id ) ) { $this->plugin_id = $this->p->id; } $this->plugin_ucid = strtoupper( $this->plugin_id ); /* * Set the text domain. */ $this->set_textdomain( $text_domain ); /* * Set the dismiss key name. */ if ( defined( $this->plugin_ucid . '_DISMISS_NAME' ) ) { $this->dismiss_name = constant( $this->plugin_ucid . '_DISMISS_NAME' ); } else { $this->dismiss_name = $this->plugin_id . '_dismissed'; } /* * Set the notices key name. */ if ( defined( $this->plugin_ucid . '_NOTICES_NAME' ) ) { $this->notices_name = constant( $this->plugin_ucid . '_NOTICES_NAME' ); } else { $this->notices_name = $this->plugin_id . '_notices'; } /* * Set the nonce key name. */ if ( defined( $this->plugin_ucid . '_NONCE_NAME' ) ) { $this->nonce_name = constant( $this->plugin_ucid . '_NONCE_NAME' ); } elseif ( defined( 'NONCE_KEY' ) ) { $this->nonce_name = NONCE_KEY; } /* * Set the translated notice label. */ $this->set_label_transl( $label_transl ); } /* * Add WordPress action and filter callbacks. */ private function add_wp_callbacks() { static $do_once = null; if ( $do_once ) return; // Stop here. $do_once = true; $doing_cron = defined( 'DOING_CRON' ) ? DOING_CRON : false; if ( is_admin() ) { add_action( 'wp_ajax_' . $this->plugin_id . '_dismiss_notice', array( $this, 'ajax_dismiss_notice' ) ); add_action( 'wp_ajax_' . $this->plugin_id . '_get_notices_json', array( $this, 'ajax_get_notices_json' ) ); /* * The 'in_admin_header' action executes at the beginning of the content section in an admin page. */ add_action( 'in_admin_header', array( $this, 'admin_header_notices' ), PHP_INT_MAX ); add_action( 'admin_footer', array( $this, 'admin_footer_script' ) ); } if ( is_admin() || $doing_cron ) { add_action( 'shutdown', array( $this, 'shutdown_notice_cache' ), -2000, 0 ); } } /* * $msg_text can be a single text string, or an array of text strings. */ private function add_notice( $msg_type, $msg_text, $user_id = null, $notice_key = false, $dismiss_time = false, $payload = array() ) { if ( ! $this->enabled ) { // Just in case. return false; } /* * If $msg_text is an array of text strings, implode the array into a single text string. */ $msg_text = is_array( $msg_text ) ? implode( $glue = ' ', $msg_text ) : (string) $msg_text; $msg_text = trim( $msg_text ); if ( empty( $msg_type ) || empty( $msg_text ) ) { return false; } $cur_uid = get_current_user_id(); // Always returns an integer. $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. if ( empty( $user_id ) ) { // User ID is 0 (cron user, for example). return false; } $payload[ 'user_id' ] = $user_id; $payload[ 'notice_label' ] = isset( $payload[ 'notice_label' ] ) ? $payload[ 'notice_label' ] : $this->label_transl; $payload[ 'notice_key' ] = empty( $notice_key ) ? false : sanitize_key( $notice_key ); $payload[ 'notice_time' ] = time(); /* * 0 disables notice expiration. */ $payload[ 'notice_ttl' ] = isset( $payload[ 'notice_ttl' ] ) ? (int) $payload[ 'notice_ttl' ] : $this->default_ttl; $payload[ 'dismiss_time' ] = false; $payload[ 'dismiss_diff' ] = isset( $payload[ 'dismiss_diff' ] ) ? $payload[ 'dismiss_diff' ] : null; /* * Add dismiss text for dismiss button and notice message. */ if ( $this->can_dismiss() ) { $payload[ 'dismiss_time' ] = $dismiss_time; // Maybe true, false, 0, or seconds greater than 0. if ( null === $payload[ 'dismiss_diff' ] ) { // Has not been provided, so set a default value. $dismiss_suffix_msg = false; if ( true === $payload[ 'dismiss_time' ] ) { // True. $payload[ 'dismiss_diff' ] = __( 'Forever', $this->text_domain ); $dismiss_suffix_msg = __( 'This notice can be dismissed permanently.', $this->text_domain ); } elseif ( empty( $payload[ 'dismiss_time' ] ) ) { // False or 0 seconds. $payload[ 'dismiss_time' ] = false; $payload[ 'dismiss_diff' ] = false; } elseif ( is_numeric( $payload[ 'dismiss_time' ] ) ) { // Seconds greater than 0. $payload[ 'dismiss_diff' ] = human_time_diff( 0, $payload[ 'dismiss_time' ] ); $dismiss_suffix_msg = __( 'This notice can be dismissed for %s.', $this->text_domain ); } if ( ! empty( $payload[ 'dismiss_diff' ] ) && $dismiss_suffix_msg ) { $msg_close_div = ''; if ( '' === substr( $msg_text, -6 ) ) { $msg_text = substr( $msg_text, 0, -6 ); $msg_close_div = ''; } $msg_add_p = '

' === substr( $msg_text, -4 ) ? true : false; $msg_text .= $msg_add_p || $msg_close_div ? '

' : ' '; $msg_text .= sprintf( $dismiss_suffix_msg, $payload[ 'dismiss_diff' ] ); $msg_text .= $msg_add_p || $msg_close_div ? '

' : ''; $msg_text .= $msg_close_div; } } } /* * Maybe add a reference URL at the end. */ $msg_text .= $this->get_ref_url_html(); $payload[ 'msg_text' ] = preg_replace( '/(.*?)/Us', ' ', $msg_text ); $payload[ 'msg_spoken' ] = preg_replace( '/(.*?)/Us', ' ', $msg_text ); $payload[ 'msg_spoken' ] = SucomUtil::decode_html( SucomUtil::strip_html( $payload[ 'msg_spoken' ] ) ); $msg_key = empty( $payload[ 'notice_key' ] ) ? sanitize_key( $payload[ 'msg_spoken' ] ) : $payload[ 'notice_key' ]; $this->notice_cache[ $user_id ][ $msg_type ][ $msg_key ] = $payload; /* * Save the notice cache now. */ if ( $cur_uid !== $user_id ) { $this->update_notice_cache( $user_id ); } } private function unload_notice_cache( $user_id, $msg_type, $msg_key ) { unset( $this->notice_cache[ $user_id ][ $msg_type ][ $msg_key ] ); if ( empty( $this->notice_cache[ $user_id ][ $msg_type ] ) ) { unset( $this->notice_cache[ $user_id ][ $msg_type ] ); } $this->notice_noload[ $user_id ][ $msg_type ][ $msg_key ] = true; } /* * Merge notice cache with saved notices (without overwriting). */ private function load_notice_cache( $user_id = null ) { $cur_uid = get_current_user_id(); // Always returns an integer. $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. $result = $this->get_notice_cache( $user_id ); // Always returns an array. if ( ! empty( $result ) ) { foreach ( $this->all_types as $msg_type ) { if ( ! empty( $result[ $msg_type ] ) ) { foreach ( $result[ $msg_type ] as $msg_key => $payload ) { if ( ! isset( $this->notice_cache[ $user_id ][ $msg_type ][ $msg_key ] ) && ! isset( $this->notice_noload[ $user_id ][ $msg_type ][ $msg_key ] ) ) { $this->notice_cache[ $user_id ][ $msg_type ][ $msg_key ] = $payload; $this->notice_noload[ $user_id ][ $msg_type ][ $msg_key ] = true; } } } } } } private function load_update_notices( $user_id ) { if ( ! class_exists( 'SucomUpdate' ) ) { return; } elseif ( empty( $this->p->cf[ 'plugin' ] ) ) { // Just in case. return; } foreach ( $this->p->cf[ 'plugin' ] as $ext => $info ) { if ( SucomUpdate::is_configured( $ext ) ) { foreach ( array( 'inf', 'err' ) as $type ) { if ( $msg = SucomUpdate::get_umsg( $ext, $type ) ) { $msg_text = preg_replace( '/(.*?)/Us', ' ', $msg ); $msg_spoken = preg_replace( '/(.*?)/Us', ' ', $msg ); $msg_spoken = SucomUtil::decode_html( SucomUtil::strip_html( $msg_spoken ) ); $msg_key = sanitize_key( $msg_spoken ); $this->notice_cache[ $user_id ][ $type ][ $msg_key ] = array( 'notice_label' => $this->label_transl, 'notice_key' => $msg_key, 'msg_text' => $msg_text, 'msg_spoken' => $msg_spoken, ); } } } } } private function update_notice_cache( $user_id = null ) { $cur_uid = get_current_user_id(); // Always returns an integer. $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. $update = true; $result = false; if ( ! empty( $user_id ) ) { // Just in case. if ( $cur_uid !== $user_id ) { $this->load_notice_cache( $user_id ); // Read and merge notices from transient cache. } $result = update_user_option( $user_id, $this->notices_name, $this->notice_cache[ $user_id ], $global = false ); } $this->notice_cache[ $user_id ] = array(); return $result; } private function get_notice_cache( $user_id = null ) { $cur_uid = get_current_user_id(); // Always returns an integer. $user_id = is_numeric( $user_id ) ? (int) $user_id : $cur_uid; // $user_id can be true, false, null, or numeric. $result = array(); if ( ! empty( $user_id ) ) { // Nothing to do. $result = get_user_option( $this->notices_name, $user_id ); if ( ! is_array( $result ) ) { // Always return an array. $result = array(); } } return $result; } /* * Use a reference for the $payload variable so we can modify the 'msg_text' element and remove text that should be * shown only once. */ private function get_notice_html( $msg_type, array &$payload, $notice_alt = false ) { /* * Add an 'inline' class in toolbar notices to prevent WordPress from moving the notice. * * See wordpress/wp-admin/js/common.js:1083 */ $notice_type = $notice_alt ? 'notice notice-alt inline' : 'notice'; $notice_display = 'block'; switch ( $msg_type ) { case 'nag': $payload[ 'notice_label' ] = ''; // No label for nag notices. $msg_type = 'nag'; $css_class = 'update-nag'; break; case 'err': case 'error': $msg_type = 'err'; $css_class = $notice_type . ' notice-error error'; break; case 'warn': case 'warning': $msg_type = 'warn'; $css_class = $notice_type . ' notice-warning'; break; case 'inf': case 'info': $msg_type = 'inf'; $css_class = $notice_type . ' notice-info'; break; case 'upd': case 'updated': $msg_type = 'upd'; $css_class = $notice_type . ' notice-success updated'; break; default: // Unknown $msg_type. $msg_type = 'unknown'; $css_class = $notice_type; break; } $css_id_attr = empty( $payload[ 'notice_key' ] ) ? '' : ' id="' . $msg_type . '-' . $payload[ 'notice_key' ] . '"'; $is_dismissible = empty( $payload[ 'dismiss_time' ] ) ? false : true; $data_attr = ''; if ( $is_dismissible ) { $data_attr .= ' data-notice-key="' . ( isset( $payload[ 'notice_key' ] ) ? esc_attr( $payload[ 'notice_key' ] ) : '' ). '"'; $data_attr .= ' data-dismiss-time="' . ( isset( $payload[ 'dismiss_time' ] ) && is_numeric( $payload[ 'dismiss_time' ] ) ? esc_attr( $payload[ 'dismiss_time' ] ) : 0 ) . '"'; $data_attr .= ' data-dismiss-nonce="' . wp_create_nonce( __FILE__ ) . '"'; } $style_attr = ' style="' . ( empty( $payload[ 'style' ] ) ? '' : $payload[ 'style' ] ) . ( empty( $payload[ 'hidden' ] ) ? 'display:' . $notice_display . ' !important;' : 'display:none !important;' ) . '"'; $msg_html = '
'; // Display block or none. /* * Float the dismiss button on the right, so the button must be added first. */ if ( ! empty( $payload[ 'dismiss_diff' ] ) && $is_dismissible ) { $msg_html .= ''; } /* * The notice label can be false, an empty string, or translated string. */ if ( ! empty( $payload[ 'notice_label' ] ) ) { $msg_html .= '
' . $payload[ 'notice_label' ] . '
'; } /* * Check to see if there's a section that should be shown only once. */ if ( preg_match( '/.*/Us', $payload[ 'msg_text' ], $matches ) ) { static $show_once = array(); $match_md5 = md5( $matches[ 0 ] ); /* * Remove the "show once" text if it has already been shown, or remove it from dismisible and * dismissed notices, so it can be shown in a later notice. */ if ( isset( $show_once[ $match_md5 ] ) || ( $is_dismissible && $this->is_dismissed( $payload[ 'notice_key' ] ) ) ) { /* * The $payload is a reference variable so we can modify the 'msg_text' element and remove * text that should be shown only once. */ $payload[ 'msg_text' ] = str_replace( $matches[ 0 ], '', $payload[ 'msg_text' ] ); } else { $show_once[ $match_md5 ] = true; } } $msg_html .= '
' . $payload[ 'msg_text' ] . '
'; $msg_html .= '
' . "\n"; return $msg_html; } /* * Refresh the minimized notice stylesheet. * * See WpssoUtilCache->refresh(). */ public function refresh_notice_style() { $this->get_notice_style( $read_cache = false ); } /* * See SucomNotice->show_admin_notices(). */ private function get_notice_style( $read_cache = true ) { global $wp_version; $cache_md5_pre = $this->plugin_id . '_'; $cache_exp_secs = WEEK_IN_SECONDS; $cache_salt = __METHOD__ . '(wp_version:' . $wp_version . ')'; $cache_id = $cache_md5_pre . md5( $cache_salt ); if ( $read_cache ) { if ( ! SucomUtilWP::doing_dev() ) { if ( $custom_style_css = get_transient( $cache_id ) ) { return ''; } } } $custom_style_css = ' body.wp-admin.has-toolbar-notices #wpadminbar, body.wp-admin.is-fullscreen-mode.has-toolbar-notices #wpadminbar, body.wp-admin.is-wp-toolbar-disabled.has-toolbar-notices #wpadminbar, body.wp-admin.woocommerce-embed-page.has-toolbar-notices #wpadminbar { display:block !important; } body.wp-admin.is-fullscreen-mode.has-toolbar-notices .block-editor__container { min-height:calc(100vh - 32px); } body.wp-admin.is-fullscreen-mode.has-toolbar-notices .interface-interface-skeleton { top:32px; } body.wp-admin.is-fullscreen-mode.has-toolbar-notices .block-editor__container .block-editor-editor-skeleton, body.wp-admin.is-fullscreen-mode.has-toolbar-notices .block-editor__container .block-editor-editor-skeleton .editor-post-publish-panel { top:32px; } @keyframes blinker { 25% { opacity: 0; } 75% { opacity: 1; } } .components-notice-list .' . $this->plugin_id . '-notice { margin:0; min-height:0; -webkit-box-shadow:none; -moz-box-shadow:none; box-shadow:none; } .components-notice-list .is-dismissible .' . $this->plugin_id . '-notice { padding-right:30px; } .components-notice-list .' . $this->plugin_id . '-notice *, #wpadminbar .' . $this->plugin_id . '-notice *, .' . $this->plugin_id . '-notice * { line-height:1.4em; } .components-notice-list .' . $this->plugin_id . '-notice .notice-label, .components-notice-list .' . $this->plugin_id . '-notice .notice-message, .components-notice-list .' . $this->plugin_id . '-notice .notice-dismiss { padding:8px; margin:0; border:0; background:inherit; } #wpadminbar #wp-toolbar li.has-toolbar-notices.show-timeout div.ab-sub-wrapper { display:block; } #wpadminbar #wp-toolbar li.has-toolbar-notices div.ab-item { color:inherit !important; background:inherit !important; } #wpadminbar #wp-toolbar li.has-toolbar-notices #' . $this->plugin_id . '-toolbar-notices-icon.ab-icon::before { color:#fff; /* White on background color. */ background-color:inherit; } #wpadminbar #wp-toolbar li.has-toolbar-notices #' . $this->plugin_id . '-toolbar-notices-count { color:#fff; /* White on background color. */ background-color:inherit; } #wpadminbar #wp-toolbar li.has-toolbar-notices.toolbar-notices-error { background-color:#dc3232; /* Red. */ } #wpadminbar #wp-toolbar li.has-toolbar-notices.toolbar-notices-warning { background-color:#ffb900; /* Yellow. */ } #wpadminbar #wp-toolbar li.has-toolbar-notices.toolbar-notices-info { background-color:#00a0d2; /* Blue. */ } #wpadminbar #wp-toolbar li.has-toolbar-notices.toolbar-notices-success { background-color:#46b450; /* Green. */ } #wpadminbar #wp-toolbar #wp-admin-bar-' . $this->plugin_id . '-toolbar-notices .ab-sub-wrapper { color:#c3c4c7; background-color:rgb(30, 30, 30); } #wpadminbar #wp-toolbar li.has-toolbar-notices #wp-admin-bar-' . $this->plugin_id . '-toolbar-notices-default { padding:0; } #wpadminbar #wp-toolbar li.has-toolbar-notices #wp-admin-bar-' . $this->plugin_id . '-toolbar-notices-container { min-width:60vw; /* Minimum width. */ max-height:90vh; /* Minimum height. */ overflow-y:scroll; } #wpadminbar #wp-toolbar li.has-toolbar-notices.show-timeout #wp-admin-bar-' . $this->plugin_id . '-toolbar-notices-container { max-height:20vh; /* Minimum height with timeout. */ } #wpadminbar .' . $this->plugin_id . '-notice, #wpadminbar .' . $this->plugin_id . '-notice.error, #wpadminbar .' . $this->plugin_id . '-notice.updated, .' . $this->plugin_id . '-notice, .' . $this->plugin_id . '-notice.error, .' . $this->plugin_id . '-notice.updated { clear:both; padding:0; -webkit-box-shadow:none; -moz-box-shadow:none; box-shadow:none; } #wpadminbar .' . $this->plugin_id . '-notice, #wpadminbar .' . $this->plugin_id . '-notice.error, #wpadminbar .' . $this->plugin_id . '-notice.updated { background:inherit; border-bottom:none; border-right:none; } #wpadminbar .' . $this->plugin_id . '-notice > div, #wpadminbar .' . $this->plugin_id . '-notice.error > div, #wpadminbar .' . $this->plugin_id . '-notice.updated > div { min-height:50px; } #wpadminbar .' . $this->plugin_id . '-notice.notice.notice-alt { display:block !important; /* Fix Squirrly SEO display:none !important. */ position:static !important; /* Fix Squirrly SEO position:absolute !important. */ top:inherit !important; /* Fix Squirrly SEO top:-1000px !important. */ height:auto !important; /* Fix Squirrly SEO height:0 !important. */ } #wpadminbar div.' . $this->plugin_id . '-notice.notice-copy { font-size:0.9em; line-height:1; text-align:center; min-height:auto; } #wpadminbar div.' . $this->plugin_id . '-notice.notice-copy > div { min-height:auto; } #wpadminbar div.' . $this->plugin_id . '-notice.notice-copy div.notice-message { display:inline-block; padding:5px 20px; } #wpadminbar div.' . $this->plugin_id . '-notice.notice-copy div.notice-message a { font-size:0.9em; font-weight:200; letter-spacing:0.2px; } #wpadminbar div.' . $this->plugin_id . '-notice a, .' . $this->plugin_id . '-notice a { display:inline; text-decoration:underline; padding:0; } #wpadminbar div.' . $this->plugin_id . '-notice .notice-label, #wpadminbar div.' . $this->plugin_id . '-notice .notice-message, #wpadminbar div.' . $this->plugin_id . '-notice .notice-dismiss { position:relative; display:table-cell; padding:20px; margin:0; border:none; vertical-align:top; background:inherit; } @media screen and ( max-width:1200px ) { #wpadminbar div.' . $this->plugin_id . '-notice .notice-label { display:none; } } .' . $this->plugin_id . '-notice div.notice-actions { text-align:center; margin:20px 0 15px 0; } .' . $this->plugin_id . '-notice div.notice-single-button { display:inline-block; vertical-align:top; margin:5px; } .' . $this->plugin_id . '-notice .notice-label, .' . $this->plugin_id . '-notice .notice-message, .' . $this->plugin_id . '-notice .notice-dismiss { position:relative; display:table-cell; padding:15px 20px; margin:0; border:none; vertical-align:top; } .' . $this->plugin_id . '-notice .notice-dismiss-text { color:#c3c4c7; } .' . $this->plugin_id . '-notice .notice-dismiss::before { color:#c3c4c7; font-size:18px; display:inline-block; padding:2px; } .' . $this->plugin_id . '-notice .notice-dismiss:hover::before { color:#d63638; } .components-notice-list .' . $this->plugin_id . '-notice .notice-dismiss, #wpadminbar .' . $this->plugin_id . '-notice .notice-dismiss, .' . $this->plugin_id . '-notice .notice-dismiss { clear:both; /* Clear the "Screen Options" tab in nags. */ display:block; float:right; top:0; right:0; padding-left:0; padding-bottom:15px; } #wpadminbar .' . $this->plugin_id . '-notice .notice-label, .' . $this->plugin_id . '-notice .notice-label { font-weight:600; color:#444; /* Default text color. */ background-color:#fcfcfc; /* Default background color. */ white-space:nowrap; } #wpadminbar .' . $this->plugin_id . '-notice.notice-error .notice-label, .' . $this->plugin_id . '-notice.notice-error .notice-label { background-color:#fbeaea; } #wpadminbar .' . $this->plugin_id . '-notice.notice-warning .notice-label, .' . $this->plugin_id . '-notice.notice-warning .notice-label { background-color:#fff8e5; } #wpadminbar .' . $this->plugin_id . '-notice.notice-info .notice-label, .' . $this->plugin_id . '-notice.notice-info .notice-label { background-color:#e5f5fa; } #wpadminbar .' . $this->plugin_id . '-notice.notice-success .notice-label, .' . $this->plugin_id . '-notice.notice-success .notice-label { background-color:#ecf7ed; } .' . $this->plugin_id . '-notice.notice-success .notice-label::before, .' . $this->plugin_id . '-notice.notice-info .notice-label::before, .' . $this->plugin_id . '-notice.notice-warning .notice-label::before, .' . $this->plugin_id . '-notice.notice-error .notice-label::before { font-family:"Dashicons"; font-size:1.2em; vertical-align:bottom; margin-right:6px; } .' . $this->plugin_id . '-notice.notice-error .notice-label::before { content:"\f488"; /* megaphone */ } .' . $this->plugin_id . '-notice.notice-warning .notice-label::before { content:"\f227"; /* flag */ } .' . $this->plugin_id . '-notice.notice-info .notice-label::before { content:"\f537"; /* sticky */ } .' . $this->plugin_id . '-notice.notice-success .notice-label::before { content:"\f147"; /* yes */ } #wpadminbar .' . $this->plugin_id . '-notice .notice-message h2, .' . $this->plugin_id . '-notice .notice-message h2 { font-size:1.2em; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message h3, .' . $this->plugin_id . '-notice .notice-message h3 { font-size:1.1em; margin-top:1.2em; margin-bottom:0.8em; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message code, .' . $this->plugin_id . '-notice .notice-message code { font-family:"Courier", monospace; font-size:1em; vertical-align:middle; padding:0 2px; margin:0; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message a, .' . $this->plugin_id . '-notice .notice-message a { display:inline; text-decoration:underline; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message a code, .' . $this->plugin_id . '-notice .notice-message a code { padding:0; vertical-align:middle; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message p, #wpadminbar .' . $this->plugin_id . '-notice .notice-message pre, .' . $this->plugin_id . '-notice .notice-message p, .' . $this->plugin_id . '-notice .notice-message pre { color:inherit; margin:0.8em 0 0 0; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message .top, .' . $this->plugin_id . '-notice .notice-message .top { margin-top:0; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message p.reference-message, .' . $this->plugin_id . '-notice .notice-message p.reference-message { color:#c3c4c7; font-size:0.9em; margin:10px 0 0 0; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message p.reference-message a { font-size:0.9em; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message p.smaller-message, #wpadminbar .' . $this->plugin_id . '-notice .notice-message p.smaller-message a, .' . $this->plugin_id . '-notice .notice-message p.smaller-message, .' . $this->plugin_id . '-notice .notice-message p.smaller-message a { font-size:0.9em; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message ul, .' . $this->plugin_id . '-notice .notice-message ul { margin:1em 0 1em 3em; list-style:disc outside none; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message ol, .' . $this->plugin_id . '-notice .notice-message ol { margin:1em 0 1em 3em; list-style:decimal outside none; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message li, .' . $this->plugin_id . '-notice .notice-message li { text-align:left; margin:5px 0 5px 0; padding-left:0.8em; list-style:inherit; } #wpadminbar .' . $this->plugin_id . '-notice .notice-message b, #wpadminbar .' . $this->plugin_id . '-notice .notice-message b a, #wpadminbar .' . $this->plugin_id . '-notice .notice-message strong, #wpadminbar .' . $this->plugin_id . '-notice .notice-message strong a, .' . $this->plugin_id . '-notice .notice-message b, .' . $this->plugin_id . '-notice .notice-message b a, .' . $this->plugin_id . '-notice .notice-message strong, .' . $this->plugin_id . '-notice .notice-message strong a { font-weight:600; } #wpadminbar .' . $this->plugin_id . '-notice .notice-dismiss .notice-dismiss-text, .' . $this->plugin_id . '-notice .notice-dismiss .notice-dismiss-text { display:inline-block; font-size:12px; padding:2px; vertical-align:top; white-space:nowrap; } .' . $this->plugin_id . '-notice .notice-message .button-highlight { border-color:#0074a2; background-color:#daeefc; } .' . $this->plugin_id . '-notice .notice-message .button-highlight:hover { background-color:#c8e6fb; } '; if ( ! SucomUtilWP::doing_dev() ) { $custom_style_css = SucomUtil::minify_css( $custom_style_css, $this->plugin_id ); set_transient( $cache_id, $custom_style_css, $cache_exp_secs ); } return ''; } private function get_notice_script() { if ( ! empty( $this->p->debug->enabled ) ) { $this->p->debug->mark(); } return ' ' . "\n"; } } }