' . esc_html( $label ) . ''; array_unshift( $links, $settings ); return $links; } public static function handle_notice_dismiss() { if ( empty( $_GET['quicksync_dismiss'] ) || ! current_user_can( 'manage_woocommerce' ) ) { return; } check_admin_referer( 'quicksync_dismiss' ); $which = sanitize_key( wp_unslash( $_GET['quicksync_dismiss'] ) ); if ( 'activation' === $which ) { delete_option( 'quicksync_show_activation_notice' ); } if ( 'review' === $which ) { QuickSync_Plugin::update_options( array( 'review_dismissed' => 1 ) ); } wp_safe_redirect( remove_query_arg( array( 'quicksync_dismiss', '_wpnonce' ) ) ); exit; } public static function handle_copy() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'You do not have permission to change this connection.', 'quicksync-pro-for-woocommerce' ) ); } check_admin_referer( 'quicksync_copy' ); QuickSync_Identity::treat_as_copy(); wp_safe_redirect( QuickSync_Connect::settings_url() ); exit; } public static function handle_moved() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'You do not have permission to change this connection.', 'quicksync-pro-for-woocommerce' ) ); } check_admin_referer( 'quicksync_moved' ); if ( ! QuickSync_Identity::treat_as_moved() ) { wp_safe_redirect( add_query_arg( 'quicksync_error', rawurlencode( __( 'This site is a different address. Reconnect it as its own store.', 'quicksync-pro-for-woocommerce' ) ), QuickSync_Connect::settings_url() ) ); exit; } wp_safe_redirect( QuickSync_Connect::settings_url() ); exit; } public static function handle_review() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'You do not have permission to dismiss this notice.', 'quicksync-pro-for-woocommerce' ) ); } check_admin_referer( 'quicksync_review' ); $choice = isset( $_POST['quicksync_review'] ) ? sanitize_key( wp_unslash( $_POST['quicksync_review'] ) ) : ''; if ( in_array( $choice, array( 'done', 'later', 'leave' ), true ) ) { QuickSync_Plugin::update_options( array( 'review_dismissed' => 1 ) ); } if ( 'leave' === $choice ) { wp_safe_redirect( self::REVIEW_URL ); exit; } wp_safe_redirect( QuickSync_Connect::settings_url() ); exit; } public static function activation_notice() { if ( ! current_user_can( 'manage_woocommerce' ) ) { return; } if ( ! get_option( 'quicksync_show_activation_notice' ) ) { return; } $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || 'plugins' !== $screen->id ) { return; } $dismiss = wp_nonce_url( add_query_arg( 'quicksync_dismiss', 'activation' ), 'quicksync_dismiss' ); echo '

'; echo esc_html__( 'QuickSync is ready. Open WooCommerce → QuickSync and we will walk you through connect.', 'quicksync-pro-for-woocommerce' ); echo ' ' . esc_html__( 'Connect now', 'quicksync-pro-for-woocommerce' ) . ''; echo ' | ' . esc_html__( 'Dismiss', 'quicksync-pro-for-woocommerce' ) . ''; echo '

'; } public static function review_notice() { if ( ! current_user_can( 'manage_woocommerce' ) ) { return; } if ( ! self::should_ask_review() ) { return; } $dismiss = wp_nonce_url( add_query_arg( 'quicksync_dismiss', 'review' ), 'quicksync_dismiss' ); echo '

'; echo esc_html__( 'Would you share your experience with QuickSync on WordPress.org?', 'quicksync-pro-for-woocommerce' ); echo '

'; echo '' . esc_html__( 'Leave a review', 'quicksync-pro-for-woocommerce' ) . ' '; echo '' . esc_html__( "I've already left a review", 'quicksync-pro-for-woocommerce' ) . ' '; echo '' . esc_html__( 'Dismiss', 'quicksync-pro-for-woocommerce' ) . ''; echo '

