post_type ) { return; } echo '

' . esc_html__( 'Name the agent, choose a model, then copy the shortcode from the sidebar to put the chat on a page.', 'arwp-agents' ) . '

'; } /** * Prompt setup when the API key is missing. */ public function maybe_setup_notice() { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || 'edit-arwp_agent' !== $screen->id ) { return; } if ( ! current_user_can( 'manage_options' ) ) { return; } if ( class_exists( 'ARWP_Settings' ) && ARWP_Settings::get_api_key() ) { return; } echo '

'; printf( /* translators: %s: settings URL */ esc_html__( 'Connect your OpenRouter API key before chatting. %s', 'arwp-agents' ), '' . esc_html__( 'Open Settings', 'arwp-agents' ) . '' ); echo '

'; } /** * Warn once when blocked patterns were dropped on save. */ public function maybe_pattern_notice() { $user_id = get_current_user_id(); if ( ! $user_id ) { return; } $key = 'arwp_admin_notice_' . $user_id; $text = get_transient( $key ); if ( ! is_string( $text ) || '' === $text ) { return; } delete_transient( $key ); echo '

' . esc_html( $text ) . '

'; } /** * Set default title for new agents. * * @param string $title Default title. * @param WP_Post $post Post being created. * @return string */ public function set_default_agent_title( $title, $post ) { if ( 'arwp_agent' === $post->post_type ) { return __( 'New AI Agent', 'arwp-agents' ); } return $title; } /** * Define custom columns for the arwp_agent post type list table. * * @param array $columns Existing columns. * @return array */ public function set_custom_agent_columns( $columns ) { $new_columns = array(); foreach ( $columns as $key => $title ) { if ( 'date' === $key ) { $new_columns['arwp_model'] = __( 'Model', 'arwp-agents' ); $new_columns['arwp_shortcode'] = __( 'Shortcode', 'arwp-agents' ); } $new_columns[ $key ] = $title; } return $new_columns; } /** * Render content for custom columns in the arwp_agent list table. * * @param string $column Column key. * @param int $post_id Post ID. */ public function custom_agent_column_content( $column, $post_id ) { if ( 'arwp_shortcode' === $column ) { $shortcode = '[arwp id="' . intval( $post_id ) . '"]'; ?> ' . esc_html__( 'Global Default', 'arwp-agents' ) . ''; } else { $fetched_models = class_exists( 'ARWP_Settings' ) ? ARWP_Settings::get_models() : array(); $label = isset( $fetched_models[ $model ] ) ? $fetched_models[ $model ] : $model; echo esc_html( $label ); } } } /** * Add Model filter dropdown to All Agents screen. * * @param string $post_type Current post type. */ public function add_agent_model_filter( $post_type ) { if ( 'arwp_agent' !== $post_type ) { return; } $fetched_models = class_exists( 'ARWP_Settings' ) ? ARWP_Settings::get_models() : array(); $models = array( 'default' => __( 'Global Default Model', 'arwp-agents' ), ) + $fetched_models; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only admin list filter, mirrors core's own GET-based list table filters. $selected = isset( $_GET['arwp_model_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['arwp_model_filter'] ) ) : ''; echo ''; } /** * Filter agents by selected model. * * @param WP_Query $query Main query. */ public function filter_agents_by_model( $query ) { global $pagenow; // Read-only admin list filter, mirrors core's own GET-based list table filters (e.g. ?post_status=), so no nonce is required. if ( is_admin() && 'edit.php' === $pagenow && isset( $_GET['post_type'] ) && 'arwp_agent' === $_GET['post_type'] && $query->is_main_query() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $filter_val = isset( $_GET['arwp_model_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['arwp_model_filter'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( '' !== $filter_val ) { $meta_query = $query->get( 'meta_query' ); if ( ! is_array( $meta_query ) ) { $meta_query = array(); } if ( 'default' === $filter_val ) { $meta_query[] = array( 'relation' => 'OR', array( 'key' => '_arwp_model', 'value' => 'default', 'compare' => '=', ), array( 'key' => '_arwp_model', 'compare' => 'NOT EXISTS', ), ); } else { $meta_query[] = array( 'key' => '_arwp_model', 'value' => $filter_val, 'compare' => '=', ); } $query->set( 'meta_query', $meta_query ); } } } /** * Add 'Clone' link to post row actions. * * @param array $actions Row actions. * @param WP_Post $post Current post. * @return array */ public function add_clone_agent_action( $actions, $post ) { if ( 'arwp_agent' === $post->post_type ) { $url = wp_nonce_url( admin_url( 'admin.php?action=arwp_clone_agent&post=' . $post->ID ), 'arwp_clone_agent_nonce', 'nonce' ); $actions['clone'] = '' . esc_html__( 'Clone', 'arwp-agents' ) . ''; } return $actions; } /** * Handle the clone agent action. */ public function handle_clone_agent() { if ( ! isset( $_GET['action'] ) || 'arwp_clone_agent' !== $_GET['action'] ) { return; } if ( ! isset( $_GET['post'] ) || ! isset( $_GET['nonce'] ) ) { wp_die( esc_html__( 'Missing required parameters.', 'arwp-agents' ) ); } $post_id = intval( $_GET['post'] ); if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['nonce'] ) ), 'arwp_clone_agent_nonce' ) ) { wp_die( esc_html__( 'Security check failed.', 'arwp-agents' ) ); } if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_die( esc_html__( 'You do not have permission to clone agents.', 'arwp-agents' ) ); } $post = get_post( $post_id ); if ( ! $post || 'arwp_agent' !== $post->post_type ) { wp_die( esc_html__( 'Invalid agent.', 'arwp-agents' ) ); } // Create a copy of the post. $new_post_args = array( 'post_title' => $post->post_title . ' ' . __( '(Copy)', 'arwp-agents' ), 'post_content' => $post->post_content, 'post_status' => 'draft', // Draft is safer so they don't get confused about which is which before publishing. 'post_type' => $post->post_type, 'post_author' => get_current_user_id(), ); $new_post_id = wp_insert_post( $new_post_args ); if ( ! is_wp_error( $new_post_id ) ) { $meta_data = get_post_custom( $post_id ); $skip_meta = array( '_edit_lock', '_edit_last', ); foreach ( $meta_data as $key => $values ) { if ( in_array( $key, $skip_meta, true ) ) { continue; } foreach ( $values as $value ) { $unserialized = maybe_unserialize( $value ); // add_post_meta() removes slashes. Put them back so \d in a pattern survives. add_post_meta( $new_post_id, $key, wp_slash( $unserialized ) ); } } // Redirect back to the agent list. wp_safe_redirect( admin_url( 'edit.php?post_type=arwp_agent' ) ); exit; } else { wp_die( esc_html__( 'Failed to clone the agent.', 'arwp-agents' ) ); } } /** * Admin CSS and editor/list scripts for ARWP Agents screens. * * @param string $hook Current admin page hook. */ public function enqueue_admin_scripts( $hook ) { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; $is_ours = ( false !== strpos( $hook, 'arwp-settings' ) || false !== strpos( $hook, 'arwp-conversations' ) ); if ( $screen && isset( $screen->post_type ) && 'arwp_agent' === $screen->post_type ) { $is_ours = true; } if ( ! $is_ours ) { return; } wp_register_style( 'arwp-admin', false, array(), ARWP_VERSION ); wp_enqueue_style( 'arwp-admin' ); wp_add_inline_style( 'arwp-admin', ' .arwp-admin-help { margin: 8px 0 16px; color: #646970; font-size: 14px; } .arwp-meta-table { width: 100%; border-spacing: 0 12px; } .arwp-meta-table th { text-align: left; vertical-align: top; width: 200px; font-weight: 600; } .arwp-meta-table td input[type="number"], .arwp-meta-table td select, .arwp-meta-table td textarea { width: 100%; max-width: 600px; box-sizing: border-box; } .arwp-meta-table td textarea { min-height: 120px; } .arwp-meta-table td p.description { margin-top: 4px; color: #666; font-size: 12px; } .arwp-role-list label { display: block; margin: 4px 0; } #arwp_access_roles_wrap { margin-top: 8px; } .arwp-role-limits p { margin: 6px 0; } .arwp-role-limits label { display: inline-block; min-width: 140px; } .post-type-arwp_agent #misc-publishing-actions, .post-type-arwp_agent #preview-action, .post-type-arwp_agent #delete-action { display: none !important; } .post-type-arwp_agent #submitpost { display: flex; justify-content: space-between; align-items: center; padding: 15px 10px; } .post-type-arwp_agent #minor-publishing, .post-type-arwp_agent #minor-publishing-actions, .post-type-arwp_agent #major-publishing-actions, .post-type-arwp_agent #publishing-action, .post-type-arwp_agent #save-action { display: contents !important; } ' ); $is_editor = ( 'post.php' === $hook || 'post-new.php' === $hook ) && $screen && 'arwp_agent' === $screen->post_type; $is_list = ( 'edit.php' === $hook && $screen && 'edit-arwp_agent' === $screen->id ); $admin_deps = array( 'jquery' ); if ( $is_editor ) { wp_enqueue_media(); $admin_deps[] = 'media-editor'; } wp_register_script( 'arwp-admin', false, $admin_deps, ARWP_VERSION, true ); if ( $is_editor ) { wp_enqueue_style( 'arwp-select2-css', ARWP_URL . 'assets/vendor/select2/select2.min.css', array(), '4.1.0' ); wp_enqueue_script( 'arwp-select2-js', ARWP_URL . 'assets/vendor/select2/select2.min.js', array( 'jquery' ), '4.1.0', true ); wp_enqueue_script( 'arwp-admin' ); wp_localize_script( 'arwp-admin', 'arwp_agent_editor', array( 'select_logo' => __( 'Select header logo', 'arwp-agents' ), 'use_logo' => __( 'Use this logo', 'arwp-agents' ), ) ); wp_add_inline_script( 'arwp-admin', $this->editor_script() ); } if ( $is_list ) { wp_enqueue_script( 'arwp-admin' ); wp_add_inline_script( 'arwp-admin', "jQuery(function($){ $('.arwp-list-shortcode-input').on('click', function() { $(this).select(); document.execCommand('copy'); $(this).next('.arwp-list-copied-msg').stop().fadeIn('fast').delay(1500).fadeOut('fast'); }); });" ); } } /** * Agent editor behavior: model picker, access roles, and header logo. * * @return string */ private function editor_script() { return <<<'JS' jQuery(function($){ $('#arwp_model').select2({ width: '100%', maxWidth: '600px' }); $('#arwp_shortcode_input').on('click', function() { this.select(); document.execCommand('copy'); $('#arwp_shortcode_msg').stop().fadeIn().delay(2000).fadeOut(); }); var accessSelect = $('#arwp_access'); var rolesWrap = $('#arwp_access_roles_wrap'); var syncAccess = function() { if (accessSelect.val() === 'roles') { rolesWrap.show(); } else { rolesWrap.hide(); } }; accessSelect.on('change', syncAccess); syncAccess(); var editor = window.arwp_agent_editor || {}; var logoFrame; $('#arwp_ui_logo_select').on('click', function(e) { e.preventDefault(); if (typeof wp === 'undefined' || !wp.media) { return; } if (logoFrame) { logoFrame.open(); return; } logoFrame = wp.media({ title: editor.select_logo || 'Select header logo', button: { text: editor.use_logo || 'Use this logo' }, library: { type: 'image' }, multiple: false }); logoFrame.on('select', function() { var attachment = logoFrame.state().get('selection').first().toJSON(); var url = attachment.url; if (attachment.sizes && attachment.sizes.medium && attachment.sizes.medium.url) { url = attachment.sizes.medium.url; } $('#arwp_ui_logo_id').val(attachment.id); $('#arwp_ui_logo_preview').empty().append($('', { src: url, alt: '' }).css({ maxHeight: '48px', width: 'auto' })); $('#arwp_ui_logo_remove').show(); }); logoFrame.open(); }); $('#arwp_ui_logo_remove').on('click', function(e) { e.preventDefault(); $('#arwp_ui_logo_id').val('0'); $('#arwp_ui_logo_preview').empty(); $(this).hide(); }); }); JS; } /** * Register arwp_agent Custom Post Type. */ public function register_arwp_agent_cpt() { $labels = array( 'name' => _x( 'Agents', 'Post Type General Name', 'arwp-agents' ), 'singular_name' => _x( 'Agent', 'Post Type Singular Name', 'arwp-agents' ), 'menu_name' => __( 'ARWP Agents', 'arwp-agents' ), 'name_admin_bar' => __( 'Agent', 'arwp-agents' ), 'archives' => __( 'Agent Archives', 'arwp-agents' ), 'attributes' => __( 'Agent Attributes', 'arwp-agents' ), 'parent_item_colon' => __( 'Parent Agent:', 'arwp-agents' ), 'all_items' => __( 'Agents', 'arwp-agents' ), 'add_new_item' => __( 'Add New Agent', 'arwp-agents' ), 'add_new' => __( 'Add Agent', 'arwp-agents' ), 'new_item' => __( 'New Agent', 'arwp-agents' ), 'edit_item' => __( 'Edit Agent', 'arwp-agents' ), 'update_item' => __( 'Update Agent', 'arwp-agents' ), 'view_item' => __( 'View Agent', 'arwp-agents' ), 'view_items' => __( 'View Agents', 'arwp-agents' ), 'search_items' => __( 'Search Agent', 'arwp-agents' ), 'not_found' => __( 'Not found', 'arwp-agents' ), 'not_found_in_trash' => __( 'Not found in Trash', 'arwp-agents' ), 'featured_image' => __( 'Chat Avatar', 'arwp-agents' ), 'set_featured_image' => __( 'Set chat avatar', 'arwp-agents' ), 'remove_featured_image' => __( 'Remove chat avatar', 'arwp-agents' ), 'use_featured_image' => __( 'Use as chat avatar', 'arwp-agents' ), 'insert_into_item' => __( 'Insert into agent', 'arwp-agents' ), 'uploaded_to_this_item' => __( 'Uploaded to this agent', 'arwp-agents' ), 'items_list' => __( 'Agents list', 'arwp-agents' ), 'items_list_navigation' => __( 'Agents list navigation', 'arwp-agents' ), 'filter_items_list' => __( 'Filter agents list', 'arwp-agents' ), ); $args = array( 'label' => __( 'Agent', 'arwp-agents' ), 'description' => __( 'Chat agents for this site.', 'arwp-agents' ), 'labels' => $labels, 'supports' => array( 'title', 'thumbnail' ), 'hierarchical' => false, 'public' => false, 'show_ui' => true, 'show_in_menu' => true, 'menu_position' => 26, 'menu_icon' => 'dashicons-format-chat', 'show_in_admin_bar' => true, 'show_in_nav_menus' => false, 'can_export' => true, 'has_archive' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'capability_type' => 'post', 'map_meta_cap' => true, 'capabilities' => arwp_agent_capabilities(), 'show_in_rest' => false, ); register_post_type( 'arwp_agent', $args ); } /** * Add Meta Box for arwp_agent custom post type. */ public function add_agent_meta_boxes() { global $wp_meta_boxes; // Change default 'Publish' metabox title to 'Publish Agent'. if ( isset( $wp_meta_boxes['arwp_agent']['side']['core']['submitdiv'] ) ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Core has no filter for this metabox title. $wp_meta_boxes['arwp_agent']['side']['core']['submitdiv']['title'] = __( 'Publish Agent', 'arwp-agents' ); } add_meta_box( 'arwp_agent_core_settings', __( 'Agent & Model', 'arwp-agents' ), array( $this, 'render_agent_core_settings_meta_box' ), 'arwp_agent', 'normal', 'high' ); add_meta_box( 'arwp_agent_ui_settings', __( 'Chat Appearance', 'arwp-agents' ), array( $this, 'render_agent_ui_settings_meta_box' ), 'arwp_agent', 'normal', 'high' ); add_meta_box( 'arwp_agent_message_checks', __( 'Message checks', 'arwp-agents' ), array( $this, 'render_agent_checks_meta_box' ), 'arwp_agent', 'normal', 'default' ); add_meta_box( 'arwp_agent_shortcode', __( 'Add to a page', 'arwp-agents' ), array( $this, 'render_agent_shortcode_meta_box' ), 'arwp_agent', 'side', 'high' ); } /** * Render Agent Shortcode Meta Box. * * @param WP_Post $post Current post. */ public function render_agent_shortcode_meta_box( $post ) { if ( 'auto-draft' === $post->post_status || empty( $post->ID ) ) { echo '

' . esc_html__( 'Please save or publish the agent first to generate a shortcode.', 'arwp-agents' ) . '

'; return; } $shortcode = '[arwp id="' . intval( $post->ID ) . '"]'; ?>

ID, '_arwp_ui_theme', true ); $ui_title = get_post_meta( $post->ID, '_arwp_ui_title', true ); $ui_greeting = get_post_meta( $post->ID, '_arwp_ui_greeting', true ); $ui_placeholder = get_post_meta( $post->ID, '_arwp_ui_placeholder', true ); $primary_color = get_post_meta( $post->ID, '_arwp_ui_primary_color', true ); if ( empty( $ui_theme ) ) { $ui_theme = 'dark'; } if ( empty( $ui_title ) ) { $ui_title = 'AI Assistant'; } if ( empty( $ui_greeting ) ) { $ui_greeting = 'Hello! How can I help you today?'; } if ( empty( $ui_placeholder ) ) { $ui_placeholder = 'Type your message here...'; } if ( empty( $primary_color ) ) { $primary_color = '#3b82f6'; } ?> ID, '_arwp_ui_description', true ); $logo_id = absint( get_post_meta( $post->ID, '_arwp_ui_logo_id', true ) ); $logo_url = $logo_id ? wp_get_attachment_image_url( $logo_id, 'medium' ) : ''; $suggestions = get_post_meta( $post->ID, '_arwp_ui_suggestions', true ); $disclaimer = get_post_meta( $post->ID, '_arwp_ui_disclaimer', true ); if ( ! is_string( $ui_description ) ) { $ui_description = ''; } if ( ! is_string( $logo_url ) ) { $logo_url = ''; } if ( ! is_array( $suggestions ) ) { $suggestions = array(); } if ( ! is_string( $disclaimer ) ) { $disclaimer = ''; } $suggestions = array_values( array_filter( $suggestions, 'is_string' ) ); ?>

