true ), 'objects' ); unset( $types['attachment'] ); return array_filter( $types, function ( $type ) { return is_post_type_viewable( $type ); } ); } /** * Content types written by visitors rather than the site's own editors * (forums, Q&A, user-submitted listings). Visitors could plant * misleading text or instructions there, so they get a warning. * * @return string[] */ public static function visitor_written_types() { /** * Filters the post types AskMyPages marks as written by visitors. * * @param string[] $types Post type names. */ return (array) apply_filters( 'askmypages_visitor_written_types', array( 'forum', 'topic', 'reply', 'question', 'answer', 'dwqa-question', 'dwqa-answer', 'job_listing', 'resume', 'wpdiscuz', 'testimonial' ) ); } /** * Saves which content goes into search, then runs a full check so newly * included items are sent and excluded ones removed. */ public static function handle_content() { self::guard( 'askmypages_content' ); // phpcs:disable WordPress.Security.NonceVerification.Missing -- checked in guard(). $posted = isset( $_POST['post_types'] ) ? array_map( 'sanitize_key', (array) wp_unslash( $_POST['post_types'] ) ) : array(); $terms = isset( $_POST['exclude_terms'] ) ? array_map( 'absint', (array) wp_unslash( $_POST['exclude_terms'] ) ) : array(); // phpcs:enable WordPress.Security.NonceVerification.Missing $types = array_values( array_intersect( $posted, array_keys( self::selectable_types() ) ) ); update_option( Sync::OPT_POST_TYPES, $types, false ); update_option( Sync::OPT_PDFS, isset( $_POST['pdfs'] ) ? '1' : '0', false ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- checked in guard(). update_option( Sync::OPT_EXCLUDE_TERMS, array_values( array_filter( $terms ) ), false ); if ( Keys::is_connected() ) { as_enqueue_async_action( Sync::HOOK_RECONCILE, array(), Sync::GROUP ); } delete_transient( 'askmypages_status' ); self::back( 'content_saved' ); } /** * "Leave out of search" box on the edit screen of indexed types. * * @param string $post_type Post type of the screen. */ public static function add_exclude_box( $post_type = '' ) { foreach ( Sync::post_types() as $type ) { add_meta_box( 'askmypages-exclude', 'AskMyPages', array( __CLASS__, 'render_exclude_box' ), $type, 'side', 'low' ); } // PDFs, on their Media Library edit screen. $post = get_post(); if ( 'attachment' === $post_type && Sync::pdfs_enabled() && $post && 'application/pdf' === $post->post_mime_type ) { add_meta_box( 'askmypages-exclude', 'AskMyPages', array( __CLASS__, 'render_exclude_box' ), 'attachment', 'side', 'low' ); } } /** * Renders the box: exclude from the index, or mark as members-only * (with roles) when members-only content is on. * * @param \WP_Post $post Post. */ public static function render_exclude_box( $post ) { wp_nonce_field( 'askmypages_exclude', 'askmypages_exclude_nonce' ); printf( '

', checked( '1', (string) get_post_meta( $post->ID, Sync::META_EXCLUDE, true ), false ), esc_html__( 'Exclude from AskMyPages', 'askmypages' ) ); if ( ! Access::members_enabled() ) { return; } $vis = (string) get_post_meta( $post->ID, Access::META_VISIBILITY, true ); $roles = array_map( 'sanitize_key', (array) get_post_meta( $post->ID, Access::META_ROLES, true ) ); printf( '

', checked( true, in_array( $vis, array( 'members', 'roles' ), true ), false ), esc_html__( 'Members only', 'askmypages' ) ); echo '
'; foreach ( wp_roles()->get_names() as $role => $role_name ) { printf( '', esc_attr( $role ), checked( in_array( $role, $roles, true ), true, false ), esc_html( translate_user_role( $role_name ) ) ); } echo '
'; echo '

' . esc_html__( 'Members only: answered from for logged-in users with these roles (none ticked: any logged-in user).', 'askmypages' ) . '

'; } /** * Saves the box and updates the index for this post. * * @param int $post_id Post id. * @param \WP_Post $post Post. */ public static function save_exclude_box( $post_id, $post ) { if ( ! isset( $_POST['askmypages_exclude_nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['askmypages_exclude_nonce'] ) ), 'askmypages_exclude' ) ) { return; } if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) { return; } if ( isset( $_POST['askmypages_exclude'] ) ) { update_post_meta( $post_id, Sync::META_EXCLUDE, '1' ); } else { delete_post_meta( $post_id, Sync::META_EXCLUDE ); } if ( isset( $_POST['askmypages_members'] ) ) { $roles = isset( $_POST['askmypages_roles'] ) ? array_map( 'sanitize_key', (array) wp_unslash( $_POST['askmypages_roles'] ) ) : array(); $roles = array_values( array_intersect( $roles, array_keys( wp_roles()->get_names() ) ) ); update_post_meta( $post_id, Access::META_VISIBILITY, $roles ? 'roles' : 'members' ); update_post_meta( $post_id, Access::META_ROLES, $roles ); } else { delete_post_meta( $post_id, Access::META_VISIBILITY ); delete_post_meta( $post_id, Access::META_ROLES ); } if ( ! Keys::is_connected() ) { return; } if ( Sync::is_eligible( $post ) ) { Sync::queue( Sync::HOOK_SYNC, $post_id ); } elseif ( get_post_meta( $post_id, Sync::META_HASH, true ) ) { Sync::queue( Sync::HOOK_DELETE, $post_id ); } } /** * Content tab: what goes into search. * * @param array|null $status Status from the service, if available. */ private static function tab_content( $status ) { $selected = Sync::post_types(); $allowed = Sync::custom_types_allowed(); $excluded = Sync::excluded_terms(); $total = 0; self::render_counts( $status ); self::render_skipped_pdfs(); ?>

'category', 'hide_empty' => false, 'number' => 200, ) ); if ( is_array( $categories ) && $categories ) : ?>

