PluginProbe
Countdown Timer – Widget Countdown / trunk
Countdown Timer – Widget Countdown vtrunk
2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 All 182 releases
widget-countdown / includes / admin / AdminMenu.php

AdminMenu.php in Countdown Timer – Widget Countdown trunk, at includes/admin/AdminMenu.php

352 lines 13.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) exit;
3
4 /**
5 * AdminMenu — menu registration, script enqueues, AJAX handlers.
6 *
7 * Replaces the god-class admin.php. Each responsibility is a focused method.
8 * DB operations are NEVER done inside enqueue hooks.
9 */
10 class Wpda_Countdown_Admin_Menu {
11
12 private $timer_repo;
13 private $theme_repo;
14 private $installer;
15
16 public function __construct(
17 Wpda_Countdown_Timer_Repository $timer_repo,
18 Wpda_Countdown_Theme_Repository $theme_repo,
19 Wpda_Countdown_Installer $installer
20 ) {
21 $this->timer_repo = $timer_repo;
22 $this->theme_repo = $theme_repo;
23 $this->installer = $installer;
24 }
25
26 /**
27 * Wire all admin hooks. Called once from Plugin bootstrap.
28 */
29 public function init() {
30 add_action( 'admin_menu', array( $this, 'register_menus' ) );
31 add_filter( 'mce_external_plugins', array( $this, 'mce_plugins' ) );
32 add_filter( 'mce_buttons', array( $this, 'mce_buttons' ) );
33 add_action( 'wp_ajax_wpda_countdown_post_page_content', array( $this, 'ajax_post_popup' ) );
34
35 if ( WPDA_COUNTDOWN_IS_PRO ) {
36 add_action( 'wp_ajax_countdown_popup_page_save', array( $this, 'ajax_save_popup' ) );
37 add_action( 'wp_ajax_sticky_bar_page_save', array( $this, 'ajax_save_sticky_bar' ) );
38 }
39
40 if ( $this->is_woocommerce_active() ) {
41 $this->init_woocommerce();
42 }
43
44 $this->init_gutenberg();
45 }
46
47 // ─── Menu registration ──────────────────────────────────────
48
49 public function register_menus() {
50 global $submenu;
51
52 $main = add_menu_page(
53 'Countdown', 'Countdown', 'manage_options',
54 'wpda_countdown_menu', array( $this, 'page_timer' ),
55 'dashicons-clock'
56 );
57 add_submenu_page(
58 'wpda_countdown_menu', 'Timer', 'Timer', 'manage_options',
59 'wpda_countdown_menu', array( $this, 'page_timer' )
60 );
61 $theme_page = add_submenu_page(
62 'wpda_countdown_menu', 'Themes', 'Themes', 'manage_options',
63 'wpda_countdown_themes', array( $this, 'page_theme' )
64 );
65 $popup_label = WPDA_COUNTDOWN_IS_PRO ? 'Popup' : 'Popup <span style="color:#7052fb;font-weight:600;">(pro)</span>';
66 $sticky_label = WPDA_COUNTDOWN_IS_PRO ? 'Sticky Bar' : 'Sticky Bar <span style="color:#7052fb;font-weight:600;">(pro)</span>';
67 $popup_page = add_submenu_page(
68 'wpda_countdown_menu', 'Popup', $popup_label, 'manage_options',
69 'wpda_countdown_popup_settings', array( $this, 'page_popup' )
70 );
71 $sticky_page = add_submenu_page(
72 'wpda_countdown_menu', 'Sticky Bar', $sticky_label, 'manage_options',
73 'wpda_countdown_sticky_bar', array( $this, 'page_sticky_bar' )
74 );
75 add_submenu_page(
76 'wpda_countdown_menu', 'Featured Plugins', 'Featured Plugins', 'manage_options',
77 'wpda_countdown_featured_plugins', array( $this, 'page_featured_plugins' )
78 );
79 $hire_page = add_submenu_page(
80 'wpda_countdown_menu', 'Hire an Expert',
81 '<span style="color:#00ff66">Hire an Expert</span>', 'manage_options',
82 'wpda_countdown_hire_expert', array( $this, 'page_hire_expert' )
83 );
84
85 if ( isset( $submenu['wpda_countdown_menu'] ) ) {
86 add_submenu_page(
87 'wpda_countdown_menu', 'Support or Any Ideas?',
88 '<span style="color:#00ff66">Support or Any Ideas?</span>', 'manage_options',
89 'any_ideas', array( $this, 'page_any_ideas' ), 155
90 );
91 }
92
93 // Enqueue assets per page
94 add_action( 'admin_print_styles-' . $main, array( $this, 'enqueue_timer_page' ) );
95 add_action( 'admin_print_styles-' . $theme_page, array( $this, 'enqueue_theme_page' ) );
96 add_action( 'admin_print_styles-' . $popup_page, array( $this, 'enqueue_popup_page' ) );
97 add_action( 'admin_print_styles-' . $sticky_page, array( $this, 'enqueue_sticky_bar_page' ) );
98 add_action( 'admin_print_styles-' . $hire_page, array( $this, 'enqueue_hire_expert_page' ) );
99
100 // Redirect support link
101 if ( isset( $submenu['wpda_countdown_menu'] ) ) {
102 $count = count( $submenu['wpda_countdown_menu'] ) - 1;
103 $submenu['wpda_countdown_menu'][ $count ][2] = wpdevart_countdown_support_url;
104 }
105 }
106
107 // ─── Script enqueues (NO database operations here!) ─────────
108
109 public function enqueue_timer_page() {
110 // Actions (delete, set default) run here so the page body renders against the post-action state.
111 $this->process_timer_actions();
112
113 $is_edit = $this->is_edit_task( array( 'add_wpda_countdown_timer', 'add_edit_timer', 'update_timer' ) );
114
115 wp_enqueue_script( 'jquery' );
116 wp_enqueue_style( 'wpda_countdown_timer_page_css' );
117
118 if ( $is_edit ) {
119 wp_enqueue_script( 'wpda_flatpickr_js' );
120 wp_enqueue_style( 'wpda_flatpickr_css' );
121 wp_enqueue_script( 'wpda_countdown_timer_page_js' );
122 wp_enqueue_script( 'wpda_countdown_timeline_js' );
123 wp_enqueue_style( 'wpda_admin_add_edit_header' );
124 } else {
125 wp_enqueue_style( 'wpda_admin_list_header' );
126 wp_enqueue_style( 'wpda_table_maker_css' );
127 wp_enqueue_script( 'wpda_table_maker_js' );
128 // Only table-info is localized here (stable). Row list is output inline in
129 // display_table_list_timer() so it reflects rows created/updated in the
130 // same request (save runs AFTER enqueue).
131 $timer_page = new wpda_countdown_timer_page( $this->timer_repo );
132 wp_localize_script( 'wpda_table_maker_js', 'wpdaPageRowsInfo', $timer_page->get_table_info() );
133 }
134 }
135
136 public function enqueue_theme_page() {
137 // Actions (delete, set default) run here so the page body renders against the post-action state.
138 $this->process_theme_actions();
139
140 $is_edit = $this->is_edit_task( array( 'add_wpda_countdown_theme', 'add_edit_theme', 'update_theme' ) );
141
142 wp_enqueue_script( 'jquery' );
143 wp_enqueue_style( 'wpda_countdown_theme_page_css' );
144
145 if ( $is_edit ) {
146 wp_enqueue_style( 'wp-color-picker' );
147 wp_enqueue_script( 'wp-color-picker' );
148 wp_enqueue_script( 'wpda_countdown_theme_page_js' );
149 wp_enqueue_style( 'wpda_admin_add_edit_header' );
150 // Load the frontend CSS on the theme editor so the live preview uses the
151 // same theme-isolation reset and specific rules as the actual frontend.
152 wp_enqueue_style( 'wpdevart_countdown_front' );
153 } else {
154 wp_enqueue_style( 'wpda_admin_list_header' );
155 wp_enqueue_style( 'wpda_table_maker_css' );
156 wp_enqueue_script( 'wpda_table_maker_js' );
157 // Row list is output inline in display_table_list_theme() (see note above).
158 $theme_page = new wpda_countdown_theme_page( $this->theme_repo );
159 wp_localize_script( 'wpda_table_maker_js', 'wpdaPageRowsInfo', $theme_page->get_table_info() );
160 }
161 }
162
163 public function enqueue_popup_page() {
164 wp_enqueue_script( 'jquery' );
165 wp_enqueue_style( 'wpdevart-countdown-pro-jquery-ui' );
166 wp_enqueue_style( 'wp-color-picker' );
167 wp_enqueue_script( 'wp-color-picker' );
168 wp_enqueue_script( 'jquery-ui-sortable' );
169 wp_enqueue_script( 'wpdevart_chosen' );
170 wp_enqueue_script( 'wpdevart_prism' );
171 wp_enqueue_style( 'wpda_admin_add_edit_header' );
172 wp_enqueue_style( 'wpda_countdown_popup_page_css' );
173 wp_enqueue_script( 'wpda_countdown_popup_page_js' );
174 if ( function_exists( 'wp_enqueue_media' ) ) wp_enqueue_media();
175 }
176
177 public function enqueue_sticky_bar_page() {
178 wp_enqueue_script( 'jquery' );
179 wp_enqueue_style( 'wp-color-picker' );
180 wp_enqueue_script( 'wp-color-picker' );
181 wp_enqueue_script( 'wpdevart_chosen' );
182 wp_enqueue_style( 'wpda_admin_add_edit_header' );
183 wp_enqueue_style( 'wpda_countdown_popup_page_css' );
184 wp_enqueue_script( 'wpda_countdown_sticky_bar_js' );
185 if ( function_exists( 'wp_enqueue_media' ) ) wp_enqueue_media();
186 }
187
188 public function enqueue_hire_expert_page() {
189 wp_enqueue_style( 'wpda_countdown_hire_expert_css' );
190 }
191
192 // ─── Page callbacks ─────────────────────────────────────────
193
194 public function page_timer() {
195 $this->installer->ensure_tables();
196 $this->process_timer_actions();
197 $timer_page = new wpda_countdown_timer_page( $this->timer_repo );
198 $timer_page->controller_page();
199 }
200
201 public function page_theme() {
202 $this->installer->ensure_tables();
203 $this->process_theme_actions();
204 $theme_page = new wpda_countdown_theme_page( $this->theme_repo );
205 $theme_page->controller_page();
206 }
207
208 public function page_popup() {
209 $this->installer->ensure_tables();
210 $popup_page = new wpda_countdown_popup_page();
211 $popup_page->controller_page();
212 }
213
214 public function page_sticky_bar() {
215 $this->installer->ensure_tables();
216 $sticky_page = new wpda_countdown_sticky_bar_page();
217 $sticky_page->controller_page();
218 }
219
220 public function page_featured_plugins() {
221 include wpda_countdown_plugin_path . 'includes/admin/Views/featured-plugins.php';
222 }
223
224 public function page_hire_expert() {
225 include wpda_countdown_plugin_path . 'includes/admin/Views/hire-expert.php';
226 }
227
228 public function page_any_ideas() {
229 // Callback for Support submenu — link is redirected via $submenu override
230 }
231
232 // ─── Action processing ──────────────────────────────────────
233 // Called from enqueue hooks (fires before page render) so the
234 // localized JS list data reflects the current state. Safe to call
235 // multiple times thanks to the $processed flags.
236
237 private $timer_actions_done = false;
238 private $theme_actions_done = false;
239
240 private function process_timer_actions() {
241 if ( $this->timer_actions_done ) return;
242 $this->timer_actions_done = true;
243
244 $task = isset( $_GET['task'] ) ? sanitize_text_field( $_GET['task'] ) : '';
245 $id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0;
246
247 if ( $task === 'remove_timer' && $id ) {
248 $this->verify_action_nonce( 'wpda_timer_action' );
249 $this->timer_repo->delete( $id );
250 }
251 }
252
253 private function process_theme_actions() {
254 if ( $this->theme_actions_done ) return;
255 $this->theme_actions_done = true;
256
257 $task = isset( $_GET['task'] ) ? sanitize_text_field( $_GET['task'] ) : '';
258 $id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0;
259
260 if ( $task === 'remove_theme' && $id ) {
261 $this->verify_action_nonce( 'wpda_theme_action' );
262 // Protect default theme from deletion
263 $row = $this->theme_repo->find( $id );
264 if ( $row && $row->default ) {
265 add_action( 'admin_notices', array( $this, 'notice_cannot_delete_default' ) );
266 return;
267 }
268 $this->theme_repo->delete( $id );
269 }
270 if ( $task === 'set_default_theme' && $id ) {
271 $this->verify_action_nonce( 'wpda_theme_action' );
272 $this->theme_repo->set_default( $id );
273 }
274 }
275
276 /**
277 * Verify nonce for destructive GET actions. wp_die on failure.
278 */
279 private function verify_action_nonce( $action ) {
280 $nonce = isset( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : '';
281 if ( ! wp_verify_nonce( $nonce, $action ) ) {
282 wp_die(
283 'Security check failed. Please return and try again.',
284 'Security Check',
285 array( 'response' => 403, 'back_link' => true )
286 );
287 }
288 }
289
290 public function notice_cannot_delete_default() {
291 echo '<div class="notice notice-error is-dismissible"><p>You cannot delete the default theme. Set a different theme as default first.</p></div>';
292 }
293
294 // ─── TinyMCE integration ────────────────────────────────────
295
296 public function mce_plugins( $plugin_array ) {
297 $plugin_array['wpda_countdown'] = wpda_countdown_plugin_url . 'includes/admin/js/post_page_insert_button.js';
298 return $plugin_array;
299 }
300
301 public function mce_buttons( $buttons ) {
302 $buttons[] = 'wpda_countdown';
303 return $buttons;
304 }
305
306 // ─── AJAX handlers ──────────────────────────────────────────
307
308 public function ajax_post_popup() {
309 if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Unauthorized' );
310 require_once wpda_countdown_plugin_path . 'includes/admin/PostPopup.php';
311 new wpda_countdown_post_page_popup();
312 }
313
314 public function ajax_save_popup() {
315 if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Unauthorized' );
316 // PopupController already loaded by Plugin.php
317 wpda_countdown_popup_page::save_in_db();
318 }
319
320 public function ajax_save_sticky_bar() {
321 if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Unauthorized' );
322 // StickyBarController already loaded by Plugin.php
323 wpda_countdown_sticky_bar_page::save_in_db();
324 }
325
326 // ─── Integrations ───────────────────────────────────────────
327
328 private function init_woocommerce() {
329 require_once wpda_countdown_plugin_path . 'includes/Integration/WooCommerce.php';
330 $woo = new wpda_countdown_woocomerce();
331 add_action( 'add_meta_boxes', array( $woo, 'add_metabox' ) );
332 add_action( 'save_post_product', array( $woo, 'save_metabox' ) );
333 add_filter( 'woocommerce_get_settings_pages', array( $woo, 'woocommerce_settings' ) );
334 }
335
336 private function init_gutenberg() {
337 require_once wpda_countdown_plugin_path . 'includes/Integration/Gutenberg.php';
338 new wpda_countdown_gutenberg();
339 }
340
341 // ─── Helpers ────────────────────────────────────────────────
342
343 private function is_edit_task( $tasks ) {
344 $task = isset( $_GET['task'] ) ? sanitize_text_field( $_GET['task'] ) : '';
345 return in_array( $task, $tasks, true );
346 }
347
348 private function is_woocommerce_active() {
349 return wpda_countdown_is_plugin_active( 'woocommerce/woocommerce.php' );
350 }
351 }
352