-
-
Save gschoppe/dd7d12577974166529ea0139f1f53939 to your computer and use it in GitHub Desktop.
<?php if( !defined( 'ABSPATH' ) ) { die(); } // Include in all php files, to prevent direct execution | |
/** | |
* Class Name : WP Persistent Notices | |
* Description : Implements a Standardized messaging system that allows admin messages to be passed across page redirects. | |
* Class URI : http://gschoppe.com/wordpress/pass-wordpress-admin-notices-across-page-redirects/ | |
* Version : 1.0.0 | |
* Author : Greg Schoppe | |
* Author URI : http://gschoppe.com | |
* License: GPL-2.0+ | |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt | |
**/ | |
if( !class_exists( 'WP_Persistent_Notices' ) ) { | |
class WP_Persistent_Notices { // replace ClassName with the name of your class | |
private static $_this; | |
private $session_var = 'wp_persistent_notices'; | |
private $max_age; | |
private $default_notice; | |
private $notices; | |
public static function Instance() { | |
static $instance = null; | |
if ( $instance === null ) { | |
$instance = new self(); | |
} | |
return $instance; | |
} | |
private function __construct() { | |
$this->max_age = max( intval( ini_get( 'max_execution_time' ) ) * 2, 30 ); | |
$this->notices = array(); | |
$this->default_notice = array( | |
'id' => '', | |
'type' => 'info', | |
'custom_class' => '', | |
'message' => '', | |
'dismissible' => false, | |
'html' => '', | |
'location' => 'default' | |
); | |
add_action( 'admin_init' , array( $this, 'admin_init' ) ); | |
add_action( 'admin_notices' , array( $this, 'render_notices' ) ); | |
add_action( 'wp_ajax_get_persistent_notices', array( $this, 'ajax_get_notices' ) ); | |
add_action( 'shutdown' , array( $this, 'save_notices' ) ); | |
} | |
public function admin_init() { | |
// add a filter and that returns true to replace or prevent the session initialization functionality | |
if( !apply_filters( 'wp_persistent_notices_replace_initialization', false ) ) { | |
session_start(); | |
} | |
} | |
public function add_notice( $notice = array() ) { | |
if( !is_array( $notice ) ) { | |
$notice = array( | |
'message' => $notice | |
); | |
} | |
$notice = array_merge( $this->default_notice, $notice ); | |
$notice['created'] = time(); | |
$this->notices[] = $notice; | |
return true; | |
} | |
public function render_notices( $location = 'default' ) { | |
if( !$location ) { | |
$location = 'default'; | |
} | |
if( defined( 'DOING_AJAX' ) && DOING_AJAX ) { | |
return; | |
} | |
$notices = $this->retrieve_notices( $location ); | |
$output_array = array(); | |
foreach ( $notices as $notice ) { | |
if( !is_array( $notice ) ) { | |
$notice = array( | |
'message' => $notice | |
); | |
} | |
if( $notice['html'] ) { | |
$output_array[] = wp_kses_post( $notice['html'] ); | |
} elseif( $notice['message'] ) { | |
$notice = array_merge( $this->default_notice, $notice ); | |
$id = ''; | |
if( $notice['id'] ) { | |
$id = ' id="wp-persistent-notice-' . sanitize_title( $id ) . '"'; | |
} | |
$type = ''; | |
if( $notice['type'] ) { | |
$type = ' notice-' . sanitize_title( $notice['type'] ); | |
} | |
$cclass = ''; | |
if( $notice['custom_class'] ) { | |
$cclass = ' ' . sanitize_title( $notice['custom_class'] ); | |
} | |
$dismissible = ''; | |
if( $notice['dismissible'] ) { | |
$dismissible = ' is-dismissible'; | |
} | |
$class = ' class="notice' . $type . $cclass . $dismissible . '"'; | |
$message = wp_kses_post( $notice['message'] ); | |
$output_array[] = sprintf( '<div%1$s%2$s><p>%3$s</p></div>', $id, $class, $message ); | |
} | |
} | |
echo implode( "\n", $output_array ); | |
} | |
public function ajax_get_notices() { | |
$location = 'default'; | |
if( isset( $_GET['location'] ) && $_GET['location'] ) { | |
$location = $_GET['location']; | |
} | |
if( isset( $_POST['location'] ) && $_POST['location'] ) { | |
$location = $_POST['location']; | |
} | |
$notices = $this->retrieve_notices( $location ); | |
echo json_encode( $notices ); | |
wp_die(); | |
} | |
public function save_notices() { | |
$notices = $this->retrieve_notices( 'all' ); | |
if ( isset( $notices ) ) { | |
// add a filter that returns true to replace the notice saving functionality | |
if( apply_filters( 'wp_persistent_notices_replace_save_notices', false, $notices ) !== true ) { | |
$_SESSION[ $this->session_var ] = $notices; | |
} | |
} | |
} | |
private function retrieve_notices( $location = 'default' ) { | |
// note: once a notice is retrieved, it's gone | |
$notices = array(); | |
// add a filter that returns true to prevent retrieving messages on specific pages | |
if( !apply_filters( 'wp_persistent_notices_prevent_retrieval', false ) ) { | |
// add a filter that returns notices or empty array() to replace the session retrieval functionality | |
$raw_notices = apply_filters( 'wp_persistent_notices_replace_retrieve_notices', false ); | |
if( $raw_notices === false ) { | |
$raw_notices = array(); | |
if( isset( $_SESSION[ $this->session_var ] ) && is_array( $_SESSION[ $this->session_var ] ) ) { | |
$session_notices = $_SESSION[ $this->session_var ]; | |
if( is_array( $session_notices ) ) { | |
$raw_notices = $session_notices; | |
} | |
} | |
} | |
$raw_notices += $this->notices; | |
$raw_notices = apply_filters( 'wp_persistent_notices', $raw_notices ); | |
// clear all places notices are stored | |
unset( $_SESSION[ $this->session_var ] ); | |
$this->notices = array(); | |
remove_all_filters( 'wp_persistent_notices' ); | |
$notices = array(); | |
// filter for age and location | |
foreach( $raw_notices as $notice ) { | |
if( !isset( $notice['created'] ) || !$notice['created'] ) { | |
$notice['created'] = time(); | |
} else { | |
if( time() - $notice['created'] > $this->max_age ) { | |
continue; | |
} | |
} | |
if( $location == 'all' || $notice['location'] == $location ) { | |
$notices[] = $notice; | |
} else { | |
$this->notices[] = $notice; | |
} | |
} | |
// attach a filter that returns true to disable grouping notices | |
if( !apply_filters( 'wp_persistent_notices_display_ungrouped', false ) ) { | |
usort( $notices, array( $this, 'compare_notices' ) ); | |
} | |
} | |
return $notices; | |
} | |
private function compare_notices( $a, $b ) { | |
// attach a filter that returns an integer { -1, 0, 1 } to replace comparison function | |
$compare = apply_filters( 'wp_persistent_notices_replace_comparison', false, $a, $b ); | |
if( $compare !== false ) { | |
return $compare; | |
} | |
// if one of them doesn't have a type | |
if( !isset( $a['type'] ) ) { | |
if( !isset( $b['type'] ) ) { | |
return 0; | |
} | |
return -1; | |
} | |
// if types are equal | |
if( $a['type'] == $b['type'] ) { | |
return 0; | |
} | |
// give a weight to each type | |
$test = array( $a['type'], $b['type'] ); | |
$results = array(); | |
foreach( $test as $val ) { | |
$i = false; | |
switch( $val ) { | |
case 'error': | |
$i = apply_filters( 'wp_persistent_notices_sort_error_weight', 0 ); | |
break; | |
case 'warning': | |
$i = apply_filters( 'wp_persistent_notices_sort_warning_weight', 5 ); | |
break; | |
case 'success': | |
$i = apply_filters( 'wp_persistent_notices_sort_success_weight', 10 ); | |
break; | |
case 'info': | |
$i = apply_filters( 'wp_persistent_notices_sort_info_weight', 15 ); | |
break; | |
default: | |
// use the val to determine weight | |
$i = apply_filters( 'wp_persistent_notices_sort_custom_weight', 20, $val ); | |
} | |
$results[] = $i; | |
} | |
return ( $results[0] - $results[1] ); | |
} | |
} | |
WP_Persistent_Notices::Instance(); | |
if( !function_exists( 'add_persistent_notice' ) ) { | |
function add_persistent_notice( $notice ) { | |
$cl = WP_Persistent_Notices::Instance(); | |
return $cl->add_notice( $notice ); | |
} | |
} | |
if( !function_exists( 'render_persistent_notices' ) ) { | |
function render_persistent_notices( $location = 'default' ) { | |
$cl = WP_Persistent_Notices::Instance(); | |
return $cl->render_notices( $location ); | |
} | |
} | |
} |
I'd just add a verification for sessions already started:
if( session_status() == PHP_SESSION_NONE ) session_start();
Then it would be perfect!
Thanks for sharing this, it's exactly what I was looking for! Really surprised that they don't include something like this out of the box.
Really surprised that they don't include something like this out of the box.
Please consider this package [spam link here]
Its code is very simple, has many features and uses transients.
Its code is very simple, has many features and uses transients.
your code does not solve one of the core issues with WordPress messages, which is the need for transactional messages that can survive over a double redirect. Your code targets notices to classes of user or all users, but not to the specific user who initiated an action. In multi-user environments, this means that one user might cause an action, and another might receive the notification.
Beyond that, it is considered very rude to spam pages for one solution to advertise your alternative.
Excuse me.
You're right. My code is not for general purpose WordPress usage.
It is for system usage when some central thing goes wrong: e.g. "Google API is not reachable" in wp-cron, or "All editors, please prepare for release!"
Owh my God, finally something that really works! Been struggling with persistent notices problem in WordPress for the last couple of days until I found your class. This should really be a part of WP core.
Zillions of THANKS my friend, you saved me!