ID, '_arwp_blocked_phrases', true ); $patterns = get_post_meta( $post->ID, '_arwp_blocked_patterns', true ); if ( ! is_array( $phrases ) ) { $phrases = array(); } if ( ! is_array( $patterns ) ) { $patterns = array(); } $phrases = array_values( array_filter( $phrases, 'is_string' ) ); $patterns = array_values( array_filter( $patterns, 'is_string' ) ); ?>

ID, '_arwp_system_prompt', true ); $model = get_post_meta( $post->ID, '_arwp_model', true ); $cooldown = get_post_meta( $post->ID, '_arwp_cooldown', true ); $rate_ip = get_post_meta( $post->ID, '_arwp_rate_limit_per_ip', true ); $rate_agent = get_post_meta( $post->ID, '_arwp_rate_limit_per_agent', true ); $history_limit = get_post_meta( $post->ID, '_arwp_history_context_limit', true ); $temperature = get_post_meta( $post->ID, '_arwp_temperature', true ); $max_tokens = get_post_meta( $post->ID, '_arwp_max_tokens', true ); if ( empty( $system_prompt ) ) { $system_prompt = 'You are a helpful and professional AI assistant.'; } if ( ! $model ) { $model = 'default'; } if ( '' === $cooldown ) { $cooldown = arwp_default_cooldown(); } if ( '' === $rate_ip ) { $rate_ip = arwp_default_rate_limit_per_ip(); } if ( '' === $rate_agent ) { $rate_agent = arwp_default_rate_limit_per_agent(); } if ( '' === $temperature ) { $temperature = 0.7; } if ( '' === $max_tokens ) { $max_tokens = 1000; } $fetched_models = class_exists( 'ARWP_Settings' ) ? ARWP_Settings::get_models() : array(); $models = array( 'default' => __( 'Use Global Default Model', 'arwp-agents' ), ) + $fetched_models; ?> ID, '_arwp_access', true ); if ( ! in_array( $access, array( 'public', 'logged_in', 'roles' ), true ) ) { $access = 'public'; } $access_roles = get_post_meta( $post->ID, '_arwp_access_roles', true ); if ( ! is_array( $access_roles ) ) { $access_roles = array(); } $rate_user = get_post_meta( $post->ID, '_arwp_rate_limit_per_user', true ); if ( '' === $rate_user || false === $rate_user || null === $rate_user ) { $rate_user = 0; } $role_limits = get_post_meta( $post->ID, '_arwp_rate_limit_per_role', true ); if ( ! is_array( $role_limits ) ) { $role_limits = array(); } $editable_roles = $this->editable_roles(); ?>

