| @@ -1,9 +1,9 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | 3 | * Admin Notices Handler |
| 4 | 4 | * |
| 5 | - * @namespace UsabilityDynamics | |
| 5 | + * @namespace wpCloud\StatelessMedia | |
| 6 | 6 | * |
| 7 | 7 | * This file can be used to bootstrap any of the UD plugins, it essentially requires that you have |
| 8 | 8 | * a core file which will be called after 'plugins_loaded'. In addition, if the core class has |
| 9 | 9 | * 'activate' and 'deactivate' functions, then those will be called automatically by this class. |
| @@ -89,25 +89,48 @@ | ||
| 89 | 89 | add_action( 'wp_ajax_stateless_enable_notice_button_action', array( $this, 'stateless_enable_notice_button_action' ) ); |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | /** |
| 93 | + * Prevents adding duplicating messages | |
| 94 | + * Some triggers may happen few times during site load (like 'switch_blog' hook) | |
| 95 | + * adding the same message several times is not necessary | |
| 96 | + * | |
| 97 | + * @param string $collection | |
| 98 | + * @param string $message | |
| 99 | + */ | |
| 100 | + private function add_message( &$collection, $message ) { | |
| 101 | + $exiting_keys = array_column($collection, 'key'); | |
| 102 | + | |
| 103 | + if ( in_array( $message['key'], $exiting_keys ) ) { | |
| 104 | + return; | |
| 105 | + } | |
| 106 | + | |
| 107 | + $collection[] = $message; | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 93 | 111 | * Add new message for admin notices |
| 94 | 112 | * |
| 95 | 113 | * @param string $message |
| 96 | 114 | * @param string $type Values: 'error', 'message', 'warning' |
| 115 | + * @param string $translate Values: true, false | |
| 97 | 116 | * @author peshkov@UD |
| 98 | 117 | */ |
| 99 | - public function add( $message, $type = 'error' ) { | |
| 118 | + public function add( $message, $type = 'error', $translate = true ) { | |
| 100 | 119 | switch( $type ) { |
| 101 | 120 | case 'error': |
| 102 | - $this->errors[] = $message; | |
| 121 | + $this->add_message($this->errors, $message); | |
| 103 | 122 | break; |
| 104 | 123 | case 'message': |
| 105 | 124 | case 'warning': |
| 106 | 125 | case 'notice': |
| 107 | 126 | if(!is_array($message)){ |
| 127 | + $title = $translate | |
| 128 | + ? sprintf( __( '%s has the following notice:', $this->domain ), esc_html($this->name) ) | |
| 129 | + : sprintf( '%s has the following notice:', esc_html($this->name) ); | |
| 130 | + | |
| 108 | 131 | $message = array( |
| 109 | - 'title' => sprintf( __( '<b>%s</b> has the following notice:', $this->domain ), $this->name ), | |
| 132 | + 'title' => $title, | |
| 110 | 133 | 'message' => $message, |
| 111 | 134 | 'button' => null, |
| 112 | 135 | ); |
| 113 | 136 | } |
| @@ -114,9 +137,9 @@ | ||
| 114 | 137 | |
| 115 | 138 | if(empty($message['key'])){ |
| 116 | 139 | $message['key'] = md5( $message['title'] ); |
| 117 | 140 | } |
| 118 | - $this->notices[] = $message; | |
| 141 | + $this->add_message($this->notices, $message); | |
| 119 | 142 | break; |
| 120 | 143 | } |
| 121 | 144 | } |
| 122 | 145 | |
| @@ -161,41 +184,42 @@ | ||
| 161 | 184 | wp_enqueue_script( "sateless-error-notice-js", ud_get_stateless_media()->path( 'static/scripts/error-notice.js', 'url' ), array( 'jquery' ) ); |
| 162 | 185 | wp_enqueue_script( "ud-dismiss", $script_path, array( 'jquery' ) ); |
| 163 | 186 | wp_localize_script( "ud-dismiss", "_ud_vars", array( |
| 164 | 187 | "ajaxurl" => admin_url( 'admin-ajax.php' ), |
| 165 | - ) ); | |
| 188 | + )); | |
| 189 | + wp_localize_script( "sateless-error-notice-js", "stateless_error_notice_vars", array( | |
| 190 | + "dismiss_nonce" => wp_create_nonce( 'stateless_notice_dismiss' ), | |
| 191 | + "enable_action_nonce" => wp_create_nonce( 'stateless_enable_notice_button_action' ), | |
| 192 | + )); | |
| 166 | 193 | |
| 167 | - | |
| 168 | 194 | //** Don't show the message if the user has no enough permissions. */ |
| 169 | 195 | if ( ! function_exists( 'wp_get_current_user' ) ) { |
| 170 | 196 | require_once( ABSPATH . 'wp-includes/pluggable.php' ); |
| 171 | 197 | } |
| 172 | 198 | |
| 173 | - if( | |
| 199 | + $default_show = true; | |
| 200 | + | |
| 201 | + if ( | |
| 174 | 202 | empty( $this->args['type'] ) || |
| 175 | 203 | ( $this->args['type'] == 'plugin' && !current_user_can( 'activate_plugins' ) ) || |
| 176 | 204 | ( $this->args['type'] == 'theme' && !current_user_can( 'switch_themes' ) ) |
| 177 | 205 | ) { |
| 178 | - return; | |
| 206 | + $default_show = false; | |
| 179 | 207 | } |
| 180 | 208 | |
| 181 | 209 | //** Don't show the message if on a multisite and the user isn't a super user. */ |
| 182 | 210 | if ( is_multisite() && ! is_super_admin() ) { |
| 183 | - return; | |
| 211 | + $default_show = false; | |
| 184 | 212 | } |
| 185 | - //** Ignore messages on TGM Plugin Activation page */ | |
| 186 | - if( \UsabilityDynamics\WP\TGM_Plugin_Activation::get_instance()->is_tgmpa_page() ) { | |
| 187 | - return; | |
| 188 | - } | |
| 189 | 213 | |
| 190 | 214 | $errors = apply_filters( 'ud:errors:admin_notices', $this->errors, $this->args ); |
| 191 | 215 | $notices = apply_filters( 'stateless:notices:admin_notices', $this->notices, $this->args ); |
| 192 | 216 | |
| 193 | 217 | //** Errors Block */ |
| 194 | - if( !empty( $errors ) && is_array( $errors ) ) { | |
| 218 | + if( $default_show && !empty( $errors ) && is_array( $errors ) ) { | |
| 195 | 219 | $message = '<ul style="none;"><li>' . implode( '</li><li>', $errors ) . '</li></ul>'; |
| 196 | 220 | $data = array( |
| 197 | - 'title' => sprintf( __( '%s is not active due to following errors:', $this->domain ), $this->name ), | |
| 221 | + 'title' => sprintf( __( '%s is not active due to following errors:', $this->domain ), esc_html($this->name) ), | |
| 198 | 222 | 'class' => 'error', |
| 199 | 223 | 'message' => $message, |
| 200 | 224 | 'action_links' => !empty($this->action_links[ 'errors' ])?$this->action_links[ 'errors' ]:null, |
| 201 | 225 | ); |
| @@ -206,23 +230,49 @@ | ||
| 206 | 230 | $has_notice = false; |
| 207 | 231 | //** Determine if warning has been dismissed */ |
| 208 | 232 | if ( ! empty( $notices ) && is_array( $notices ) ) { |
| 209 | 233 | //** Warnings Block */ |
| 210 | - foreach($notices as $notice){ | |
| 211 | - if(get_option( 'dismissed_notice_' . $notice['key'] )){ | |
| 234 | + foreach ($notices as $notice ) { | |
| 235 | + if ( get_option( 'dismissed_notice_' . $notice['key'] )){ | |
| 212 | 236 | continue; |
| 213 | 237 | } |
| 214 | 238 | |
| 239 | + // Check additional capabilities | |
| 240 | + $capability = isset( $notice['capability'] ) && !empty( $notice['capability'] ) ? $notice['capability'] : null; | |
| 241 | + | |
| 242 | + if ( ( !$default_show && empty($capability) ) || ( !empty($capability) && !current_user_can($capability) ) ) { | |
| 243 | + continue; | |
| 244 | + } | |
| 245 | + | |
| 246 | + // Additional HTML classes | |
| 247 | + $classes = []; | |
| 248 | + | |
| 249 | + if ( isset($notice['classes']) ) { | |
| 250 | + $classes = $notice['classes']; | |
| 251 | + | |
| 252 | + if ( !is_array($classes) ) { | |
| 253 | + $classes = [$classes]; | |
| 254 | + } | |
| 255 | + } | |
| 256 | + | |
| 257 | + $classes[] = 'notice'; | |
| 258 | + | |
| 215 | 259 | $data = wp_parse_args($notice, array( |
| 216 | 260 | 'title' => '', |
| 217 | - 'class' => 'notice', | |
| 261 | + 'class' => implode(' ', $classes), | |
| 218 | 262 | 'message' => '', |
| 219 | 263 | 'button' => '', |
| 220 | 264 | 'button_link' => '#', |
| 221 | 265 | 'key' => '', |
| 222 | 266 | 'action_links' => $this->action_links[ 'notices' ], |
| 267 | + 'dismiss' => true, | |
| 223 | 268 | )); |
| 224 | 269 | |
| 270 | + $button_capability = isset( $notice['button_capability'] ) && !empty( $notice['button_capability'] ) ? $notice['button_capability'] : null; | |
| 271 | + if ( !empty($button_capability) && !current_user_can($button_capability) ) { | |
| 272 | + $data['button'] = ''; | |
| 273 | + } | |
| 274 | + | |
| 225 | 275 | include ud_get_stateless_media()->path( '/static/views/error-notice.php', 'dir' ); |
| 226 | 276 | |
| 227 | 277 | $has_notice = true; |
| 228 | 278 | } |
| @@ -233,22 +283,32 @@ | ||
| 233 | 283 | /** |
| 234 | 284 | * dismiss the notice ajax callback |
| 235 | 285 | * @throws \Exception |
| 236 | 286 | */ |
| 237 | - public function dismiss_notices(){ | |
| 287 | + public function dismiss_notices() { | |
| 288 | + check_ajax_referer('stateless_notice_dismiss'); | |
| 289 | + | |
| 290 | + if ( !is_user_logged_in() ) { | |
| 291 | + wp_send_json_error( array( 'error' => __( 'You are not allowed to do this action.', $this->domain ) ) ); | |
| 292 | + } | |
| 293 | + | |
| 238 | 294 | $response = array( |
| 239 | 295 | 'success' => '0', |
| 240 | 296 | 'error' => __( 'There was an error in request.', $this->domain ), |
| 241 | 297 | ); |
| 298 | + | |
| 242 | 299 | $error = false; |
| 243 | 300 | |
| 244 | - if( empty($_POST['key']) && strpos($_POST['key'], 'dismissed_notice_') !== false ) { | |
| 301 | + $option_key = isset($_POST['key']) ? sanitize_key($_POST['key']) : ''; | |
| 302 | + | |
| 303 | + if ( strpos($option_key, 'dismissed_') !== 0 ) { | |
| 245 | 304 | $response['error'] = __( 'Invalid key', $this->domain ); |
| 246 | 305 | $error = true; |
| 247 | 306 | } |
| 248 | - else { | |
| 249 | - $option_key = sanitize_key($_POST['key']); | |
| 250 | - update_option( $option_key, time() ); | |
| 307 | + | |
| 308 | + if ( !$error && update_option( $option_key, time() ) ) { | |
| 309 | + do_action('wp_stateless_notice_dismissed', $option_key); | |
| 310 | + | |
| 251 | 311 | $response['success'] = '1'; |
| 252 | 312 | $response['error'] = null; |
| 253 | 313 | } |
| 254 | 314 | |
| @@ -259,11 +319,18 @@ | ||
| 259 | 319 | * Action for the stateless_enable_notice_button_action ajax callback |
| 260 | 320 | * @throws \Exception |
| 261 | 321 | */ |
| 262 | 322 | public function stateless_enable_notice_button_action(){ |
| 323 | + check_ajax_referer('stateless_enable_notice_button_action'); | |
| 324 | + | |
| 325 | + if ( !is_user_logged_in() ) { | |
| 326 | + wp_send_json_error( array( 'error' => __( 'You are not allowed to do this action.', $this->domain ) ) ); | |
| 327 | + } | |
| 328 | + | |
| 263 | 329 | $response = array( |
| 264 | 330 | 'success' => '1', |
| 265 | 331 | ); |
| 332 | + | |
| 266 | 333 | $error = false; |
| 267 | 334 | |
| 268 | 335 | if( empty($_POST['key']) ) { |
| 269 | 336 | $response['success'] = '0'; |
| @@ -269,9 +336,10 @@ | ||
| 269 | 336 | $response['success'] = '0'; |
| 270 | 337 | $response['error'] = __( 'Invalid key', $this->domain ); |
| 271 | 338 | } |
| 272 | 339 | else{ |
| 273 | - $compatibility = Module::get_module($_POST['key']); | |
| 340 | + $option_key = sanitize_key($_POST['key']); | |
| 341 | + $compatibility = Module::get_module($option_key); | |
| 274 | 342 | if(!empty($compatibility['self']) && is_callable(array($compatibility['self'], 'enable_compatibility'))){ |
| 275 | 343 | $response['success'] = $compatibility['self']->enable_compatibility(); |
| 276 | 344 | } |
| 277 | 345 | } |