'; $data_uri = 'data:image/svg+xml;base64,' . base64_encode( $svg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- the icon as WordPress expects it return $data_uri; } /** Shared "WinnyPlus" parent menu, so other WinnyPlus plugins can add their pages under it. */ public static function register_parent_menu() { if ( defined( 'WINNYPLUS_PARENT_MENU_REGISTERED' ) ) { return; } define( 'WINNYPLUS_PARENT_MENU_REGISTERED', true ); add_menu_page( __( 'WinnyPlus', 'winnyplus' ), __( 'WinnyPlus', 'winnyplus' ), self::CAP, 'winnyplus', array( __CLASS__, 'render_hub' ), self::menu_icon_data_uri(), 56 ); } public static function menu() { self::register_parent_menu(); add_submenu_page( 'winnyplus', __( 'WinnyPlus', 'winnyplus' ), __( 'Home', 'winnyplus' ), self::CAP, 'winnyplus', array( __CLASS__, 'render_hub' ) ); add_submenu_page( 'winnyplus', __( 'WinnyPlus Connect', 'winnyplus' ), __( 'What is sent', 'winnyplus' ), self::CAP, 'winnyplus', array( __CLASS__, 'render_sync' ) ); } /** The menu entry's own colors, added to the admin styles on every admin page. */ private static function menu_css() { return '#adminmenu #toplevel_page_winnyplus .wp-menu-image.svg, #adminmenu #toplevel_page_winnyplus .wp-menu-image { background-size: 20px auto !important; }' . '#adminmenu #toplevel_page_winnyplus > a.menu-top:hover, #adminmenu #toplevel_page_winnyplus.wp-has-current-submenu > a.wp-has-current-submenu, #adminmenu #toplevel_page_winnyplus.current > a.menu-top, #adminmenu #toplevel_page_winnyplus.wp-has-current-submenu:hover > a.wp-has-current-submenu { background: #00A859 !important; color: #fff !important; }' . '#adminmenu #toplevel_page_winnyplus.wp-has-current-submenu .wp-menu-image, #adminmenu #toplevel_page_winnyplus:hover .wp-menu-image { opacity: 1 !important; }'; } public static function assets( $hook ) { wp_register_style( 'winnyplus-connect-menu', false, array(), WINNYPLUS_CONNECT_VERSION ); wp_enqueue_style( 'winnyplus-connect-menu' ); wp_add_inline_style( 'winnyplus-connect-menu', self::menu_css() ); // Deleting the plugin erases its data: ask first (the Plugins page only) if ( 'plugins.php' === $hook ) { wp_enqueue_script( 'winnyplus-connect-plugins', WINNYPLUS_CONNECT_PLUGIN_URL . 'assets/js/plugins-page.js', array(), WINNYPLUS_CONNECT_VERSION, true ); wp_localize_script( 'winnyplus-connect-plugins', 'WINNYPLUS_CONNECT_PLUGINS', array( 'plugin' => plugin_basename( WINNYPLUS_CONNECT_PLUGIN_FILE ), 'message' => __( 'Warning: deleting WinnyPlus Connect will permanently erase its data from your database (the connection to WinnyPlus), and this cannot be undone. Are you sure you want to delete it?', 'winnyplus' ), ) ); } if ( strpos( $hook, 'winnyplus' ) === false ) { return; } wp_enqueue_style( 'winnyplus-connect-admin', WINNYPLUS_CONNECT_PLUGIN_URL . 'assets/css/admin.css', array(), WINNYPLUS_CONNECT_VERSION ); wp_enqueue_script( 'winnyplus-connect-admin', WINNYPLUS_CONNECT_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery' ), WINNYPLUS_CONNECT_VERSION, true ); wp_localize_script( 'winnyplus-connect-admin', 'WINNYPLUS_CONNECT_ADMIN', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'pair_nonce' => wp_create_nonce( 'winnyplus_connect_pair_connection' ), 'disconnect_nonce' => wp_create_nonce( 'winnyplus_connect_disconnect_connection' ), 'i18n' => array( 'connecting' => __( 'Connecting...', 'winnyplus' ), 'disconnecting' => __( 'Disconnecting...', 'winnyplus' ), 'connectionErr' => __( 'A connection error occurred', 'winnyplus' ), 'enterCodeFirst' => __( 'Please enter the Connection Code first.', 'winnyplus' ), 'confirmDisconnect' => __( 'Are you sure you want to disconnect from the WinnyPlus platform?', 'winnyplus' ), ), ) ); } /** ------------------- AJAX: pairing and disconnecting ------------------- */ public static function ajax_pair_connection() { check_ajax_referer( 'winnyplus_connect_pair_connection', 'nonce' ); if ( ! current_user_can( self::CAP ) ) { wp_send_json_error( array( 'message' => __( 'Not allowed', 'winnyplus' ) ) ); } $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : ''; $code = isset( $_POST['connection_code'] ) ? sanitize_text_field( wp_unslash( $_POST['connection_code'] ) ) : ''; $result = WinnyPlus_Connect_Connection::pair( $site_url, $code ); if ( $result['success'] ) { wp_send_json_success( array( 'installation_id' => $result['installation_id'], 'message' => __( 'Connected successfully.', 'winnyplus' ), ) ); } wp_send_json_error( array( 'message' => $result['error'] ) ); } public static function ajax_disconnect_connection() { check_ajax_referer( 'winnyplus_connect_disconnect_connection', 'nonce' ); if ( ! current_user_can( self::CAP ) ) { wp_send_json_error( array( 'message' => __( 'Not allowed', 'winnyplus' ) ) ); } WinnyPlus_Connect_Connection::disconnect(); wp_send_json_success( array( 'message' => __( 'Disconnected.', 'winnyplus' ) ) ); } /** ------------------- Plugins page ------------------- */ public static function plugin_action_links( $links ) { array_unshift( $links, sprintf( '%s', esc_url( admin_url( 'admin.php?page=winnyplus' ) ), esc_html__( 'Settings', 'winnyplus' ) ) ); return $links; } /** ------------------- Shared layout ------------------- */ /** * The top of every page: the brand of WinnyPlus, where this store is connected to, and the pages of the plugin as one tab bar. Every page of the plugin * is the same product, so it looks the same and the way around it is always in the same place. */ private static function hero( $active, $overview = null ) { $connected = WinnyPlus_Connect_Connection::is_connected(); $brand = is_array( $overview ) && ! empty( $overview['brand']['name'] ) ? $overview['brand']['name'] : ''; $tabs = array( 'winnyplus' => array( __( 'Home', 'winnyplus' ), 'bolt' ), 'winnyplus' => array( __( 'What is sent', 'winnyplus' ), 'plug' ), ); ?>

WinnyPlus

'; self::hero( $active, $overview ); echo '
'; } /** The way through setup as four steps, with the next thing to do under it. */ private static function steps( $connected, $has_service, $events_on, $sent_today, $links ) { $steps = array( array( __( 'Connect your store', 'winnyplus' ), __( 'Pair this site with your WinnyPlus account.', 'winnyplus' ), $connected ), array( __( 'Choose your services', 'winnyplus' ), __( 'Subscribe to what your business needs.', 'winnyplus' ), $has_service ), array( __( 'Decide what is sent', 'winnyplus' ), __( 'Orders, customers, carts and products, as your services need them.', 'winnyplus' ), $events_on > 0 ), array( __( 'Follow it from the dashboard', 'winnyplus' ), __( 'Orders, carts and numbers, in one place.', 'winnyplus' ), $sent_today > 0 ), ); $current = count( $steps ); foreach ( $steps as $i => $step ) { if ( ! $step[2] ) { $current = $i; break; } } ?>
    $step ) : ?>