> | >

' . esc_html__( 'The list could not be loaded right now. Check the Connection tab.', 'askmypages' ) . '

'; return; } $items = (array) ( $result['items'] ?? array() ); $total = (int) ( $result['total'] ?? 0 ); $per = max( 1, (int) ( $result['perPage'] ?? 20 ) ); if ( ! $items ) { echo '

' . esc_html( $problems ? __( 'No problems: everything sent is in search.', 'askmypages' ) : __( 'Nothing has been sent yet.', 'askmypages' ) ) . '

'; return; } ?>
labels->singular_name : (string) ( $item['postType'] ?? '' ) ); } ?>
1 ) { $link = static function ( $n ) use ( $base, $problems ) { $args = array( 'items_page' => $n ); if ( $problems ) { $args['items'] = 'problems'; } return add_query_arg( $args, $base ) . '#askmypages-items'; }; echo '

'; if ( $page > 1 ) { echo '' . esc_html__( 'Newer', 'askmypages' ) . ' '; } /* translators: 1: page number, 2: number of pages. */ echo esc_html( sprintf( __( 'Page %1$s of %2$s', 'askmypages' ), number_format_i18n( $page ), number_format_i18n( $pages ) ) ); if ( $page < $pages ) { echo ' ' . esc_html__( 'Older', 'askmypages' ) . ''; } echo '

'; } ?> 'attachment', 'post_status' => 'inherit', 'meta_key' => Sync::META_PDF_ISSUE, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- small admin-only query. 'posts_per_page' => 50, 'fields' => 'ids', ) ); if ( ! $skipped ) { return; } $reasons = array( 'pdf_pages_exceeded' => __( 'over the plan\'s PDF page allowance (Free: 150 pages in total; Starter: 2,500; Business: 10,000)', 'askmypages' ), 'pdf_bytes_exceeded' => __( 'over the plan\'s PDF storage allowance (Free: 50 MB in total; Starter: 500 MB; Business: 2 GB)', 'askmypages' ), 'no_text' => __( 'no readable text (scanned?)', 'askmypages' ), 'invalid_pdf' => __( 'could not be read', 'askmypages' ), 'quota_exceeded' => __( 'over the plan\'s item limit', 'askmypages' ), ); echo '

' . esc_html__( 'Some PDFs are not in search:', 'askmypages' ) . '