> $role_data ) : ?>

$role_data ) : ?>

editable_roles() ); $access_roles = array(); $posted_roles = isset( $_POST['arwp_access_roles'] ) ? map_deep( wp_unslash( $_POST['arwp_access_roles'] ), 'sanitize_text_field' ) : array(); if ( is_array( $posted_roles ) ) { foreach ( $posted_roles as $role ) { $role = sanitize_key( $role ); if ( in_array( $role, $valid_roles, true ) && ! in_array( $role, $access_roles, true ) ) { $access_roles[] = $role; } } } update_post_meta( $post_id, '_arwp_access_roles', $access_roles ); $rate_user = isset( $_POST['arwp_rate_limit_per_user'] ) ? intval( $_POST['arwp_rate_limit_per_user'] ) : 0; update_post_meta( $post_id, '_arwp_rate_limit_per_user', min( 10000, max( 0, $rate_user ) ) ); $role_limits = array(); $posted_limits = isset( $_POST['arwp_role_limits'] ) ? map_deep( wp_unslash( $_POST['arwp_role_limits'] ), 'sanitize_text_field' ) : array(); if ( is_array( $posted_limits ) ) { foreach ( $posted_limits as $role => $limit ) { $role = sanitize_key( $role ); if ( ! in_array( $role, $valid_roles, true ) ) { continue; } $role_limits[ $role ] = min( 100000, max( 0, intval( $limit ) ) ); } } update_post_meta( $post_id, '_arwp_rate_limit_per_role', $role_limits ); if ( isset( $_POST['arwp_agent_ui_meta_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['arwp_agent_ui_meta_nonce'] ) ), 'arwp_save_agent_ui_meta_action' ) ) { if ( isset( $_POST['arwp_ui_theme'] ) ) { $theme = sanitize_text_field( wp_unslash( $_POST['arwp_ui_theme'] ) ); if ( ! in_array( $theme, array( 'light', 'dark' ), true ) ) { $theme = 'dark'; } update_post_meta( $post_id, '_arwp_ui_theme', $theme ); } if ( isset( $_POST['arwp_ui_title'] ) ) { update_post_meta( $post_id, '_arwp_ui_title', sanitize_text_field( wp_unslash( $_POST['arwp_ui_title'] ) ) ); } if ( isset( $_POST['arwp_ui_greeting'] ) ) { update_post_meta( $post_id, '_arwp_ui_greeting', sanitize_textarea_field( wp_unslash( $_POST['arwp_ui_greeting'] ) ) ); } if ( isset( $_POST['arwp_ui_placeholder'] ) ) { update_post_meta( $post_id, '_arwp_ui_placeholder', sanitize_text_field( wp_unslash( $_POST['arwp_ui_placeholder'] ) ) ); } if ( isset( $_POST['arwp_ui_primary_color'] ) ) { $color = sanitize_hex_color( wp_unslash( $_POST['arwp_ui_primary_color'] ) ); if ( $color ) { update_post_meta( $post_id, '_arwp_ui_primary_color', $color ); } } if ( isset( $_POST['arwp_ui_description'] ) ) { $description = sanitize_text_field( wp_unslash( $_POST['arwp_ui_description'] ) ); update_post_meta( $post_id, '_arwp_ui_description', wp_slash( $this->cut_chars( $description, 180 ) ) ); } $logo_id = isset( $_POST['arwp_ui_logo_id'] ) ? absint( $_POST['arwp_ui_logo_id'] ) : 0; if ( $logo_id && ! wp_attachment_is_image( $logo_id ) ) { $logo_id = 0; } update_post_meta( $post_id, '_arwp_ui_logo_id', $logo_id ); $suggestions = isset( $_POST['arwp_ui_suggestions'] ) ? sanitize_textarea_field( wp_unslash( $_POST['arwp_ui_suggestions'] ) ) : ''; update_post_meta( $post_id, '_arwp_ui_suggestions', wp_slash( $this->lines_from_textarea( $suggestions, 6, 120 ) ) ); if ( isset( $_POST['arwp_ui_disclaimer'] ) ) { update_post_meta( $post_id, '_arwp_ui_disclaimer', wp_slash( sanitize_textarea_field( wp_unslash( $_POST['arwp_ui_disclaimer'] ) ) ) ); } } if ( isset( $_POST['arwp_agent_checks_meta_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['arwp_agent_checks_meta_nonce'] ) ), 'arwp_save_agent_checks_meta_action' ) ) { $phrase_raw = isset( $_POST['arwp_blocked_phrases'] ) ? sanitize_textarea_field( wp_unslash( $_POST['arwp_blocked_phrases'] ) ) : ''; update_post_meta( $post_id, '_arwp_blocked_phrases', wp_slash( $this->lines_from_textarea( $phrase_raw, 20, 80 ) ) ); $pattern_raw = isset( $_POST['arwp_blocked_patterns'] ) ? sanitize_textarea_field( wp_unslash( $_POST['arwp_blocked_patterns'] ) ) : ''; $patterns = array(); $dropped = false; foreach ( $this->textarea_lines( $pattern_raw ) as $line ) { $line = sanitize_text_field( $line ); if ( '' === $line ) { continue; } if ( ! arwp_pattern_is_safe( $line ) ) { $dropped = true; continue; } if ( ! in_array( $line, $patterns, true ) ) { $patterns[] = $line; } if ( count( $patterns ) >= 10 ) { break; } } update_post_meta( $post_id, '_arwp_blocked_patterns', wp_slash( $patterns ) ); if ( $dropped ) { set_transient( 'arwp_admin_notice_' . get_current_user_id(), __( 'Some patterns were not saved because they are not valid.', 'arwp-agents' ), 60 ); } } } /** * Roles the current user is allowed to assign. * * @return array */ private function editable_roles() { if ( ! function_exists( 'get_editable_roles' ) ) { require_once ABSPATH . 'wp-admin/includes/user.php'; } $roles = get_editable_roles(); return is_array( $roles ) ? $roles : array(); } /** * Cut a string to a character limit. * * @param string $text Text. * @param int $limit Maximum characters. * @return string */ private function cut_chars( $text, $limit ) { $text = (string) $text; $limit = (int) $limit; if ( function_exists( 'mb_substr' ) ) { return mb_substr( $text, 0, $limit ); } return substr( $text, 0, $limit ); } /** * Split a textarea into trimmed lines. * * @param mixed $raw Submitted text. * @return array */ private function textarea_lines( $raw ) { $raw = str_replace( array( "\r\n", "\r" ), "\n", (string) $raw ); return explode( "\n", $raw ); } /** * Keep the first non-empty lines, trimmed and cut to length. * * @param mixed $raw Submitted text. * @param int $max Maximum number of lines. * @param int $chars Maximum characters per line. * @return array */ private function lines_from_textarea( $raw, $max, $chars ) { $lines = array(); foreach ( $this->textarea_lines( $raw ) as $line ) { $line = sanitize_text_field( trim( $line ) ); if ( '' === $line ) { continue; } $line = $this->cut_chars( $line, $chars ); if ( '' === $line || in_array( $line, $lines, true ) ) { continue; } $lines[] = $line; if ( count( $lines ) >= (int) $max ) { break; } } return $lines; } }