PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
← All changes | includes/admin/class-charitable-admin-pages.php +541 -49 1.7.0.1 → 1.8.13 View file →
@@ -3,12 +3,12 @@
3 3 * This class is responsible for adding the Charitable admin pages.
4 4 *
5 5 * @package Charitable/Classes/Charitable_Admin_Pages
6 6 * @author David Bisset
7 - * @copyright Copyright (c) 2022, WP Charitable LLC
7 + * @copyright Copyright (c) 2023, WP Charitable LLC
8 8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 9 * @since 1.0.0
10 - * @version 1.6.39
10 + * @version 1.8.1.12
11 11 */
12 12
13 13 // Exit if accessed directly.
14 14 if ( ! defined( 'ABSPATH' ) ) {
@@ -59,8 +59,11 @@
59 59 * @param string $cap The capability required.
60 60 */
61 61 $this->admin_menu_capability = apply_filters( 'charitable_admin_menu_capability', 'view_charitable_sensitive_data' );
62 62 $this->admin_menu_parent_page = 'charitable';
63 +
64 + // Hook into plugin installation to set timestamps for rotating menu
65 + add_action( 'upgrader_process_complete', array( $this, 'handle_plugin_installation' ), 10, 2 );
63 66 }
64 67
65 68 /**
66 69 * Returns and/or create the single instance of this class.
@@ -81,8 +84,10 @@
81 84 * This forces the charitable menu to be open for category and tag pages.
82 85 *
83 86 * @since 1.7.0
84 87 *
88 + * @param string $parent_file The parent file.
89 + *
85 90 * @return string
86 91 */
87 92 public function menu_highlight( $parent_file ) {
88 93 global $current_screen;
@@ -110,9 +115,9 @@
110 115 public function add_menu() {
111 116 add_menu_page(
112 117 'Charitable',
113 118 'Charitable',
114 - 'edit_campaigns',
119 + 'edit_campaigns', // phpcs:ignore
115 120 $this->admin_menu_parent_page,
116 121 array( $this, 'render_welcome_page' )
117 122 );
118 123
@@ -142,9 +147,10 @@
142 147
143 148 /**
144 149 * Returns an array with all the submenu pages.
145 150 *
146 - * @since 1.0.0
151 + * @since 1.0.0
152 + * @since 1.8.8
147 153 *
148 154 * @return array
149 155 */
150 156 private function get_submenu_pages() {
@@ -154,64 +160,262 @@
154 160 /**
155 161 * Filter the list of submenu pages that come
156 162 * under the Charitable menu tab.
157 163 *
158 - * @since 1.0.0
164 + * @since 1.0.0
165 + * @version 1.8.1 Added dashboard and reports.
166 + * @version 1.8.1.6 Added tools.
167 + * @version 1.8.1.8 Added SMTP.
168 + * @version 1.8.2 Remove categories, tags, and customize.
169 + * @version 1.8.5.1 Added donors.
159 170 *
160 171 * @param array $pages Every page is an array with at least a page_title,
161 172 * menu_title and menu_slug set.
162 173 */
163 - return apply_filters(
174 + // Build dashboard pages array based on legacy dashboard setting
175 + $dashboard_pages = array();
176 +
177 + if ( charitable_use_legacy_dashboard() ) {
178 + // Show legacy dashboard
179 + $dashboard_pages[] = array(
180 + 'page_title' => __( 'Dashboard', 'charitable' ),
181 + 'menu_title' => __( 'Dashboard', 'charitable' ),
182 + 'menu_slug' => 'charitable-dashboard',
183 + 'function' => array( $this, 'render_dashboard_new_page' ),
184 + 'capability' => 'manage_charitable_settings',
185 + );
186 + } else {
187 + // Show new dashboard (formerly beta)
188 + $dashboard_pages[] = array(
189 + 'page_title' => __( 'Dashboard', 'charitable' ),
190 + 'menu_title' => __( 'Dashboard', 'charitable' ),
191 + 'menu_slug' => 'charitable-dashboard',
192 + 'function' => array( $this, 'render_dashboard_page' ),
193 + 'capability' => 'manage_charitable_settings',
194 + );
195 + }
196 +
197 + $pages = apply_filters(
164 198 'charitable_submenu_pages',
165 - array(
199 + array_merge(
200 + $dashboard_pages,
166 201 array(
167 - 'page_title' => $campaign_post_type->labels->menu_name,
168 - 'menu_title' => $campaign_post_type->labels->menu_name,
169 - 'menu_slug' => 'edit.php?post_type=campaign',
170 - 'capability' => 'edit_campaigns',
171 - ),
202 + array(
203 + 'page_title' => $campaign_post_type->labels->menu_name,
204 + 'menu_title' => $campaign_post_type->labels->menu_name,
205 + 'menu_slug' => 'edit.php?post_type=campaign',
206 + 'capability' => 'edit_campaigns',
207 + ),
208 + array(
209 + 'page_title' => $campaign_post_type->labels->add_new,
210 + 'menu_title' => $campaign_post_type->labels->add_new,
211 + 'menu_slug' => 'post-new.php?post_type=campaign',
212 + 'capability' => 'edit_campaigns',
213 + ),
214 + array(
215 + 'page_title' => $donation_post_type->labels->menu_name,
216 + 'menu_title' => $donation_post_type->labels->menu_name,
217 + 'menu_slug' => 'edit.php?post_type=donation',
218 + 'capability' => 'edit_donations',
219 + ),
220 + array(
221 + 'page_title' => __( 'Charitable Donors', 'charitable' ),
222 + 'menu_title' => __( 'Donors', 'charitable' ) . ' <span class="charitable-menu-new-indicator">&nbsp;' . esc_html__( 'NEW', 'charitable' ) . '!</span>',
223 + 'menu_slug' => 'charitable-donors',
224 + 'function' => array( $this, 'render_donors_page' ),
225 + 'capability' => 'manage_charitable_settings',
226 + ),
227 + array(
228 + 'page_title' => __( 'Charitable Reports', 'charitable' ),
229 + 'menu_title' => __( 'Reports', 'charitable' ),
230 + 'menu_slug' => 'charitable-reports',
231 + 'function' => array( $this, 'render_reports_page' ),
232 + 'capability' => 'manage_charitable_settings',
233 + ),
234 + array(
235 + 'page_title' => __( 'Charitable Tools', 'charitable' ),
236 + 'menu_title' => __( 'Tools', 'charitable' ),
237 + 'menu_slug' => 'charitable-tools',
238 + 'function' => array( $this, 'render_tools_page' ),
239 + 'capability' => 'manage_charitable_settings',
240 + ),
241 + array(
242 + 'page_title' => __( 'Charitable Settings', 'charitable' ),
243 + 'menu_title' => __( 'Settings', 'charitable' ),
244 + 'menu_slug' => 'charitable-settings',
245 + 'function' => array( $this, 'render_settings_page' ),
246 + 'capability' => 'manage_charitable_settings',
247 + ),
248 + array(
249 + 'page_title' => __( 'Charitable Addons', 'charitable' ),
250 + 'menu_title' => '<span style="color:#f18500">' . __( 'Addons', 'charitable' ) . '</span>',
251 + 'menu_slug' => 'charitable-addons',
252 + 'function' => array( $this, 'render_addons_directory_page' ),
253 + 'capability' => 'manage_charitable_settings',
254 + ),
255 + array(
256 + 'page_title' => __( 'SMTP', 'charitable' ),
257 + 'menu_title' => __( 'SMTP', 'charitable' ),
258 + 'menu_slug' => 'charitable-smtp',
259 + 'function' => array( $this, 'render_smtp_page' ),
260 + 'capability' => 'manage_charitable_settings',
261 + ),
262 + )
263 + )
264 + );
265 +
266 + // Rotating submenu: Privacy Compliance / SMTP.
267 + $rotation = $this->get_rotating_marketing_submenu();
268 +
269 + if ( $rotation ) {
270 + $pages = array_merge( $pages, array(
172 271 array(
173 - 'page_title' => $campaign_post_type->labels->add_new,
174 - 'menu_title' => $campaign_post_type->labels->add_new,
175 - 'menu_slug' => 'post-new.php?post_type=campaign',
176 - 'capability' => 'edit_campaigns',
177 - ),
178 - array(
179 - 'page_title' => $donation_post_type->labels->menu_name,
180 - 'menu_title' => $donation_post_type->labels->menu_name,
181 - 'menu_slug' => 'edit.php?post_type=donation',
182 - 'capability' => 'edit_donations',
183 - ),
184 - array(
185 - 'page_title' => __( 'Campaign Categories', 'charitable' ),
186 - 'menu_title' => __( 'Categories', 'charitable' ),
187 - 'menu_slug' => 'edit-tags.php?taxonomy=campaign_category&post_type=campaign',
188 - 'capability' => 'manage_campaign_terms',
189 - ),
190 - array(
191 - 'page_title' => __( 'Campaign Tags', 'charitable' ),
192 - 'menu_title' => __( 'Tags', 'charitable' ),
193 - 'menu_slug' => 'edit-tags.php?taxonomy=campaign_tag&post_type=campaign',
194 - 'capability' => 'manage_campaign_terms',
195 - ),
196 - array(
197 - 'page_title' => __( 'Customize', 'charitable' ),
198 - 'menu_title' => __( 'Customize', 'charitable' ),
199 - 'menu_slug' => 'customize.php?autofocus[panel]=charitable&url=' . $this->get_customizer_campaign_preview_url(),
272 + 'page_title' => $rotation['page_title'],
273 + 'menu_title' => $rotation['menu_title'],
274 + 'menu_slug' => $rotation['menu_slug'],
275 + 'function' => array( $this, 'admin_page' ),
200 276 'capability' => 'manage_charitable_settings',
201 - ),
202 - array(
203 - 'page_title' => __( 'Charitable Settings', 'charitable' ),
204 - 'menu_title' => __( 'Settings', 'charitable' ),
205 - 'menu_slug' => 'charitable-settings',
206 - 'function' => array( $this, 'render_settings_page' ),
207 - 'capability' => 'manage_charitable_settings',
208 - ),
277 + )
278 + ) );
279 + }
280 +
281 + $pages = array_merge( $pages, array(
282 + array(
283 + 'page_title' => __( 'About Charitable', 'charitable' ),
284 + 'menu_title' => __( 'About Us', 'charitable' ),
285 + 'menu_slug' => 'charitable-about',
286 + 'function' => array( $this, 'render_about_page' ),
287 + 'capability' => 'view_charitable_sensitive_data',
209 288 )
210 - );
289 + ) );
290 +
291 + return $pages;
211 292 }
212 293
213 294 /**
295 + * Determine which marketing submenu item to show (rotation).
296 + *
297 + * Current behavior:
298 + * - Show "Privacy Compliance" until the WPConsent plugin has been activated for 7 or more days.
299 + * - Once 7+ days have passed since WPConsent first activation, show "SMTP".
300 + * - This can be extended to more items later and to use per-item activation timestamps.
301 + *
302 + * @since 1.8.8
303 + *
304 + * @return array|null { menu_title, page_title, menu_slug } or null to show none.
305 + */
306 + private function get_rotating_marketing_submenu(): ?array {
307 +
308 + $items = $this->get_marketing_rotation_items();
309 + if ( empty( $items ) ) {
310 + return null;
311 + }
312 +
313 + $now = time();
314 +
315 + // Find the first item that should still be displayed.
316 + foreach ( $items as $item ) {
317 + $label = $item['label'] ?? '';
318 + $menu_slug = $item['menu_slug'] ?? '';
319 + $option_name = $item['option_name'] ?? '';
320 + $option_key = $item['option_key'] ?? '';
321 + $plugin_file = $item['plugin_file'] ?? '';
322 + $period_days = (int) ( $item['period_days'] ?? 7 );
323 +
324 + if ( empty( $label ) || empty( $menu_slug ) ) {
325 + continue; // Skip misconfigured entries.
326 + }
327 +
328 + // If a reference plugin is provided and it's not active, keep showing this item.
329 + if ( ! empty( $plugin_file ) ) {
330 + if ( ! function_exists( 'is_plugin_active' ) ) {
331 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
332 + }
333 + if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( $plugin_file ) ) {
334 + return [
335 + 'menu_title' => $label,
336 + 'page_title' => $label,
337 + 'menu_slug' => $menu_slug,
338 + ];
339 + }
340 + }
341 +
342 + $ts = 0;
343 + if ( ! empty( $option_name ) ) {
344 + $opt = get_option( $option_name );
345 + if ( is_array( $opt ) ) {
346 + $ts = isset( $opt[ $option_key ] ) && is_numeric( $opt[ $option_key ] ) ? (int) $opt[ $option_key ] : 0;
347 + } elseif ( is_numeric( $opt ) ) {
348 + $ts = (int) $opt;
349 + }
350 + }
351 +
352 + $threshold = max( 0, $period_days ) * DAY_IN_SECONDS;
353 + $within = $ts === 0 || ( $now - $ts ) < $threshold;
354 +
355 + if ( $within ) {
356 + return [
357 + 'menu_title' => $label,
358 + 'page_title' => $label,
359 + 'menu_slug' => $menu_slug,
360 + ];
361 + }
362 + }
363 +
364 + // If all items are considered "complete", return the first one (cycle back).
365 + $first = $items[0];
366 + return [
367 + 'menu_title' => $first['label'],
368 + 'page_title' => $first['label'],
369 + 'menu_slug' => $first['menu_slug'],
370 + ];
371 + }
372 +
373 + /**
374 + * Editable list of rotating marketing submenu items.
375 + *
376 + * @since 1.8.8
377 + *
378 + * @return array
379 + */
380 + private function get_marketing_rotation_items(): array {
381 + return [
382 + [
383 + 'label' => esc_html__( 'Privacy Compliance', 'charitable' ),
384 + 'menu_slug' => 'charitable-privacy-compliance',
385 + 'option_name' => 'wpconsent_activated',
386 + 'option_key' => 'wpconsent',
387 + 'plugin_file' => 'wpconsent-cookies-banner-privacy-suite/wpconsent.php',
388 + 'period_days' => 7,
389 + ],
390 + [
391 + 'label' => esc_html__( 'Backups', 'charitable' ),
392 + 'menu_slug' => 'charitable-backups',
393 + 'option_name' => 'duplicator_activated',
394 + 'option_key' => 'duplicator',
395 + 'plugin_file' => 'duplicator/duplicator.php',
396 + 'period_days' => 7,
397 + ],
398 + [
399 + 'label' => esc_html__( 'SEO', 'charitable' ),
400 + 'menu_slug' => 'charitable-seo',
401 + 'option_name' => 'all-in-one-seo-pack_activated',
402 + 'option_key' => 'all-in-one-seo-pack',
403 + 'plugin_file' => 'all-in-one-seo-pack/all_in_one_seo_pack.php',
404 + 'period_days' => 7,
405 + ],
406 + [
407 + 'label' => esc_html__( 'Automation', 'charitable' ),
408 + 'menu_slug' => 'charitable-automation',
409 + 'option_name' => 'uncanny-automator_activated',
410 + 'option_key' => 'uncanny_automator',
411 + 'plugin_file' => 'uncanny-automator/uncanny-automator.php',
412 + 'period_days' => 7,
413 + ],
414 + ];
415 + }
416 +
417 + /**
214 418 * Set up the redirect to the welcome page.
215 419 *
216 420 * @since 1.3.0
217 421 *
@@ -233,8 +437,223 @@
233 437 exit;
234 438 }
235 439
236 440 /**
441 + * Display the Charitable donors page.
442 + *
443 + * @since 1.8.5
444 + *
445 + * @return void
446 + */
447 + public function render_donors_page() {
448 + charitable_admin_view( 'donors/donors' );
449 + }
450 +
451 + /**
452 + * Display the Charitable reports page.
453 + *
454 + * @since 1.8.1
455 + *
456 + * @return void
457 + */
458 + public function render_reports_page() {
459 + charitable_admin_view( 'reports/reports' );
460 + }
461 +
462 + /**
463 + * Display the Charitable tools page.
464 + *
465 + * @since 1.8.1.6
466 + *
467 + * @return void
468 + */
469 + public function render_tools_page() {
470 + charitable_admin_view( 'tools/tools' );
471 + }
472 +
473 + /**
474 + * Display the Charitable SMTP page.
475 + *
476 + * @since 1.8.1.8
477 + *
478 + * @return void
479 + */
480 + public function render_smtp_page() {
481 + charitable_admin_view( 'smtp/smtp' );
482 + }
483 +
484 + /**
485 + * Display the Charitable About page.
486 + *
487 + * @since 1.8.7.6
488 + *
489 + * @return void
490 + */
491 + public function render_about_page() {
492 + charitable_admin_view( 'about/about' );
493 + }
494 +
495 + /**
496 + * Display the Charitable Growth Tools page.
497 + *
498 + * @since 1.8.1.6
499 + *
500 + * @return void
501 + */
502 + public function render_growth_tools_page() {
503 + charitable_admin_view( 'growth-tools/growth-tools' );
504 + }
505 +
506 + /**
507 + * Display the Charitable Privacy Compliance page.
508 + *
509 + * @since 1.8.8
510 + *
511 + * @return void
512 + */
513 + public function render_privacy_compliance_page() {
514 + charitable_admin_view( 'privacy-compliance/privacy-compliance' );
515 + }
516 +
517 + /**
518 + * Display the Charitable Backups page.
519 + *
520 + * @since 1.8.8
521 + *
522 + * @return void
523 + */
524 + public function render_backups_page() {
525 + charitable_admin_view( 'backups/backups' );
526 + }
527 +
528 + /**
529 + * Display the Charitable SEO page.
530 + *
531 + * @since 1.8.8
532 + *
533 + * @return void
534 + */
535 + public function render_seo_page() {
536 + charitable_admin_view( 'seo/seo' );
537 + }
538 +
539 + /**
540 + * Display the Charitable Automation page.
541 + *
542 + * @since 1.8.8
543 + *
544 + * @return void
545 + */
546 + public function render_automation_page() {
547 + charitable_admin_view( 'automation/automation' );
548 + }
549 +
550 + /**
551 + * Dynamic admin page renderer for rotating marketing submenu items.
552 + *
553 + * @since 1.8.8
554 + *
555 + * @return void
556 + */
557 + public function admin_page() {
558 + $rotation = $this->get_rotating_marketing_submenu();
559 + if ( ! $rotation ) {
560 + return;
561 + }
562 +
563 + $menu_slug = $rotation['menu_slug'];
564 +
565 + switch ( $menu_slug ) {
566 + case 'charitable-privacy-compliance':
567 + $this->render_privacy_compliance_page();
568 + break;
569 + case 'charitable-backups':
570 + $this->render_backups_page();
571 + break;
572 + case 'charitable-seo':
573 + $this->render_seo_page();
574 + break;
575 + case 'charitable-automation':
576 + $this->render_automation_page();
577 + break;
578 + default:
579 + // Fallback to privacy compliance if unknown
580 + $this->render_privacy_compliance_page();
581 + break;
582 + }
583 + }
584 +
585 + /**
586 + * Display the Charitable dashboard page.
587 + *
588 + * @since 1.8.1
589 + *
590 + * @return void
591 + */
592 + public function render_dashboard_page() {
593 + $this->enqueue_dashboard_spinner_script();
594 + charitable_admin_view( 'dashboard/dashboard' );
595 + }
596 +
597 + /**
598 + * Display the Charitable dashboard new page.
599 + *
600 + * @since 1.8.1
601 + *
602 + * @return void
603 + */
604 + public function render_dashboard_new_page() {
605 + $this->enqueue_dashboard_spinner_script();
606 + charitable_admin_view( 'dashboard/dashboard-legacy' );
607 + }
608 +
609 + /**
610 + * Enqueue dashboard spinner script
611 + *
612 + * @since 1.8.7.5
613 + *
614 + * @return void
615 + */
616 + private function enqueue_dashboard_spinner_script() {
617 + // Add inline script to hide spinner when dashboard content loads
618 + wp_add_inline_script( 'charitable-admin-dashboard', '
619 + (function() {
620 + // Hide spinners immediately when dashboard content is detected
621 + function hideDashboardSpinners() {
622 + document.body.classList.add("charitable-dashboard-loaded");
623 + var dashboardV2 = document.getElementById("charitable-dashboard-v2");
624 + if (dashboardV2) {
625 + dashboardV2.classList.add("charitable-dashboard-loaded");
626 + }
627 + }
628 +
629 + // Hide spinners on DOM ready
630 + if (document.readyState === "loading") {
631 + document.addEventListener("DOMContentLoaded", hideDashboardSpinners);
632 + } else {
633 + hideDashboardSpinners();
634 + }
635 +
636 + // Also hide spinners when dashboard content is detected
637 + var checkForContent = function() {
638 + var hasContent = document.querySelector("#charitable-dashboard-v2 .charitable-dashboard-v2-content") ||
639 + document.querySelector("#charitable-dashboard-report-container") ||
640 + document.querySelector(".charitable-dashboard-report");
641 +
642 + if (hasContent) {
643 + hideDashboardSpinners();
644 + } else {
645 + setTimeout(checkForContent, 100);
646 + }
647 + };
648 +
649 + // Start checking for content after a short delay
650 + setTimeout(checkForContent, 200);
651 + })();
652 + ' );
653 + }
654 +
655 + /**
237 656 * Display the Charitable settings page.
238 657 *
239 658 * @since 1.0.0
240 659 *
@@ -244,8 +663,19 @@
244 663 charitable_admin_view( 'settings/settings' );
245 664 }
246 665
247 666 /**
667 + * Display the Charitable addons page.
668 + *
669 + * @since 1.7.0.4
670 + *
671 + * @return void
672 + */
673 + public function render_addons_directory_page() {
674 + charitable_admin_view( 'addons-directory/addons-directory' );
675 + }
676 +
677 + /**
248 678 * Display the Charitable donations page.
249 679 *
250 680 * @since 1.0.0
251 681 *
@@ -290,9 +720,9 @@
290 720 'meta_query' => array(
291 721 'relation' => 'OR',
292 722 array(
293 723 'key' => '_campaign_end_date',
294 - 'value' => date( 'Y-m-d H:i:s' ),
724 + 'value' => date( 'Y-m-d H:i:s' ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
295 725 'compare' => '>=',
296 726 'type' => 'datetime',
297 727 ),
298 728 array(
@@ -317,8 +747,70 @@
317 747 $url = home_url();
318 748 }
319 749
320 750 return urlencode( $url );
751 + }
752 +
753 + /**
754 + * Handle plugin installation to set timestamps for rotating menu items.
755 + *
756 + * @since 1.8.8
757 + *
758 + * @param WP_Upgrader $upgrader The upgrader instance.
759 + * @param array $hook_extra Extra arguments passed to hooked filters.
760 + * @return void
761 + */
762 + public function handle_plugin_installation( $upgrader, $hook_extra ) {
763 + // Only process plugin installations, not updates
764 + if ( ! isset( $hook_extra['type'] ) || 'plugin' !== $hook_extra['type'] ) {
765 + return;
766 + }
767 +
768 + // Only process installations, not updates
769 + if ( ! isset( $hook_extra['action'] ) || 'install' !== $hook_extra['action'] ) {
770 + return;
771 + }
772 +
773 + $items = $this->get_marketing_rotation_items();
774 + $current_time = time();
775 +
776 + foreach ( $items as $item ) {
777 + $option_name = $item['option_name'] ?? '';
778 + $option_key = $item['option_key'] ?? '';
779 + $plugin_file = $item['plugin_file'] ?? '';
780 +
781 + if ( empty( $option_name ) || empty( $plugin_file ) ) {
782 + continue;
783 + }
784 +
785 + // Check if the installed plugin matches our rotating menu items
786 + $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file;
787 + if ( file_exists( $plugin_path ) ) {
788 + // Set timestamp for this plugin installation
789 + $existing_option = get_option( $option_name );
790 +
791 + if ( is_array( $existing_option ) ) {
792 + $existing_option[ $option_key ] = $current_time;
793 + update_option( $option_name, $existing_option );
794 + } else {
795 + update_option( $option_name, array( $option_key => $current_time ) );
796 + }
797 + }
798 + }
799 + }
800 +
801 + /**
802 + * Handle plugin activation to set timestamps for rotating menu items.
803 + * (Kept for reference but not used in current implementation)
804 + *
805 + * @since 1.8.8
806 + *
807 + * @param string $plugin The plugin file that was activated.
808 + * @return void
809 + */
810 + public function handle_plugin_activation( $plugin ) {
811 + // This method is kept for reference but not used in current implementation
812 + // The rotating menu now tracks installations instead of activations
321 813 }
322 814 }
323 815
324 816 endif;