'; } /** * The menu icon: the AskMyPages mark in one colour, which WordPress * recolours to match the admin colour scheme. * * @return string Data URI. */ private static function menu_icon() { $svg = file_get_contents( dirname( __DIR__ ) . '/assets/askmypages-mark-mono.svg' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- local plugin file. return 'data:image/svg+xml;base64,' . base64_encode( (string) $svg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- data URI for the menu icon. } /** * Adds the AskMyPages menu, with a submenu entry per tab. */ public static function menu() { $hook = add_menu_page( 'AskMyPages', 'AskMyPages', 'manage_options', self::PAGE, array( __CLASS__, 'render' ), self::menu_icon(), 81 ); add_action( 'load-' . $hook, array( __CLASS__, 'handle_return' ) ); if ( ! Keys::is_connected() ) { return; } foreach ( self::tabs() as $tab => $label ) { add_submenu_page( self::PAGE, 'AskMyPages', $label, 'manage_options', 'overview' === $tab ? self::PAGE : self::PAGE . '&tab=' . $tab, '__return_null' ); } } /** * Highlights the submenu entry of the tab being viewed. * * @param string|null $submenu_file Current submenu file. * @param string $parent_file Parent menu. * @return string|null */ public static function current_submenu( $submenu_file, $parent_file ) { if ( self::PAGE !== $parent_file ) { return $submenu_file; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display only. $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'overview'; return array_key_exists( $tab, self::tabs() ) && 'overview' !== $tab ? self::PAGE . '&tab=' . $tab : self::PAGE; } /** * The page used to live under Settings; links and in-progress * connections that still use that address land on the new one. */ public static function redirect_old_url() { global $pagenow; // phpcs:disable WordPress.Security.NonceVerification.Recommended -- a redirect only; the target page does every check (state for connections, nonces for actions). if ( 'options-general.php' !== $pagenow || ! isset( $_GET['page'] ) || self::PAGE !== $_GET['page'] ) { return; } $query = array(); foreach ( array( 'tab', 'code', 'state', 'error', 'askmypages_notice' ) as $key ) { if ( isset( $_GET[ $key ] ) ) { $query[ $key ] = sanitize_text_field( wp_unslash( $_GET[ $key ] ) ); } } // phpcs:enable WordPress.Security.NonceVerification.Recommended wp_safe_redirect( add_query_arg( $query, Connect::return_url() ) ); exit; } /** * The portal sends the owner back here with ?code=&state= (or ?error=). * The state check is the CSRF protection for this request. */ public static function handle_return() { if ( ! current_user_can( 'manage_options' ) ) { return; } // phpcs:disable WordPress.Security.NonceVerification.Recommended -- verified by the one-time state instead of a nonce. if ( isset( $_GET['error'] ) ) { // Only a matching state cancels; anything else is ignored. $state = isset( $_GET['state'] ) ? sanitize_text_field( wp_unslash( $_GET['state'] ) ) : ''; if ( Connect::cancel( $state ) ) { self::back( 'cancelled' ); } return; } if ( ! isset( $_GET['code'], $_GET['state'] ) ) { return; } $code = sanitize_text_field( wp_unslash( $_GET['code'] ) ); $state = sanitize_text_field( wp_unslash( $_GET['state'] ) ); // phpcs:enable WordPress.Security.NonceVerification.Recommended $result = Connect::complete( $code, $state ); if ( is_wp_error( $result ) ) { set_transient( 'askmypages_notice_error', $result->get_error_message(), MINUTE_IN_SECONDS ); self::back( 'error' ); } self::back( 'connected' ); } /** * Starts connecting. */ public static function handle_connect() { self::guard( 'askmypages_connect' ); wp_redirect( Connect::start_url() ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- the portal is on another host by design. exit; } /** * Tests the connection with a signed request. */ public static function handle_test() { self::guard( 'askmypages_test' ); $result = Api::signed( 'GET', '/v1/plugin/site' ); if ( is_wp_error( $result ) ) { set_transient( 'askmypages_notice_error', $result->get_error_message(), MINUTE_IN_SECONDS ); self::back( 'error' ); } self::back( 'test_ok' ); } /** * Queues a full reconciliation now. */ public static function handle_sync() { self::guard( 'askmypages_sync' ); as_enqueue_async_action( Sync::HOOK_RECONCILE, array(), Sync::GROUP ); delete_transient( 'askmypages_status' ); self::back( 'sync_queued' ); } /** * Turns the search box upgrade on or off. */ public static function handle_search_toggle() { self::guard( 'askmypages_search_toggle' ); update_option( Search::OPTION_ENABLED, '1' === (string) get_option( Search::OPTION_ENABLED, '1' ) ? '0' : '1', false ); self::back( 'search_saved' ); } /** * Disconnects. */ public static function handle_disconnect() { self::guard( 'askmypages_disconnect' ); Connect::disconnect(); self::back( 'disconnected' ); } /** * Capability and nonce check for admin-post actions. * * @param string $action Nonce action. */ private static function guard( $action ) { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to do this.', 'askmypages' ), 403 ); } check_admin_referer( $action ); } /** * Redirects back to the settings page with a notice. * * @param string $notice Notice key. */ private static function back( $notice ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- checked in guard() before any redirect. $tab = isset( $_POST['tab'] ) ? sanitize_key( wp_unslash( $_POST['tab'] ) ) : 'overview'; $tab = array_key_exists( $tab, self::tabs() ) ? $tab : 'overview'; wp_safe_redirect( add_query_arg( 'askmypages_notice', $notice, self::tab_url( $tab ) ) ); exit; } /** * Renders a form button for an admin-post action. * * @param string $action Action name. * @param string $label Button label. * @param string $css Button class. * @param string $tab Tab to return to. * @param string $confirm Optional confirmation question. */ private static function button( $action, $label, $css = 'button', $tab = 'overview', $confirm = '' ) { ?>
>

' . esc_html__( 'Could not load counts from the service right now.', 'askmypages' ) . '

'; return; } $counts = isset( $status['counts'] ) && is_array( $status['counts'] ) ? $status['counts'] : array(); $labels = array( 'INDEXED' => __( 'Searchable', 'askmypages' ), 'PENDING' => __( 'Being prepared', 'askmypages' ), 'NO_TEXT' => __( 'No readable text', 'askmypages' ), 'FAILED' => __( 'Failed', 'askmypages' ), ); echo '
'; foreach ( $labels as $key => $label ) { if ( 'INDEXED' !== $key && empty( $counts[ $key ] ) ) { continue; } printf( '
%s%s
', esc_html( number_format_i18n( (int) ( $counts[ $key ] ?? 0 ) ) ), esc_html( $label ) ); } echo '
'; $last = (int) get_option( 'askmypages_last_reconcile' ); if ( $last ) { echo '

' . esc_html( sprintf( /* translators: %s: how long ago, e.g. "5 mins". */ __( 'Last full check: %s ago.', 'askmypages' ), human_time_diff( $last ) ) ) . '

'; } } /** * A usage meter. * * @param int $used Used. * @param int $limit Limit. * @param string $label What is counted. */ private static function meter( $used, $limit, $label ) { $ratio = $limit > 0 ? min( 1, $used / $limit ) : 0; $class = $ratio >= 1 ? ' is-full' : ( $ratio >= 0.8 ? ' is-warn' : '' ); printf( '

%s

', esc_attr( $class ), esc_attr( sprintf( '%s: %s / %s', $label, number_format_i18n( $used ), number_format_i18n( $limit ) ) ), esc_attr( (string) round( $ratio * 100 ) ), esc_html( sprintf( /* translators: 1: used, 2: limit, 3: what is counted, e.g. "items on your plan". */ __( '%1$s of %2$s %3$s', 'askmypages' ), number_format_i18n( $used ), number_format_i18n( $limit ), $label ) ) ); } /** * Tab names and labels. * * @return array */ private static function tabs() { return array( 'overview' => __( 'Overview', 'askmypages' ), 'content' => __( 'Content', 'askmypages' ), 'search' => __( 'Search', 'askmypages' ), 'chat' => __( 'Chat', 'askmypages' ), 'access' => __( 'Access', 'askmypages' ), 'connection' => __( 'Connection', 'askmypages' ), ); } /** * The settings page URL for a tab. * * @param string $tab Tab. * @return string */ public static function tab_url( $tab ) { return 'overview' === $tab ? Connect::return_url() : add_query_arg( 'tab', $tab, Connect::return_url() ); } /** * Loads the page's stylesheet. * * @param string $hook Admin page hook. */ public static function assets( $hook ) { if ( 'toplevel_page_' . self::PAGE !== $hook ) { return; } wp_enqueue_style( 'askmypages-admin', plugins_url( 'assets/admin.css', __DIR__ ), array(), ASKMYPAGES_VERSION ); // The Media Library picker for the assistant's picture (Chat tab). wp_enqueue_media(); wp_enqueue_script( 'askmypages-admin', plugins_url( 'assets/admin.js', __DIR__ ), array( 'media-editor' ), ASKMYPAGES_VERSION, array( 'in_footer' => true ) ); wp_localize_script( 'askmypages-admin', 'AskMyPagesAdmin', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'askmypages_try' ), 'i18n' => array( 'thinking' => __( 'Looking through your site…', 'askmypages' ), 'sources' => __( 'Sources', 'askmypages' ), 'failed' => __( 'Something went wrong. Please try again.', 'askmypages' ), /* translators: 1: test answers left, 2: test answers per month. */ 'left' => __( '%1$s of %2$s test answers left this month.', 'askmypages' ), 'errors' => array( 'quota_exceeded' => __( 'This month\'s test answers are used up. They come back next month.', 'askmypages' ), 'budget_exhausted' => __( 'AI answers are paused for this month.', 'askmypages' ), 'unavailable' => __( 'The answer service is busy. Please try again.', 'askmypages' ), ), ), ) ); } /** * One request for a WordPress.org review, on this plugin's own page only, * once the site's visitors have had 25 answers this month. Shown until * the owner clicks either button. * * @param int $answers AI answers used this month. */ private static function review_request( $answers ) { if ( $answers < 25 || get_option( 'askmypages_review' ) || ! current_user_can( 'manage_options' ) ) { return; } ?>

id, array( 'plugins', 'dashboard' ), true ) ) { return; } if ( ! get_option( 'askmypages_welcome' ) || Keys::is_connected() || ! current_user_can( 'manage_options' ) ) { return; } ?>

