✏️ 正在编辑: class-tasks.php
路径:
/home/eblama1/mintawon.farm/wp-content/plugins/burst-statistics/includes/Admin/class-tasks.php
提示:
您可以编辑任何文件(包括二进制文件),但请注意不当修改可能导致文件损坏。
<?php namespace Burst\Admin; // don't remove, it is used in the Tasks code. use Burst\Traits\Admin_Helper; use Burst\Traits\Helper; defined( 'ABSPATH' ) || die(); class Tasks { use Helper; use Admin_Helper; public array $tasks = []; /** * Get all structured app data. * * @return array{ * tasks: array<int, array{ * id: string, * icon: string, * condition: array<string, mixed>|callable[], * status: string, * label: string * }> * } */ public function get(): array { return [ 'tasks' => $this->get_tasks(), ]; } /** * Add initial tasks that are marked with ['condition']['type'] === activation by inserting an option */ public function add_initial_tasks(): void { $tasks = $this->get_raw_tasks(); foreach ( $tasks as $task ) { if ( isset( $task['condition']['type'] ) && $task['condition']['type'] === 'activation' ) { $this->add_task( $task['id'] ); } } } /** * Tasks should never get validated directly, always use this schedule function */ public function schedule_task_validation(): void { if ( ! wp_next_scheduled( 'burst_validate_tasks' ) ) { wp_schedule_single_event( time() + 30, 'burst_validate_tasks' ); } } /** * Insert a task */ public function add_task( string $task_id ): void { $current_tasks = get_option( 'burst_tasks', [] ); $permanently_dismissed = $this->is_dismissed_permanently( $task_id ); if ( $permanently_dismissed ) { return; } if ( ! in_array( $task_id, $current_tasks, true ) ) { $current_tasks[] = sanitize_title( $task_id ); update_option( 'burst_tasks', $current_tasks, false ); } } /** * Check if this task is permanently dismissed. */ private function is_dismissed_permanently( string $task_id ): bool { $task = $this->get_task_by_id( $task_id ); if ( isset( $task['dismiss_permanently'] ) && $task['dismiss_permanently'] ) { $permanently_dismissed = get_option( 'burst_tasks_permanently_dismissed', [] ); if ( in_array( $task_id, $permanently_dismissed, true ) ) { return true; } } return false; } /** * Remove a task from the permanently dismissed list. */ public function undismiss_task( string $task_id ): bool { $permanently_dismissed = get_option( 'burst_tasks_permanently_dismissed', [] ); $key = array_search( $task_id, $permanently_dismissed, true ); if ( $key !== false ) { unset( $permanently_dismissed[ $key ] ); $permanently_dismissed = array_values( $permanently_dismissed ); update_option( 'burst_tasks_permanently_dismissed', $permanently_dismissed, false ); return true; } return false; } /** * Dismiss a task */ public function dismiss_task( string $task_id ): void { $current_tasks = get_option( 'burst_tasks', [] ); if ( in_array( sanitize_title( $task_id ), $current_tasks, true ) ) { do_action( 'burst_dismiss_task', $task_id ); $current_tasks = array_diff( $current_tasks, [ $task_id ] ); update_option( 'burst_tasks', $current_tasks, false ); // only dismiss permanently if the task exists in the tasks array. $this->maybe_dismiss_permanently( $task_id ); } delete_transient( 'burst_plusone_count' ); } /** * Store task as dismissed permanently */ private function maybe_dismiss_permanently( string $task_id ): void { $task = $this->get_task_by_id( $task_id ); if ( isset( $task['dismiss_permanently'] ) && $task['dismiss_permanently'] ) { $permanently_dismissed = get_option( 'burst_tasks_permanently_dismissed', [] ); if ( ! in_array( $task_id, $permanently_dismissed, true ) ) { $permanently_dismissed[] = $task_id; } update_option( 'burst_tasks_permanently_dismissed', $permanently_dismissed, false ); } } /** * Check if a task is active */ public function has_task( string $task_id ): bool { $current_tasks = get_option( 'burst_tasks', [] ); return in_array( sanitize_title( $task_id ), $current_tasks, true ); } /** * Validate tasks * Don't call directly. Use the schedule_task_validation function */ public function validate_tasks(): void { $tasks = $this->get_raw_tasks(); foreach ( $tasks as $task ) { if ( isset( $task['condition']['type'] ) && $task['condition']['type'] === 'serverside' ) { if ( isset( $task['condition']['constant'] ) ) { $invert = str_contains( $task['condition']['constant'], '!' ); $constant = $invert ? substr( $task['condition']['constant'], 1 ) : $task['condition']['constant']; $is_valid = defined( $constant ); } else { $invert = str_contains( $task['condition']['function'], '!' ); $function = $invert ? substr( $task['condition']['function'], 1 ) : $task['condition']['function']; $is_valid = $this->validate_function( $function ); } if ( $invert ) { $is_valid = ! $is_valid; } if ( $is_valid ) { $this->add_task( $task['id'] ); } else { $this->dismiss_task( $task['id'] ); } } } delete_transient( 'burst_plusone_count' ); } /** * Get raw tasks directly from the config file and apply transformations. * * @return array<int, array{ * id: string, * url?: string, * icon?: string, * condition?: mixed * }> */ public function get_raw_tasks(): array { if ( empty( $this->tasks ) ) { $tasks = require BURST_PATH . 'includes/Admin/App/config/tasks.php'; $this->tasks = apply_filters( 'burst_tasks', $tasks ); } // convert URL to website URL. foreach ( $this->tasks as $key => $task ) { if ( isset( $task['url'] ) ) { // if url starts with #, we want to link internally. So we can just return the url. if ( str_starts_with( $task['url'], '#' ) ) { continue; } // if url starts with https://, it's not a link to burst-statistics, but to an external website. if ( strpos( $task['url'], 'https://' ) === 0 ) { continue; } $this->tasks[ $key ]['url'] = $this->get_website_url( $task['url'], [ 'utm_source' => 'tasks', 'utm_content' => $task['id'], ] ); } } return $this->tasks; } /** * Get array of tasks with metadata, filtered and sorted. * * Each task contains: * - 'id': string * - 'icon': string ('open', 'success', 'error', 'warning', etc.) * - 'condition': callable[]|array<string, mixed> * - 'status': string ('open' or 'completed') * - 'label': string * * @return array<int, array{ * id: string, * icon: string, * condition: array<string, mixed>|callable[], * status: string, * label: string * }> */ public function get_tasks(): array { $tasks = $this->get_raw_tasks(); foreach ( $tasks as $index => $task ) { $tasks[ $index ] = wp_parse_args( $task, [ 'condition' => [], 'icon' => 'open', ] ); } // Filter out tasks that do not apply, or are dismissed. $dismiss_non_error_tasks = $this->get_option_bool( 'dismiss_non_error_notices' ); foreach ( $tasks as $index => $task ) { // set task status based on current icon. $tasks[ $index ]['status'] = $task['icon'] !== 'success' ? 'open' : 'completed'; // get the translated label. $tasks[ $index ]['label'] = $this->get_label( $task['icon'] ); if ( isset( $task['condition']['type'] ) && $task['condition']['type'] === 'clientside' ) { continue; } // remove this option if it's dismissed. if ( ! $this->has_task( $task['id'] ) ) { unset( $tasks[ $index ] ); } // dismiss all non error tasks if this option is enabled. if ( $dismiss_non_error_tasks && $task['icon'] !== 'error' ) { unset( $tasks[ $index ] ); } } $tasks = $this->filter_unique_ids( $tasks ); // sort so warnings are on top. $warnings = []; $open = []; $other = []; foreach ( $tasks as $index => $task ) { if ( $task['icon'] === 'warning' ) { $warnings[ $index ] = $task; } elseif ( $task['icon'] === 'open' ) { $open[ $index ] = $task; } else { $other[ $index ] = $task; } } return $warnings + $open + $other; } /** * Get translated label */ private function get_label( string $icon ): string { $icon_labels = [ 'completed' => __( 'Completed', 'burst-statistics' ), 'new' => __( 'New!', 'burst-statistics' ), 'warning' => __( 'Warning', 'burst-statistics' ), 'error' => __( 'Error', 'burst-statistics' ), 'open' => __( 'Open', 'burst-statistics' ), 'pro' => __( 'Pro', 'burst-statistics' ), 'sale' => __( 'Sale', 'burst-statistics' ), 'offer' => __( 'Offer', 'burst-statistics' ), 'milestone' => __( 'Milestone', 'burst-statistics' ), 'insight' => __( 'Update', 'burst-statistics' ), ]; return $icon_labels[ $icon ]; } /** * Remove duplicate IDs from the tasks array, keeping the last occurrence. * * @return array<int, array{id: string, icon: string, condition: mixed, status: string, label: string}> */ private function filter_unique_ids( array $tasks ): array { $unique_tasks = []; foreach ( $tasks as $task ) { // Check if the id already exists in the unique array. if ( ! in_array( $task['id'], array_column( $unique_tasks, 'id' ), true ) ) { // If the id is not in the unique array, add the current task. $unique_tasks[] = $task; } else { // if it is already in the array, replace the previous one. $index = array_search( $task['id'], array_column( $unique_tasks, 'id' ), true ); $unique_tasks[ $index ] = $task; } } return $unique_tasks; } /** * Get a task by ID. */ public function get_task_by_id( string $task_id ): ?array { $tasks = $this->get_raw_tasks(); foreach ( $tasks as $task ) { if ( $task['id'] === $task_id ) { return $task; } } return null; } /** * Count the plusones * * @since 3.2 */ public function plusone_count(): int { if ( ! $this->user_can_manage() ) { return 0; } $cache = ! $this->is_burst_page(); $count = get_transient( 'burst_plusone_count' ); if ( ! $cache || ( $count === false ) ) { $count = 0; $notices = $this->get_tasks(); foreach ( $notices as $id => $notice ) { $success = isset( $notice['icon'] ) && $notice['icon'] === 'success'; if ( ! $success && isset( $notice['plusone'] ) && $notice['plusone'] ) { ++$count; } } if ( $count === 0 ) { $count = 'empty'; } set_transient( 'burst_plusone_count', $count, DAY_IN_SECONDS ); } if ( $count === 'empty' ) { return 0; } return $count; } /** * Get output of function, in format 'function', or 'class()->sub()->function' */ private function validate_function( string $func ): bool { $invert = false; if ( str_contains( $func, '! ' ) ) { $func = str_replace( '!', '', $func ); $invert = true; } if ( str_contains( $func, 'wp_option_' ) ) { $output = get_option( str_replace( 'wp_option_', '', $func ) ) !== false; } else { if ( preg_match( '/(.*)\(\)\-\>(.*)->(.*)/i', $func, $matches ) ) { $base = $matches[1]; $class = $matches[2]; $function = $matches[3]; $output = call_user_func( [ $base()->{$class}, $function ] ); } elseif ( preg_match( '/^\s*([\w\\\\]+)::(\w+)\s*\(\s*\)\s*$/', $func, $matches ) ) { $class = $matches[1]; $function = $matches[2]; if ( $class === 'Tasks' ) { // @phpstan-ignore-next-line $output = self::$function(); } else { // @phpstan-ignore-next-line $output = $class::$function(); } } elseif ( preg_match( '/\s*\(\s*new\s+(.*)\s*\(\s*\)\s*\)\s*->\s*(.*)\s*\(\s*\)/', $func, $matches ) ) { $class = $matches[1]; $function = $matches[2]; if ( $class === 'Tasks' ) { $output = call_user_func( [ $this, $function ] ); } else { $class_obj = new $class(); $output = call_user_func( [ $class_obj, $function ] ); } } else { $output = $func(); } if ( $invert ) { $output = ! $output; } if ( $invert ) { $output = ! $output; } } return (bool) $output; } /** * Whether we should show the MainWP integration reminder task. */ public static function should_show_mainwp_integration_task(): bool { $mainwp_child_plugin = 'mainwp-child/mainwp-child.php'; if ( ! file_exists( WP_PLUGIN_DIR . '/' . $mainwp_child_plugin ) ) { return false; } if ( ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $is_mainwp_child_active = is_plugin_active( $mainwp_child_plugin ); if ( is_multisite() ) { $is_mainwp_child_active = $is_mainwp_child_active || is_plugin_active_for_network( $mainwp_child_plugin ); } if ( ! $is_mainwp_child_active ) { return false; } $options = get_option( 'burst_options_settings', [] ); // Return true if integration is available but not yet enabled (show setup task). return empty( $options['enable_mainwp_integration'] ); } }
💾 保存文件
← 返回文件管理器