'; } public static function should_ask_review() { $opts = QuickSync_Plugin::options(); if ( ! empty( $opts['review_dismissed'] ) ) { return false; } if ( ! QuickSync_Plugin::is_connected() ) { return false; } $connected = (int) $opts['connected_at']; if ( $connected < 1 ) { return false; } return ( time() - $connected ) >= ( 14 * DAY_IN_SECONDS ); } public static function render_page() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'You do not have permission to access this page.', 'quicksync-pro-for-woocommerce' ) ); } delete_option( 'quicksync_show_activation_notice' ); $opts = QuickSync_Plugin::options(); $connected = QuickSync_Plugin::is_connected(); $safe = QuickSync_Identity::in_safe_mode(); // phpcs:disable WordPress.Security.NonceVerification.Recommended -- display-only query args after capability check $error = isset( $_GET['quicksync_error'] ) ? sanitize_text_field( wp_unslash( $_GET['quicksync_error'] ) ) : ''; $just = ! empty( $_GET['quicksync_connected'] ); $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'status'; // phpcs:enable WordPress.Security.NonceVerification.Recommended if ( ! in_array( $tab, array( 'status', 'support' ), true ) ) { $tab = 'status'; } $status = $connected ? QuickSync_Status::remote_status() : array(); if ( $connected && ! empty( $status['account_email'] ) && $status['account_email'] !== $opts['account_email'] ) { QuickSync_Plugin::update_options( array( 'account_email' => sanitize_email( $status['account_email'] ) ) ); $opts['account_email'] = sanitize_email( $status['account_email'] ); } $waiting = (bool) get_transient( 'quicksync_handoff_id' ); $expired = ! $waiting && ! empty( $_GET['quicksync_waiting'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display-only $rerun = ! empty( $_GET['quicksync_rerun'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display-only $checks = array(); if ( 'support' !== $tab ) { $cached = isset( $opts['diagnostics'] ) && is_array( $opts['diagnostics'] ) ? $opts['diagnostics'] : array(); if ( $rerun || ! $cached || ! (int) $opts['diagnostics_checked_at'] ) { $checks = QuickSync_Status::self_test(); QuickSync_Plugin::update_options( array( 'diagnostics' => $checks, 'diagnostics_checked_at' => time(), ) ); $opts['diagnostics_checked_at'] = time(); if ( $rerun ) { wp_safe_redirect( QuickSync_Connect::settings_url() ); exit; } } else { $checks = $cached; } if ( $connected && array_key_exists( 'rest_reachable', $status ) ) { $reachable = ! empty( $status['rest_reachable'] ); $checks[] = array( 'label' => __( 'Reachable from QuickSync', 'quicksync-pro-for-woocommerce' ), 'ok' => $reachable, 'level' => $reachable ? 'ok' : 'warn', 'detail' => $reachable ? '' : __( 'blocked (likely WAF)', 'quicksync-pro-for-woocommerce' ), 'docs' => $reachable ? '' : QuickSync_Status::DOCS_FAQ, ); } } ?>

>

>

>

=' ) || (int) $opts['last_event_at'] > 0 || ! empty( $status['last_event_at'] ); $last_error = (string) $opts['last_error']; $dash_url = ! empty( $status['dashboard_url'] ) ? $status['dashboard_url'] : 'https://app.quicksync.pro/'; ?>

· ·

' . esc_html__( 'Diagnostics', 'quicksync-pro-for-woocommerce' ) . ''; echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built above with escaped values return; } ?>

admin_url( 'admin-ajax.php' ), 'pollNonce' => wp_create_nonce( 'quicksync_handoff' ), 'connectNonce' => wp_create_nonce( 'quicksync_connect' ), 'connectedUrl' => add_query_arg( 'quicksync_connected', '1', QuickSync_Connect::settings_url() ), 'expiredUrl' => add_query_arg( 'quicksync_waiting', '1', QuickSync_Connect::settings_url() ), 'errorUrl' => add_query_arg( 'quicksync_error', 'ERR', QuickSync_Connect::settings_url() ), 'remaining' => $remaining, 'waiting' => (bool) $waiting, 'opening' => __( 'Opening QuickSync…', 'quicksync-pro-for-woocommerce' ), ); wp_add_inline_script( 'quicksync-admin', 'window.quicksyncConnect = ' . wp_json_encode( $config ) . ';', 'before' ); } private static function diagnostics_plaintext( $checks, $checked_at ) { $lines = array( 'QuickSync diagnostics' ); if ( $checked_at ) { $lines[] = 'Last checked: ' . date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $checked_at ); } foreach ( $checks as $check ) { $level = isset( $check['level'] ) ? $check['level'] : ( $check['ok'] ? 'ok' : 'warn' ); $line = $check['label'] . ': ' . strtoupper( $level ); if ( ! empty( $check['detail'] ) && 'ok' !== $level ) { $line .= ' — ' . $check['detail']; } $lines[] = $line; } return implode( "\n", $lines ); } private static function format_time( $ts ) { $ts = (int) $ts; if ( $ts < 1 ) { return __( 'None yet', 'quicksync-pro-for-woocommerce' ); } return date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ); } private static function is_plugins_screen() { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; return $screen && 'plugins' === $screen->id; } }