true, 'title' => __( 'Connect this site', 'askmypages' ), 'text' => __( 'Connected to your Hook & Plug account.', 'askmypages' ), 'link' => null, ), array( 'done' => $ready > 0 && 0 === $waiting, 'title' => __( 'Prepare your content', 'askmypages' ), 'text' => $waiting /* translators: 1: items ready, 2: items in total. */ ? sprintf( __( '%1$s of %2$s items ready. This runs in the background; you can carry on.', 'askmypages' ), number_format_i18n( $ready ), number_format_i18n( $ready + $waiting ) ) /* translators: %s: items ready. */ : sprintf( __( '%s items ready for search and answers.', 'askmypages' ), number_format_i18n( $ready ) ), 'link' => array( self::tab_url( 'content' ), __( 'Choose content', 'askmypages' ) ), ), array( 'done' => Search::enabled(), 'title' => __( 'Upgrade your search box', 'askmypages' ), 'text' => Search::enabled() ? __( 'Your search box now finds pages by meaning as well as exact words.', 'askmypages' ) : __( 'Turn on the search upgrade.', 'askmypages' ), 'link' => Search::enabled() ? array( home_url( '/?s=' ), __( 'Try it on your site', 'askmypages' ) ) : array( self::tab_url( 'search' ), __( 'Turn on', 'askmypages' ) ), ), array( 'done' => true, 'title' => __( 'Chat for visitors', 'askmypages' ), 'text' => ! empty( $chat['settings']['enabled'] ) ? __( 'On by default: a button on every page answers questions from your content, with links to the sources. Turn it off in Chat settings if you are not ready.', 'askmypages' ) : __( 'Off. Turn it on in Chat settings when you are ready.', 'askmypages' ), 'link' => array( self::tab_url( 'chat' ), __( 'Chat settings', 'askmypages' ) ), ), array( 'done' => ! empty( $usage['tryUsed'] ) || ! empty( $usage['answersUsed'] ), 'title' => __( 'Ask a test question', 'askmypages' ), 'text' => __( 'See an answer from your own content before visitors do.', 'askmypages' ), 'link' => array( self::tab_url( 'chat' ), __( 'Try it', 'askmypages' ) ), ), ); if ( ! in_array( false, wp_list_pluck( $steps, 'done' ), true ) ) { update_option( 'askmypages_setup_done', '1', false ); return; } ?>


  1. >
