class-yoast-alerts.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin\Notifications
  6. */
  7. /**
  8. * Class Yoast_Alerts.
  9. */
  10. class Yoast_Alerts {
  11. /**
  12. * Holds the admin page's ID.
  13. *
  14. * @var string
  15. */
  16. const ADMIN_PAGE = 'wpseo_dashboard';
  17. /**
  18. * Total notifications count.
  19. *
  20. * @var int
  21. */
  22. private static $notification_count = 0;
  23. /**
  24. * All error notifications.
  25. *
  26. * @var array
  27. */
  28. private static $errors = [];
  29. /**
  30. * Active errors.
  31. *
  32. * @var array
  33. */
  34. private static $active_errors = [];
  35. /**
  36. * Dismissed errors.
  37. *
  38. * @var array
  39. */
  40. private static $dismissed_errors = [];
  41. /**
  42. * All warning notifications.
  43. *
  44. * @var array
  45. */
  46. private static $warnings = [];
  47. /**
  48. * Active warnings.
  49. *
  50. * @var array
  51. */
  52. private static $active_warnings = [];
  53. /**
  54. * Dismissed warnings.
  55. *
  56. * @var array
  57. */
  58. private static $dismissed_warnings = [];
  59. /**
  60. * Yoast_Alerts constructor.
  61. */
  62. public function __construct() {
  63. $this->add_hooks();
  64. }
  65. /**
  66. * Add hooks
  67. */
  68. private function add_hooks() {
  69. $page = filter_input( INPUT_GET, 'page' );
  70. if ( self::ADMIN_PAGE === $page ) {
  71. add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
  72. }
  73. // Needed for adminbar and Alerts page.
  74. add_action( 'admin_init', [ __CLASS__, 'collect_alerts' ], 99 );
  75. // Add AJAX hooks.
  76. add_action( 'wp_ajax_yoast_dismiss_alert', [ $this, 'ajax_dismiss_alert' ] );
  77. add_action( 'wp_ajax_yoast_restore_alert', [ $this, 'ajax_restore_alert' ] );
  78. }
  79. /**
  80. * Enqueue assets.
  81. */
  82. public function enqueue_assets() {
  83. $asset_manager = new WPSEO_Admin_Asset_Manager();
  84. $asset_manager->enqueue_style( 'alerts' );
  85. }
  86. /**
  87. * Handle ajax request to dismiss an alert.
  88. */
  89. public function ajax_dismiss_alert() {
  90. $notification = $this->get_notification_from_ajax_request();
  91. if ( $notification ) {
  92. $notification_center = Yoast_Notification_Center::get();
  93. $notification_center->maybe_dismiss_notification( $notification );
  94. $this->output_ajax_response( $notification->get_type() );
  95. }
  96. wp_die();
  97. }
  98. /**
  99. * Handle ajax request to restore an alert.
  100. */
  101. public function ajax_restore_alert() {
  102. $notification = $this->get_notification_from_ajax_request();
  103. if ( $notification ) {
  104. $notification_center = Yoast_Notification_Center::get();
  105. $notification_center->restore_notification( $notification );
  106. $this->output_ajax_response( $notification->get_type() );
  107. }
  108. wp_die();
  109. }
  110. /**
  111. * Create AJAX response data.
  112. *
  113. * @param string $type Alert type.
  114. */
  115. private function output_ajax_response( $type ) {
  116. $html = $this->get_view_html( $type );
  117. // phpcs:disable WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
  118. echo WPSEO_Utils::format_json_encode(
  119. [
  120. 'html' => $html,
  121. 'total' => self::get_active_alert_count(),
  122. ]
  123. );
  124. // phpcs:enable -- Reason: WPSEO_Utils::format_json_encode is safe.
  125. }
  126. /**
  127. * Get the HTML to return in the AJAX request.
  128. *
  129. * @param string $type Alert type.
  130. *
  131. * @return bool|string
  132. */
  133. private function get_view_html( $type ) {
  134. switch ( $type ) {
  135. case 'error':
  136. $view = 'errors';
  137. break;
  138. case 'warning':
  139. default:
  140. $view = 'warnings';
  141. break;
  142. }
  143. // Re-collect alerts.
  144. self::collect_alerts();
  145. /**
  146. * Stops PHPStorm from nagging about this variable being unused. The variable is used in the view.
  147. *
  148. * @noinspection PhpUnusedLocalVariableInspection
  149. */
  150. $alerts_data = self::get_template_variables();
  151. ob_start();
  152. include WPSEO_PATH . 'admin/views/partial-alerts-' . $view . '.php';
  153. $html = ob_get_clean();
  154. return $html;
  155. }
  156. /**
  157. * Extract the Yoast Notification from the AJAX request.
  158. *
  159. * @return null|Yoast_Notification
  160. */
  161. private function get_notification_from_ajax_request() {
  162. $notification_center = Yoast_Notification_Center::get();
  163. $notification_id = filter_input( INPUT_POST, 'notification' );
  164. return $notification_center->get_notification_by_id( $notification_id );
  165. }
  166. /**
  167. * Show the alerts overview page.
  168. */
  169. public static function show_overview_page() {
  170. /**
  171. * Stops PHPStorm from nagging about this variable being unused. The variable is used in the view.
  172. *
  173. * @noinspection PhpUnusedLocalVariableInspection
  174. */
  175. $alerts_data = self::get_template_variables();
  176. include WPSEO_PATH . 'admin/views/alerts-dashboard.php';
  177. }
  178. /**
  179. * Collect the alerts and group them together.
  180. */
  181. public static function collect_alerts() {
  182. $notification_center = Yoast_Notification_Center::get();
  183. $notifications = $notification_center->get_sorted_notifications();
  184. self::$notification_count = count( $notifications );
  185. self::$errors = array_filter( $notifications, [ __CLASS__, 'filter_error_alerts' ] );
  186. self::$dismissed_errors = array_filter( self::$errors, [ __CLASS__, 'filter_dismissed_alerts' ] );
  187. self::$active_errors = array_diff( self::$errors, self::$dismissed_errors );
  188. self::$warnings = array_filter( $notifications, [ __CLASS__, 'filter_warning_alerts' ] );
  189. self::$dismissed_warnings = array_filter( self::$warnings, [ __CLASS__, 'filter_dismissed_alerts' ] );
  190. self::$active_warnings = array_diff( self::$warnings, self::$dismissed_warnings );
  191. }
  192. /**
  193. * Get the variables needed in the views.
  194. *
  195. * @return array
  196. */
  197. public static function get_template_variables() {
  198. return [
  199. 'metrics' => [
  200. 'total' => self::$notification_count,
  201. 'active' => self::get_active_alert_count(),
  202. 'errors' => count( self::$errors ),
  203. 'warnings' => count( self::$warnings ),
  204. ],
  205. 'errors' => [
  206. 'dismissed' => self::$dismissed_errors,
  207. 'active' => self::$active_errors,
  208. ],
  209. 'warnings' => [
  210. 'dismissed' => self::$dismissed_warnings,
  211. 'active' => self::$active_warnings,
  212. ],
  213. ];
  214. }
  215. /**
  216. * Get the number of active alerts.
  217. *
  218. * @return int
  219. */
  220. public static function get_active_alert_count() {
  221. return ( count( self::$active_errors ) + count( self::$active_warnings ) );
  222. }
  223. /**
  224. * Filter out any non-errors.
  225. *
  226. * @param Yoast_Notification $notification Notification to test.
  227. *
  228. * @return bool
  229. */
  230. private static function filter_error_alerts( Yoast_Notification $notification ) {
  231. return $notification->get_type() === 'error';
  232. }
  233. /**
  234. * Filter out any non-warnings.
  235. *
  236. * @param Yoast_Notification $notification Notification to test.
  237. *
  238. * @return bool
  239. */
  240. private static function filter_warning_alerts( Yoast_Notification $notification ) {
  241. return $notification->get_type() !== 'error';
  242. }
  243. /**
  244. * Filter out any dismissed notifications.
  245. *
  246. * @param Yoast_Notification $notification Notification to test.
  247. *
  248. * @return bool
  249. */
  250. private static function filter_dismissed_alerts( Yoast_Notification $notification ) {
  251. return Yoast_Notification_Center::is_notification_dismissed( $notification );
  252. }
  253. }