'array',
'sanitize_callback' => array( 'Clvrly_Settings', 'sanitize' ),
'default' => Clvrly_Settings::defaults(),
)
);
}
/**
* Suggested text for the site's privacy policy (Settings → Privacy).
*/
public static function add_privacy_text() {
if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
return;
}
$content = '
' . __( 'This site uses Clvrly, an AI assistant provided by Clvrly (https://clvrly.com). When you use the assistant, the messages you type, the page you are on and basic technical information (such as your browser type) are sent to Clvrly so it can answer your questions. Clvrly may store a visitor identifier in your browser so conversations can continue between pages.', 'clvrly' ) . '
';
wp_add_privacy_policy_content( 'Clvrly AI Assistant', wp_kses_post( wpautop( $content, false ) ) );
}
/**
* "Settings" link on the Plugins screen.
*
* @param array $links Existing links.
* @return array
*/
public static function action_links( $links ) {
array_unshift(
$links,
sprintf( '%s', esc_url( self::settings_url() ), esc_html__( 'Settings', 'clvrly' ) )
);
return $links;
}
/**
* Portal and help links under the plugin description.
*
* @param array $links Existing links.
* @param string $file Plugin file.
* @return array
*/
public static function row_meta( $links, $file ) {
if ( plugin_basename( CLVRLY_FILE ) !== $file ) {
return $links;
}
$links[] = sprintf( '%s', esc_url( self::service_url( '/portal/' ) ), esc_html__( 'Clvrly portal', 'clvrly' ) );
$links[] = sprintf( '%s', esc_url( self::service_url( '/help/installation/wordpress.html' ) ), esc_html__( 'Help', 'clvrly' ) );
return $links;
}
/**
* Dashboard and Plugins screen notices: "add your token" and "needs attention".
*/
public static function notices() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$screen = get_current_screen();
if ( ! $screen || ! in_array( $screen->id, array( 'dashboard', 'plugins' ), true ) ) {
return;
}
if ( ! Clvrly_Settings::has_token() ) {
if ( get_user_meta( get_current_user_id(), self::DISMISS_META, true ) ) {
return;
}
printf(
'',
esc_html__( 'Clvrly is almost ready.', 'clvrly' ),
esc_html__( 'Add your token to show the AI assistant on your site. It takes about a minute.', 'clvrly' ),
esc_url( self::settings_url() ),
esc_html__( 'Finish setup', 'clvrly' )
);
return;
}
$status = Clvrly_Status::get();
if ( ! Clvrly_Settings::is_enabled() || ! $status || 'error' !== $status['state'] ) {
return;
}
$problem = '';
foreach ( $status['items'] as $item ) {
if ( 'error' === $item['status'] ) {
$problem = $item['label'];
break;
}
}
printf(
'',
esc_html__( 'Clvrly needs attention:', 'clvrly' ),
esc_html( $problem ),
esc_url( self::settings_url() ),
esc_html__( 'See how to fix it', 'clvrly' )
);
}
/**
* Load admin assets.
*
* @param string $hook Current admin page hook.
*/
public static function enqueue( $hook ) {
if ( in_array( $hook, array( 'index.php', 'plugins.php' ), true ) && ! Clvrly_Settings::has_token() ) {
// Remember when the setup notice is dismissed.
wp_register_script( 'clvrly-notice', false, array(), CLVRLY_VERSION, true );
wp_enqueue_script( 'clvrly-notice' );
wp_add_inline_script(
'clvrly-notice',
sprintf(
'document.addEventListener("click",function(e){if(e.target.closest(".clvrly-setup-notice .notice-dismiss")){var b=new URLSearchParams();b.append("action","clvrly_dismiss_notice");b.append("nonce",%s);fetch(%s,{method:"POST",credentials:"same-origin",body:b});}});',
wp_json_encode( wp_create_nonce( 'clvrly_dismiss_notice' ) ),
wp_json_encode( admin_url( 'admin-ajax.php' ) )
)
);
}
if ( 'settings_page_' . self::PAGE !== $hook ) {
return;
}
// Printed inline so a CDN can't serve a stale copy after an update. See clvrly_asset_contents().
wp_register_style( 'clvrly-admin', false, array(), CLVRLY_VERSION );
wp_enqueue_style( 'clvrly-admin' );
wp_add_inline_style( 'clvrly-admin', clvrly_asset_contents( 'assets/admin.css' ) );
wp_register_script( 'clvrly-admin', false, array(), CLVRLY_VERSION, true );
wp_enqueue_script( 'clvrly-admin' );
wp_add_inline_script( 'clvrly-admin', clvrly_asset_contents( 'assets/admin.js' ) );
wp_localize_script(
'clvrly-admin',
'clvrlyAdmin',
array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'clvrly_check' ),
'i18n' => array(
'checking' => __( 'Checking your installation…', 'clvrly' ),
'failed' => __( 'The check couldn\'t run. Reload the page and try again.', 'clvrly' ),
'tokenFound' => __( 'Token found in your snippet.', 'clvrly' ),
'tokenInvalid' => __( 'This doesn\'t look like a Clvrly token yet. It should be 32 or 64 letters and numbers.', 'clvrly' ),
),
)
);
}
/**
* Render Settings → Clvrly.
*/
public static function render_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$settings = Clvrly_Settings::get();
$name = CLVRLY_OPTION;
$constant = Clvrly_Settings::token_is_constant();
?>
'any',
'post_status' => array( 'publish', 'private', 'draft', 'future', 'pending' ),
'posts_per_page' => 50,
'fields' => 'ids',
'no_found_rows' => true,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Admin-only, small result set.
'meta_query' => array(
array(
'key' => Clvrly_Settings::HIDE_META,
'value' => '1',
'compare' => '=',
),
),
)
);
if ( ! $ids ) {
return;
}
echo '' . esc_html__( 'Hidden from the editor on:', 'clvrly' ) . '
';
foreach ( $ids as $id ) {
$title = get_the_title( $id );
$link = get_edit_post_link( $id );
printf(
'- %s
',
$link
? sprintf( '%s', esc_url( $link ), esc_html( $title ? $title : __( '(no title)', 'clvrly' ) ) )
: esc_html( $title )
);
}
echo '
';
}
/**
* Human-friendly "x minutes ago".
*
* @param int $timestamp Unix time.
* @return string
*/
private static function ago( $timestamp ) {
/* translators: %s: time difference, e.g. "5 mins" */
return sprintf( __( '%s ago', 'clvrly' ), human_time_diff( $timestamp, time() ) );
}
/**
* The status card at the top of the settings screen. Returns escaped HTML.
*
* @return string
*/
public static function status_card() {
$state = Clvrly_Status::state();
$status = Clvrly_Status::get();
$headlines = array(
'setup' => array( __( 'Connect your Clvrly account', 'clvrly' ), __( 'Three quick steps and the assistant goes live.', 'clvrly' ) ),
'paused' => array( __( 'Paused', 'clvrly' ), __( 'The assistant is switched off, so visitors don\'t see it. Switch on "Show assistant" below to bring it back.', 'clvrly' ) ),
'checking' => array( __( 'Checking your installation…', 'clvrly' ), __( 'This takes a few seconds.', 'clvrly' ) ),
'ok' => array( __( 'Live on your site', 'clvrly' ), __( 'Everything is set up. Visitors can ask your assistant questions now.', 'clvrly' ) ),
'warning' => array( __( 'Almost there', 'clvrly' ), __( 'The assistant is connected, but something needs a quick look.', 'clvrly' ) ),
'error' => array( __( 'Needs attention', 'clvrly' ), __( 'The assistant can\'t run until this is fixed.', 'clvrly' ) ),
);
// Re-check automatically when there's no result yet or the last one is over 12 hours old.
$autocheck = 'checking' === $state || ( $status && in_array( $state, array( 'ok', 'warning', 'error' ), true ) && $status['checked_at'] < time() - 12 * HOUR_IN_SECONDS );
ob_start();
?>
__( 'You do not have permission to do this.', 'clvrly' ) ), 403 );
}
Clvrly_Status::run();
wp_send_json_success( array( 'html' => self::status_card() ) );
}
/**
* AJAX: remember that this user dismissed the setup notice.
*/
public static function ajax_dismiss_notice() {
check_ajax_referer( 'clvrly_dismiss_notice', 'nonce' );
if ( current_user_can( 'manage_options' ) ) {
update_user_meta( get_current_user_id(), self::DISMISS_META, 1 );
}
wp_send_json_success();
}
}