= $cap ) { $limit_notes[] = __( 'Your plan\'s item limit is reached, so new and changed content is not being added to search.', 'askmypages' ); } elseif ( $cap && $items >= 0.9 * $cap ) { $limit_notes[] = __( 'Your plan\'s item limit is almost reached. After that, new content is not added to search.', 'askmypages' ); } if ( $notes || $limit_notes ) { echo '
'; foreach ( $notes as $note ) { printf( '

%s

', esc_html( $note ) ); } foreach ( $limit_notes as $note ) { printf( '

%s %s

', esc_html( $note ), wp_kses_post( self::upgrade_link() ) ); } echo '
'; } self::render_skipped_pdfs(); self::render_setup( $status, $chat ); ?>

' . esc_html( sprintf( /* translators: %s: reason. */ __( 'In the last hour some searches used WordPress search instead: %s', 'askmypages' ), $fallback ) ) . '

'; } ?>

array( 'yes-alt', '#00a32a' ), 'recommended' => array( 'warning', '#dba617' ), 'critical' => array( 'dismiss', '#d63638' ), ); ?>

%s', esc_url( admin_url( 'admin.php?page=' . self::PAGE ) ), esc_html__( 'Settings', 'askmypages' ) ); array_unshift( $links, $settings ); if ( Keys::is_connected() && 'FREE' === ( Chat::data()['plan'] ?? '' ) ) { $links[] = sprintf( '%s', esc_url( self::upgrade_url() ), esc_html__( 'Upgrade to Starter', 'askmypages' ) ); } return $links; } /** * Where upgrades happen: the AskMyPages page of the Hook & Plug account, * with checkout and plan management. * * @return string */ public static function upgrade_url() { return ASKMYPAGES_APP_URL . '/askmypages?upgrade=1'; } /** * A link to the plans, opening in a new tab. Only used on AskMyPages's * own screens, next to the limit or feature it is about. * * @param string $text Link text; "See plans" when empty. * @param string $css Classes, e.g. "button button-primary" for a button. * @return string Safe HTML. */ public static function upgrade_link( $text = '', $css = '' ) { return sprintf( '%s %s', esc_url( self::upgrade_url() ), $css ? ' class="' . esc_attr( $css ) . '"' : '', esc_html( $text ? $text : __( 'See plans', 'askmypages' ) ), esc_html__( '(opens in a new tab)', 'askmypages' ) ); } /** * On/off status pill. * * @param bool $on On. */ private static function pill( $on ) { printf( '%s', $on ? 'is-ok' : 'is-off', esc_html( $on ? __( 'On', 'askmypages' ) : __( 'Off', 'askmypages' ) ) ); } /** * Renders the page. */ public static function render() { if ( ! current_user_can( 'manage_options' ) ) { return; } // phpcs:disable WordPress.Security.NonceVerification.Recommended -- display only. $notice = isset( $_GET['askmypages_notice'] ) ? sanitize_key( wp_unslash( $_GET['askmypages_notice'] ) ) : ''; $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'overview'; // phpcs:enable WordPress.Security.NonceVerification.Recommended $tab = array_key_exists( $tab, self::tabs() ) ? $tab : 'overview'; $messages = array( 'connected' => array( 'success', __( 'Connected. Your content is being prepared for search; this takes a few minutes.', 'askmypages' ) ), 'test_ok' => array( 'success', __( 'Connection works.', 'askmypages' ) ), 'disconnected' => array( 'success', __( 'Disconnected. The keys on this site were deleted.', 'askmypages' ) ), 'cancelled' => array( 'warning', __( 'Connecting was cancelled.', 'askmypages' ) ), 'search_saved' => array( 'success', __( 'Search setting saved.', 'askmypages' ) ), 'sync_queued' => array( 'success', __( 'Sync started. It runs in the background; counts update within a few minutes.', 'askmypages' ) ), 'reindex_queued' => array( 'success', __( 'Re-index started. It runs in the background; reload this page in a minute to see the new status.', 'askmypages' ) ), 'reindex_ineligible' => array( 'warning', __( 'That item is not in your content settings any more (or is no longer public), so it was not sent.', 'askmypages' ) ), 'chat_saved' => array( 'success', __( 'Chat settings saved.', 'askmypages' ) ), 'access_saved' => array( 'success', __( 'Access saved. Items are being checked again in the background.', 'askmypages' ) ), 'health_done' => array( 'success', __( 'Checks run again.', 'askmypages' ) ), 'content_saved' => array( 'success', __( 'Content settings saved. Search is being updated in the background; counts change within a few minutes.', 'askmypages' ) ), ); // The status call is signed: if the service says the key was revoked // elsewhere, the keys are dropped during it, so decide "connected" after. $status = Keys::is_connected() ? Sync::status() : null; $connected = Keys::is_connected(); $plan = $connected ? ( Chat::data()['plan'] ?? '' ) : ''; $revoked = ! $connected ? (int) get_option( Connect::OPT_REVOKED ) : 0; ?>

AskMyPages


%s

', esc_html( $error ? $error : __( 'Something went wrong.', 'askmypages' ) ) ); } elseif ( isset( $messages[ $notice ] ) ) { printf( '

%s

', esc_attr( $messages[ $notice ][0] ), esc_html( $messages[ $notice ][1] ) ); } ?>