connection->is_connected() ) { $this->render_first_run(); return; } $sync = new Sync( $this->connection ); // Counted once and passed down: two cards read the same figures, and a // card that disagreed with the one beside it would be worse than either. $stats = $sync->stats(); echo '
'; $this->render_workspace_card( $stats ); $this->render_entries_card( $stats ); $this->render_platform_card(); $this->render_access_card(); echo '
'; // Between the cards and the panels, which is where the Drupal module // puts them (StatusController::page() builds the cards, then #actions, // then the activity and index panels). They are the same three buttons // in the same order, so they should be in the same place. $this->render_actions( $sync ); $this->render_sync_card( $sync ); $this->render_searches_card(); } /** * The invitation, when there is nothing to report yet. * * A port of the Drupal module's first-run page: what this does, in two * features, then the three steps of connecting, then one button. The button * is a form because starting the flow is a POST behind a nonce. */ private function render_first_run(): void { ?>

render_locked_notice(); ?> render_service_notice(); ?>

' . esc_html( wp_parse_url( $this->connection->api_base(), PHP_URL_HOST ) ?? 'api.sharely.ai' ) . '', '' . esc_html__( 'Terms of Service', 'sharelyai' ) . '', '' . esc_html__( 'Privacy Policy', 'sharelyai' ) . '' ); ?>

connection->is_locked( 'workspace_id' ) && ! $this->connection->is_locked( 'api_key' ) ) { return; } ?>

connection->get( 'workspace_name' ); $id = $this->connection->workspace_id(); $last4 = (string) $this->connection->get( 'key_last4' ); $since = $this->connection->connected_at(); $app = $this->connection->app_base(); $rbac = (bool) $this->connection->get( 'rbac_enabled' ); $locked = $this->connection->is_locked( 'api_key' ) || $this->connection->is_locked( 'workspace_id' ); ?>

···· —
0 ) : ?>
0 ) { return sprintf( '%s', esc_html( sprintf( /* translators: %s: number of entries. */ _n( '%s failed', '%s failed', $stats['failed'], 'sharelyai' ), number_format_i18n( $stats['failed'] ) ) ) ); } if ( $stats['queued'] > 0 ) { return '' . esc_html__( 'syncing', 'sharelyai' ) . ''; } if ( $stats['in_scope'] > 0 && $stats['synced'] >= $stats['in_scope'] ) { return '' . esc_html__( 'up to date', 'sharelyai' ) . ''; } return ''; } /** * How much of what this site would send has been sent. * * @param array{in_scope:int, synced:int, queued:int, failed:int} $stats Sync counters. */ private function render_entries_card( array $stats ): void { $inventory = new Inventory( $this->connection ); $types = $inventory->by_post_type(); $percent = $stats['in_scope'] > 0 ? min( 100, (int) round( ( $stats['synced'] / $stats['in_scope'] ) * 100 ) ) : 0; ?>

/

connection ) )->stats(); if ( ! $stats['ok'] || ! is_array( $stats['data'] ) ) { // Deliberately quiet: a reachability problem belongs to whatever the // administrator was actually trying to do, not to a status card. return; } $data = $stats['data']; $by_status = is_array( $data['byStatus'] ?? null ) ? $data['byStatus'] : array(); $total = (int) ( $data['total'] ?? 0 ); $done = (int) ( $by_status['COMPLETED'] ?? 0 ); $working = (int) ( $by_status['BACKGROUND_START'] ?? 0 ); $failed = (int) ( $by_status['BACKGROUND_ERROR'] ?? 0 ); $untagged = (int) ( $data['withoutRoles'] ?? 0 ); ?>

0 ) : ?>
0 ) : ?>
get_names() ) + 1; ?>

/
connection ) )->private_included() ? __( 'Published entries are tagged for anonymous visitors; private ones for the roles that may read them. A visitor’s search runs as the roles they hold.', 'sharelyai' ) : __( 'Published entries are tagged for anonymous visitors. Private entries are not sent — turn that on under Settings if members-only content should be searchable.', 'sharelyai' ) ); ?>
0 ) : ?>

run(); $running = $sync->is_running(); $total = (int) ( $run['total'] ?? 0 ); $done = (int) ( $run['done'] ?? 0 ); $percent = $total > 0 ? min( 100, (int) round( ( $done / $total ) * 100 ) ) : 0; ?>

0 && ! empty( $run['finished'] ) ) : ?>

render_failures( $sync ); ?> render_log( $sync ); ?>
connection->is_locked( 'api_key' ) || $this->connection->is_locked( 'workspace_id' ); ?>
is_running() ) : ?>
render_locked_notice(); ?>

failures(); if ( array() === $failures ) { return; } ?>

log(); if ( array() === $log ) { return; } ?>
—
__( 'Sent', 'sharelyai' ), 'updated' => __( 'Updated', 'sharelyai' ), 'unchanged' => __( 'No change', 'sharelyai' ), 'removed' => __( 'Removed', 'sharelyai' ), 'skipped' => __( 'Not in scope', 'sharelyai' ), 'failed' => __( 'Failed', 'sharelyai' ), ); return $labels[ $outcome ] ?? $outcome; } /** * What visitors searched for. */ private function render_searches_card(): void { $stats = new Stats( $this->connection ); if ( ! $stats->enabled() ) { return; } $days = max( 1, (int) $this->connection->get( 'stats_retention_days', 30 ) ); $summary = $stats->summary( $days ); ?>

' . esc_html( number_format_i18n( $summary['searches'] ) ) . '', '' . esc_html( number_format_i18n( $summary['terms'] ) ) . '', '' . esc_html( number_format_i18n( $summary['empty'] ) ) . '', esc_html( number_format_i18n( $percent ) ) ); ?>

render_query_table( __( 'Most searched', 'sharelyai' ), $stats->top( $days, 10 ), true ); ?> render_query_table( __( 'Found nothing', 'sharelyai' ), $stats->top( $days, 10, true ), false ); ?>

$rows Rows. * @param bool $average Show the average result count. */ private function render_query_table( string $caption, array $rows, bool $average ): void { if ( array() === $rows ) { return; } ?>