ready()) { return; } wp_add_inline_style('common', self::asset('css/assistant.css')); wp_register_script(self::SCRIPT, false, [], SARCIO_WP_VERSION, true); wp_enqueue_script(self::SCRIPT); wp_add_inline_script(self::SCRIPT, self::asset('js/assistant.js')); $user = wp_get_current_user(); wp_add_inline_script(self::SCRIPT, 'var sarcioAssistant=' . InlineJson::encode([ 'ask' => isset($_GET['ask']) && is_string($_GET['ask']) ? mb_substr(sanitize_text_field(wp_unslash($_GET['ask'])), 0, 500) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- a suggested first message, only prefilled in the box. 'adminUrl' => esc_url_raw(admin_url()), 'brandColor' => Brand::color(), 'frameUrl' => esc_url_raw(home_url('/')), 'homeUrl' => esc_url_raw(home_url('/')), 'loginUrl' => esc_url_raw(wp_login_url()), 'previewTitle' => Brand::screen(__('preview', 'sarcio')), 'timezone' => wp_timezone_string(), 'canApply' => Requests::canApply() ? '1' : '', 'requestsUrl' => RequestsPage::url(), 'now' => wp_date('Y-m-d\TH:i'), 'consents' => Catalog::consents(), 'kinds' => Catalog::kinds(), 'labels' => Catalog::labels(), 'nonce' => wp_create_nonce('wp_rest'), 'restUrl' => esc_url_raw(rest_url(Routes::NAMESPACE . '/assistant/')), 'stageables' => Catalog::stageables(), 'siteKey' => (string) Options::get('site_key'), 'siteName' => Connect::siteName(), 'strings' => self::strings(), 'suggestions' => self::suggestions(), 'userName' => (string) ($user->display_name ?? ''), ]) . ';', 'before'); } /** The plugin's own bundled asset, printed inline so it works wherever the plugin is installed. */ private static function asset(string $file): string { $path = dirname(__DIR__, 2) . '/assets/' . $file; if (!is_readable($path)) { return ''; } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- the plugin's own bundled file. $source = file_get_contents($path); return is_string($source) ? $source : ''; } public function render(): void { if (!current_user_can(ReviewPage::CAPABILITY)) { return; } if ((string) Options::get('site_key') === '') { Cards::welcome(); return; } $info = Embed::info(); $newTab = Embed::workspaceUrl() ?? 'https://www.sarcio.io/app/'; if (!Account::has(get_current_user_id())) { Cards::account(Brand::screen(__('Assistant', 'sarcio')), $info['workspaceName'] ?? '', $newTab, false); return; } $token = Account::accessToken(get_current_user_id()); if (isset($token['reconnect'])) { Cards::account(Brand::screen(__('Assistant', 'sarcio')), $info['workspaceName'] ?? '', $newTab, true); return; } echo '

' . wp_kses(Brand::logoTag(), Brand::ALLOWED_HTML) . esc_html(Brand::screen(__('Assistant', 'sarcio'))) . '

'; echo '

' . esc_html__('Ask for a change to your site in plain words. The assistant looks things up and lays each change over a preview of your site that only you can see. Apply when it looks right; every applied change can be undone from the list on the right.', 'sarcio') . '

'; echo '
'; echo ''; echo '
'; } private function ready(): bool { return (string) Options::get('site_key') !== '' && Account::has(get_current_user_id()); } /** @return array */ private static function suggestions(): array { $suggestions = [ __('Change the phone number in the footer', 'sarcio'), __('Make the Contact page say we are closed on Mondays', 'sarcio'), __('Add an About link to the main menu', 'sarcio'), __('Make all the headings dark green', 'sarcio'), ]; if (SiteAbilities::woocommerceActive()) { $suggestions[] = __('Add a 10% coupon for new customers', 'sarcio'); $suggestions[] = __('Put the best-selling product on sale for a week', 'sarcio'); } return $suggestions; } /** @return array */ private static function strings(): array { return [ 'apply' => __('Apply', 'sarcio'), 'applyAll' => __('Apply changes', 'sarcio'), 'applyNote' => __('Apply makes every previewed change on the live site, in order. Discard forgets them all.', 'sarcio'), 'applied' => __('Applied', 'sarcio'), 'schedule' => __('Schedule…', 'sarcio'), 'sendRequest' => __('Send to my agency', 'sarcio'), 'share' => __('Share for review', 'sarcio'), 'shareNote' => __('Anyone with this link sees the preview as it is now, for a week, and can pin notes on any page. Ask the assistant what they said.', 'sarcio'), /* translators: %s: how many notes. */ 'shareNotes' => __('%s notes from reviewers so far', 'sarcio'), 'copy' => __('Copy link', 'sarcio'), 'someone' => __('Someone', 'sarcio'), 'copied' => __('Copied', 'sarcio'), 'requestTitle' => __('What is this change for?', 'sarcio'), 'requestTitlePlaceholder' => __('For example: new opening hours for the holidays', 'sarcio'), 'requestConfirm' => __('Send', 'sarcio'), 'requestNote' => __('Your agency gets the preview exactly as you see it, applies it as it is or declines it, and you are emailed either way.', 'sarcio'), 'requestSent' => __('Sent to your agency', 'sarcio'), 'requested' => __('Requested', 'sarcio'), 'requestsList' => __('Your requests', 'sarcio'), 'noRequests' => __('Nothing has been sent yet.', 'sarcio'), 'withdraw' => __('Withdraw', 'sarcio'), 'openRequests' => __('Open requests', 'sarcio'), 'requestStatus' => [ 'applied' => __('Applied', 'sarcio'), 'applying' => __('Being applied', 'sarcio'), 'declined' => __('Declined', 'sarcio'), 'failed' => __('Could not be applied', 'sarcio'), 'partial' => __('Partly applied', 'sarcio'), 'pending' => __('Waiting for your agency', 'sarcio'), 'withdrawn' => __('Withdrawn', 'sarcio'), ], 'applyNoteRequest' => __('Your agency applies changes on this site. Send the preview and they will look at it.', 'sarcio'), 'scheduleApplyAt' => __('Make the change on', 'sarcio'), 'scheduleRepeat' => __('Repeat', 'sarcio'), 'repeatOptions' => ['none' => __('Just once', 'sarcio'), 'daily' => __('Every day', 'sarcio'), 'weekly' => __('Every week', 'sarcio'), 'monthly' => __('Every month', 'sarcio')], /* translators: %s: every day, week or month. */ 'scheduledRepeat' => __('repeats %s', 'sarcio'), 'scheduleRevertAt' => __('Change it back on (optional)', 'sarcio'), 'scheduleConfirm' => __('Schedule', 'sarcio'), 'scheduleCancel' => __('Cancel', 'sarcio'), /* translators: %s: the site's time zone. */ 'scheduleNote' => __('Times are in the site’s time zone (%s). The change is made by WordPress’s scheduler, which runs when the site gets a visit.', 'sarcio'), 'scheduled' => __('Scheduled', 'sarcio'), /* translators: %s: the date and time. */ 'scheduledFor' => __('Scheduled for %s', 'sarcio'), /* translators: %s: the date and time. */ 'scheduledBack' => __('back on %s', 'sarcio'), 'scheduledList' => __('Scheduled changes', 'sarcio'), 'noScheduled' => __('Nothing is scheduled.', 'sarcio'), 'scheduledStatus' => [ 'applied' => __('Applied', 'sarcio'), 'cancelled' => __('Cancelled', 'sarcio'), 'failed' => __('Did not work', 'sarcio'), 'partial' => __('Partly applied', 'sarcio'), 'pending' => __('Waiting', 'sarcio'), 'revert_failed' => __('Could not change back', 'sarcio'), 'reverted' => __('Changed back', 'sarcio'), ], 'cancelSchedule' => __('Cancel', 'sarcio'), 'keepApplied' => __('Keep it', 'sarcio'), 'applying' => __('Applying…', 'sarcio'), 'conversations' => __('Conversations', 'sarcio'), 'delete' => __('Delete', 'sarcio'), 'discard' => __('Discard', 'sarcio'), 'discarded' => __('Preview discarded', 'sarcio'), 'earlier' => __('Earlier in this conversation', 'sarcio'), 'inPreview' => __('In your preview', 'sarcio'), 'noConversations' => __('Your past conversations will be listed here.', 'sarcio'), 'notPreviewable' => __('This one cannot be shown in the preview: it happens when you press Apply.', 'sarcio'), 'openPreview' => __('Look at the site', 'sarcio'), 'panelOpen' => __('Show beside the chat', 'sarcio'), 'panelClose' => __('Close the preview panel', 'sarcio'), 'panelHide' => __('Hide the panel', 'sarcio'), 'panelFrame' => __('Your site, as your preview shows it', 'sarcio'), 'panelNewTab' => __('Open in a new tab', 'sarcio'), 'panelLoading' => __('Loading your site…', 'sarcio'), 'panelFailed' => __('Your site cannot be shown here: it does not allow itself to be shown inside another page, or it took too long to load. Look at it in a new tab instead.', 'sarcio'), 'panelRetry' => __('Try again', 'sarcio'), 'showLive' => __('Show live', 'sarcio'), 'showLiveLabel' => __('Show the live site, without my changes, in the preview', 'sarcio'), 'showChanges' => __('Show my changes', 'sarcio'), 'showChangesLabel' => __('Show my changes again in the preview', 'sarcio'), 'showingChanges' => __('Showing your changes', 'sarcio'), 'showingLive' => __('Showing the live site', 'sarcio'), 'liveSite' => __('Your live site', 'sarcio'), /* translators: %s: how many changes. */ 'previewMany' => __('%s changes in your preview of the site', 'sarcio'), 'previewOne' => __('1 change in your preview of the site', 'sarcio'), 'previewDropped' => __('Some previewed changes no longer fit the site and were left out.', 'sarcio'), 'previewEnded' => __('That preview had ended, so it was rebuilt from this conversation.', 'sarcio'), 'summarised' => __('Earlier messages were summarised to keep the conversation going.', 'sarcio'), 'before' => __('Before', 'sarcio'), 'after' => __('After', 'sarcio'), 'checking' => __('Looking…', 'sarcio'), // translators: 1: plugin name, 2: plugin author. 'consentInstall' => __('Install %1$s by %2$s from WordPress.org', 'sarcio'), // translators: %s: plugin name. 'consentActivate' => __('Turn on %s', 'sarcio'), 'consentNote' => __('Only plugins from the WordPress.org directory. Nothing is installed until you tick this box and press Apply.', 'sarcio'), 'consentRun' => __('Yes, make this change for real', 'sarcio'), 'consentRunNote' => __('This one is made by another plugin and is not undone from here. Nothing happens until you tick this box and press Apply.', 'sarcio'), 'done' => __('Done', 'sarcio'), 'empty' => __('What would you like to change?', 'sarcio'), 'failed' => __('Did not work', 'sarcio'), // translators: %s: number of active installs. 'installs' => __('%s active installs', 'sarcio'), 'newConversation' => __('New conversation', 'sarcio'), 'noChanges' => __('No changes yet. Changes you make here will be listed so you can undo them.', 'sarcio'), 'placeholder' => __('Describe the change you want…', 'sarcio'), // translators: %s: average rating. 'rating' => __('rated %s of 5', 'sarcio'), 'recentChanges' => __('Recent changes', 'sarcio'), 'removeFromPreview' => __('Leave this one out', 'sarcio'), 'reconnect' => __('Your Sarcio sign-in here has ended. Reload the page to connect again.', 'sarcio'), 'send' => __('Send', 'sarcio'), 'skip' => __('Skip', 'sarcio'), 'skipped' => __('Skipped', 'sarcio'), 'stop' => __('Stop', 'sarcio'), 'tryAgain' => __('Try again', 'sarcio'), /* translators: %s: how many lines. */ 'unchangedLines' => __('… %s unchanged lines', 'sarcio'), 'whatChanged' => __('What changed', 'sarcio'), 'stopped' => __('Stopped. Say what to do next.', 'sarcio'), 'thinking' => __('Thinking…', 'sarcio'), 'tooManySteps' => __('That took a lot of steps. Check the result and say what to do next.', 'sarcio'), 'undo' => __('Undo', 'sarcio'), 'undone' => __('Undone', 'sarcio'), 'unreachable' => __('Could not reach your site. Check your connection and try again.', 'sarcio'), 'waiting' => __('Waiting for you', 'sarcio'), 'you' => __('You', 'sarcio'), ]; } }