%s %s

', esc_url( $next[1] ), esc_html( $next[0] ), WinnyPlus_Connect_Icons::markup( 'arrow' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- markup() is already filtered with wp_kses } } /** One service: where the brand stands with it, what it uses from the store, its numbers, and the next thing to do. */ private static function service_card( array $service ) { $state = isset( $service['state'] ) ? $service['state'] : 'available'; $chips = array( 'active' => array( __( 'Active', 'winnyplus' ), __( 'Open', 'winnyplus' ) ), 'paused' => array( __( 'Cancelled', 'winnyplus' ), __( 'Renew subscription', 'winnyplus' ) ), 'available' => array( __( 'Not subscribed', 'winnyplus' ), __( 'Activate', 'winnyplus' ) ), ); $chip = isset( $chips[ $state ] ) ? $chips[ $state ] : $chips['available']; $color = ! empty( $service['color'] ) && preg_match( '/^#[0-9a-fA-F]{3,8}$/', $service['color'] ) ? $service['color'] : '#00A859'; $feeds = ! empty( $service['feeds'] ) && is_array( $service['feeds'] ) ? $service['feeds'] : array(); $stats = ! empty( $service['stats'] ) && is_array( $service['stats'] ) ? $service['stats'] : array(); ?>

' . WinnyPlus_Connect_Icons::markup( 'alert' ) . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- markup() is already filtered with wp_kses echo '' . esc_html( $read['stale'] ? __( 'Showing the last view we saved', 'winnyplus' ) : __( 'WinnyPlus could not be reached', 'winnyplus' ) ) . ' '; echo esc_html( $read['error'] ) . ' '; printf( '%s', esc_url( wp_nonce_url( admin_url( 'admin.php?page=winnyplus&winnyplus_connect_refresh=1' ), 'winnyplus_connect_refresh_overview' ) ), esc_html__( 'Try again', 'winnyplus' ) ); echo '
'; } if ( $connected ) { ?>

1 ) : ?>

'; } /** Not connected: pair this site with a WinnyPlus account, in three steps. */ private static function connect_panel() { ?>

  1. 1
  2. 2
  3. 3

↗ ↗

'orders', 'customers' => 'customers', 'funnel' => 'carts', 'products' => 'products' ); ?>

$module ) : ?>

$label ) : ?>