' . esc_html__( 'Executor can send administrator-selected WordPress context to OpenAI when an authorized administrator actively uses the AI assistant. Review and adapt the suggested text below for your site.', 'wteam-executor' ) . '
';
$content .= '' . esc_html__( 'Suggested text:', 'wteam-executor' ) . '
';
$content .= '' . esc_html__( 'When an authorized administrator uses Executor, information needed to process the request may be sent to OpenAI. Depending on the task and enabled settings, this may include prompts and conversation history, screenshots of WordPress administration or editor screens, visible page or DOM information and controls, WordPress environment metadata, bounded source or log excerpts, and bounded database diagnostic results.', 'wteam-executor' ) . '
';
$content .= '' . esc_html__( 'Screenshots and diagnostic data can include personal, confidential, or sensitive information that is visible in WordPress administration or stored by the site. Database diagnostic redaction is enabled by default; if an administrator disables redaction, diagnostic results sent to OpenAI may contain personal or sensitive database values.', 'wteam-executor' ) . '
';
$content .= '' . sprintf(
/* translators: %s: URL to the OpenAI Privacy Policy. */
wp_kses_post( __( 'Data sent to OpenAI is processed by OpenAI according to its applicable terms and Privacy Policy .', 'wteam-executor' ) ),
esc_url( 'https://openai.com/policies/privacy-policy/' )
) . '
';
$content .= '' . esc_html__( 'Executor encrypts saved OpenAI API keys and ChatGPT authentication credentials with AES-256-GCM using the WordPress security keys from wp-config.php. Changing those keys makes previously stored credentials unreadable, so the API key must be entered again and ChatGPT must be reconnected. ChatGPT authentication data is removed when the account is disconnected or the plugin is uninstalled.', 'wteam-executor' ) . '
';
wp_add_privacy_policy_content(
__( 'Executor', 'wteam-executor' ),
wp_kses_post( $content )
);
}
/**
* @param string $hook_suffix
* @return void
*/
public function enqueue_assets( $hook_suffix ) {
$allowed_hooks = [
'toplevel_page_' . self::PAGE_SLUG,
];
if ( ! WTeam_Executor_Access_Control::can_current_user() || ! in_array( $hook_suffix, $allowed_hooks, true ) ) {
return;
}
wp_enqueue_style(
'wteam-executor-settings',
plugins_url( 'assets/css/settings.css', WTEAM_EXECUTOR_FILE ),
[],
WTEAM_EXECUTOR_VERSION
);
$settings_script_url = plugins_url( 'assets/js/settings.js', WTEAM_EXECUTOR_FILE );
wp_enqueue_script(
'wteam-executor-settings',
$settings_script_url,
[],
WTEAM_EXECUTOR_VERSION,
true
);
$codex_available = class_exists( WTeam_Executor_Codex_Runtime::class );
wp_localize_script(
'wteam-executor-settings',
'WTeam_ExecutorSettings',
[
'pricePrefix' => __( 'API text price', 'wteam-executor' ),
'inputLabel' => __( 'Input', 'wteam-executor' ),
'cachedInputLabel' => __( 'Cached input', 'wteam-executor' ),
'outputLabel' => __( 'Output', 'wteam-executor' ),
'contextLabel' => __( 'Context', 'wteam-executor' ),
'maxOutputLabel' => __( 'Max output', 'wteam-executor' ),
'priceUnavailable' => __( 'Pricing is unavailable for this catalog entry.', 'wteam-executor' ),
'adminSearchPlaceholder' => __( 'Search and select administrators…', 'wteam-executor' ),
'removeAdminLabel' => __( 'Remove administrator', 'wteam-executor' ),
'noAdminsFound' => __( 'No administrators found.', 'wteam-executor' ),
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'codexNonce' => $codex_available ? wp_create_nonce( WTeam_Executor_Codex_Runtime::NONCE_ACTION ) : '',
'codexLoginAction' => $codex_available ? WTeam_Executor_Codex_Runtime::LOGIN_AJAX_ACTION : '',
'codexStatusAction' => $codex_available ? WTeam_Executor_Codex_Runtime::STATUS_AJAX_ACTION : '',
'codexLogoutAction' => $codex_available ? WTeam_Executor_Codex_Runtime::LOGOUT_AJAX_ACTION : '',
'i18n' => class_exists( WTeam_Executor_Visual_Navigator::class ) ? WTeam_Executor_Visual_Navigator::ui_i18n() : [],
]
);
}
/** @return void */
public function register_settings() {
register_setting(
self::SETTINGS_GROUP,
self::OPTION_NAME,
[
'type' => 'array',
'sanitize_callback' => [ $this, 'sanitize_settings' ],
'default' => self::get_defaults(),
]
);
add_settings_section( 'wteam_executor_security_section', __( 'Security & access', 'wteam-executor' ), [ $this, 'render_security_section' ], self::PAGE_SLUG );
add_settings_field( 'access_mode', __( 'Who can use Executor', 'wteam-executor' ), [ $this, 'render_access_mode_field' ], self::PAGE_SLUG, 'wteam_executor_security_section' );
add_settings_field( 'allowed_admin_ids', __( 'Allowed administrators', 'wteam-executor' ), [ $this, 'render_allowed_admin_ids_field' ], self::PAGE_SLUG, 'wteam_executor_security_section' );
add_settings_section( 'wteam_executor_api_section', __( 'AI connection', 'wteam-executor' ), [ $this, 'render_api_section' ], self::PAGE_SLUG );
add_settings_field( 'ai_provider', __( 'AI provider', 'wteam-executor' ), [ $this, 'render_ai_provider_field' ], self::PAGE_SLUG, 'wteam_executor_api_section' );
add_settings_field( 'api_key', __( 'OpenAI API key', 'wteam-executor' ), [ $this, 'render_api_key_field' ], self::PAGE_SLUG, 'wteam_executor_api_section' );
add_settings_field( 'api_temporary_chat', __( 'Temporary Chat', 'wteam-executor' ), [ $this, 'render_api_temporary_chat_field' ], self::PAGE_SLUG, 'wteam_executor_api_section' );
add_settings_field( 'codex_connection', __( 'ChatGPT account', 'wteam-executor' ), [ $this, 'render_codex_connection_field' ], self::PAGE_SLUG, 'wteam_executor_api_section' );
add_settings_field( 'codex_model', __( 'ChatGPT model override', 'wteam-executor' ), [ $this, 'render_codex_model_field' ], self::PAGE_SLUG, 'wteam_executor_api_section' );
add_settings_field( 'codex_setup_guide', __( 'ChatGPT setup guide', 'wteam-executor' ), [ $this, 'render_codex_setup_guide_field' ], self::PAGE_SLUG, 'wteam_executor_api_section' );
add_settings_section( 'wteam_executor_analysis_section', __( 'Analysis defaults', 'wteam-executor' ), [ $this, 'render_analysis_section' ], self::PAGE_SLUG );
add_settings_field( 'model', __( 'Model', 'wteam-executor' ), [ $this, 'render_model_field' ], self::PAGE_SLUG, 'wteam_executor_analysis_section' );
add_settings_field( 'max_rounds', __( 'Maximum analysis rounds', 'wteam-executor' ), [ $this, 'render_max_rounds_field' ], self::PAGE_SLUG, 'wteam_executor_analysis_section' );
add_settings_field( 'system_prompt', __( 'System prompt', 'wteam-executor' ), [ $this, 'render_system_prompt_field' ], self::PAGE_SLUG, 'wteam_executor_analysis_section' );
add_settings_section( 'wteam_executor_assistant_section', __( 'Assistant diagnostics', 'wteam-executor' ), [ $this, 'render_assistant_section' ], self::PAGE_SLUG );
add_settings_field( 'ask_to_continue', __( 'Ask to continue at round limit', 'wteam-executor' ), [ $this, 'render_ask_to_continue_field' ], self::PAGE_SLUG, 'wteam_executor_assistant_section' );
add_settings_field( 'assistant_launcher_position', __( 'Assistant launcher position', 'wteam-executor' ), [ $this, 'render_assistant_launcher_position_field' ], self::PAGE_SLUG, 'wteam_executor_assistant_section' );
add_settings_field( 'assistant_backend_tools_enabled', __( 'Enable server-side assistant tools', 'wteam-executor' ), [ $this, 'render_assistant_backend_tools_enabled_field' ], self::PAGE_SLUG, 'wteam_executor_assistant_section' );
add_settings_field( 'file_reads_enabled', __( 'Enable file and log reads', 'wteam-executor' ), [ $this, 'render_file_reads_enabled_field' ], self::PAGE_SLUG, 'wteam_executor_assistant_section' );
add_settings_section( 'wteam_executor_database_section', __( 'WordPress database diagnostics', 'wteam-executor' ), [ $this, 'render_database_section' ], self::PAGE_SLUG );
add_settings_field( 'database_reads_enabled', __( 'Enable database reads', 'wteam-executor' ), [ $this, 'render_database_reads_enabled_field' ], self::PAGE_SLUG, 'wteam_executor_database_section' );
add_settings_field( 'redact_sensitive_data', __( 'Redact sensitive database values', 'wteam-executor' ), [ $this, 'render_redact_sensitive_data_field' ], self::PAGE_SLUG, 'wteam_executor_database_section' );
add_settings_field( 'database_max_read_rows', __( 'Maximum rows per diagnostic query', 'wteam-executor' ), [ $this, 'render_database_max_read_rows_field' ], self::PAGE_SLUG, 'wteam_executor_database_section' );
foreach ( self::settings_extensions() as $extension ) {
if ( isset( $extension['register_fields'] ) && is_callable( $extension['register_fields'] ) ) {
call_user_func( $extension['register_fields'], $this );
}
}
}
/** @return array */
public static function get_defaults() {
$defaults = [
'access_mode' => WTeam_Executor_Access_Control::MODE_ALL,
'allowed_admin_ids' => [],
'ai_provider' => 'openai_api',
'api_key' => '',
'api_temporary_chat' => true,
'model' => WTeam_Executor_Model_Catalog::get_default_model(),
'api_reasoning_effort' => 'low',
'codex_model' => '',
'codex_reasoning_effort' => 'medium',
'max_rounds' => self::DEFAULT_MAX_ROUNDS,
'ask_to_continue' => true,
'system_prompt' => self::DEFAULT_SYSTEM_PROMPT,
'assistant_launcher_position' => 'right',
'assistant_backend_tools_enabled' => false,
'file_reads_enabled' => false,
'database_reads_enabled' => false,
'redact_sensitive_data' => true,
'database_max_read_rows' => WTeam_Executor_Data_Policy::DEFAULT_MAX_READ_ROWS,
];
foreach ( self::settings_extensions() as $extension ) {
if ( isset( $extension['defaults'] ) && is_array( $extension['defaults'] ) ) {
$defaults = array_merge( $defaults, $extension['defaults'] );
}
}
return $defaults;
}
/** @return array> */
private static function settings_extensions() {
static $extensions = null;
if ( null === $extensions ) {
$extensions = apply_filters( 'wteam_executor_settings_extensions', [] );
$extensions = is_array( $extensions ) ? $extensions : [];
}
return $extensions;
}
/**
* @param array|null $settings
* @param bool|null $auto_actions
* @return array
*/
public static function assistant_control_catalog( ?array $settings = null, $auto_actions = null ) {
$settings = null === $settings ? self::get_settings() : $settings;
$options = [
[ 'label' => __( 'Enable server-side assistant tools', 'wteam-executor' ), 'enabled' => ! empty( $settings['assistant_backend_tools_enabled'] ) ],
[ 'label' => __( 'Enable file and log reads', 'wteam-executor' ), 'enabled' => ! empty( $settings['file_reads_enabled'] ) ],
[ 'label' => __( 'Enable database reads', 'wteam-executor' ), 'enabled' => ! empty( $settings['database_reads_enabled'] ) ],
];
$session_controls = [];
if ( null !== $auto_actions ) {
$session_controls[] = [ 'label' => __( 'Auto Actions', 'wteam-executor' ), 'enabled' => (bool) $auto_actions, 'scope' => __( 'current assistant session', 'wteam-executor' ) ];
}
$catalog = [
'settings_location' => __( 'Executor > Settings', 'wteam-executor' ),
'options' => $options,
'session_controls' => $session_controls,
];
foreach ( self::settings_extensions() as $extension ) {
if ( isset( $extension['control_catalog'] ) && is_callable( $extension['control_catalog'] ) ) {
$catalog = call_user_func( $extension['control_catalog'], $catalog, $settings, $auto_actions );
}
}
return is_array( $catalog ) ? $catalog : [];
}
/** @return array */
public static function get_settings() {
$stored = get_option( self::OPTION_NAME, [] );
$stored = is_array( $stored ) ? $stored : [];
$values = wp_parse_args( $stored, self::get_defaults() );
$values['access_mode'] = isset( $values['access_mode'] ) ? sanitize_key( (string) $values['access_mode'] ) : WTeam_Executor_Access_Control::MODE_ALL;
if ( ! in_array( $values['access_mode'], [ WTeam_Executor_Access_Control::MODE_ALL, WTeam_Executor_Access_Control::MODE_SELECTED ], true ) ) {
$values['access_mode'] = WTeam_Executor_Access_Control::MODE_ALL;
}
$values['allowed_admin_ids'] = WTeam_Executor_Access_Control::sanitize_allowed_admin_ids( isset( $values['allowed_admin_ids'] ) ? $values['allowed_admin_ids'] : [] );
$values['ai_provider'] = self::sanitize_ai_provider( isset( $values['ai_provider'] ) ? $values['ai_provider'] : 'openai_api' );
if ( 'chatgpt_codex' === $values['ai_provider'] && ! class_exists( WTeam_Executor_Codex_Runtime::class ) ) {
$values['ai_provider'] = 'openai_api';
}
$values['api_key'] = isset( $stored['api_key'] ) ? trim( WTeam_Executor_Secret_Storage::decrypt_string( $stored['api_key'], 'openai_api_key' ) ) : '';
$values['api_temporary_chat'] = ! empty( $values['api_temporary_chat'] );
$values['model'] = self::sanitize_model_name( isset( $values['model'] ) ? $values['model'] : WTeam_Executor_Model_Catalog::get_default_model() );
$values['api_reasoning_effort'] = self::normalize_reasoning_effort( isset( $values['api_reasoning_effort'] ) ? $values['api_reasoning_effort'] : 'low', 'low' );
$values['codex_model'] = self::sanitize_codex_model( isset( $values['codex_model'] ) ? $values['codex_model'] : '' );
$values['codex_reasoning_effort'] = self::normalize_reasoning_effort( isset( $values['codex_reasoning_effort'] ) ? $values['codex_reasoning_effort'] : 'medium', 'medium' );
$values['max_rounds'] = self::normalize_max_rounds( isset( $values['max_rounds'] ) ? $values['max_rounds'] : self::DEFAULT_MAX_ROUNDS );
$values['ask_to_continue'] = ! empty( $values['ask_to_continue'] );
$values['system_prompt'] = self::normalize_prompt( isset( $values['system_prompt'] ) ? $values['system_prompt'] : self::DEFAULT_SYSTEM_PROMPT );
$values['assistant_launcher_position'] = self::normalize_assistant_launcher_position( isset( $values['assistant_launcher_position'] ) ? $values['assistant_launcher_position'] : 'right' );
$values['assistant_backend_tools_enabled'] = ! empty( $values['assistant_backend_tools_enabled'] );
$values['file_reads_enabled'] = ! empty( $values['file_reads_enabled'] );
$values['database_reads_enabled'] = ! empty( $values['database_reads_enabled'] );
$values['redact_sensitive_data'] = ! empty( $values['redact_sensitive_data'] );
$values['database_max_read_rows'] = self::normalize_database_rows(
isset( $values['database_max_read_rows'] ) ? $values['database_max_read_rows'] : WTeam_Executor_Data_Policy::DEFAULT_MAX_READ_ROWS,
WTeam_Executor_Data_Policy::MAX_ALLOWED_READ_ROWS
);
foreach ( self::settings_extensions() as $extension ) {
if ( isset( $extension['normalize'] ) && is_callable( $extension['normalize'] ) ) {
$values = call_user_func( $extension['normalize'], $values, $stored );
}
}
return is_array( $values ) ? $values : [];
}
/**
* @param mixed $input
* @return array
*/
public function sanitize_settings( $input ) {
$input = is_array( $input ) ? $input : [];
$existing = self::get_settings();
$output = [];
if ( ! WTeam_Executor_Access_Control::can_current_user() ) {
add_settings_error( self::OPTION_NAME, 'wteam_executor_access_denied', __( 'You are not allowed to change Executor settings.', 'wteam-executor' ), 'error' );
return $existing;
}
$access_mode = isset( $input['access_mode'] ) ? sanitize_key( (string) $input['access_mode'] ) : $existing['access_mode'];
$output['access_mode'] = in_array( $access_mode, [ WTeam_Executor_Access_Control::MODE_ALL, WTeam_Executor_Access_Control::MODE_SELECTED ], true ) ? $access_mode : WTeam_Executor_Access_Control::MODE_ALL;
$submitted_admin_ids = ! empty( $input['allowed_admin_ids_present'] ) ? ( isset( $input['allowed_admin_ids'] ) ? $input['allowed_admin_ids'] : [] ) : $existing['allowed_admin_ids'];
$output['allowed_admin_ids'] = WTeam_Executor_Access_Control::sanitize_allowed_admin_ids( $submitted_admin_ids );
if ( WTeam_Executor_Access_Control::MODE_SELECTED === $output['access_mode'] && empty( $output['allowed_admin_ids'] ) ) {
$current_user_id = get_current_user_id();
if ( $current_user_id > 0 ) {
$output['allowed_admin_ids'] = [ $current_user_id ];
add_settings_error( self::OPTION_NAME, 'wteam_executor_access_lockout_prevented', __( 'At least one administrator must be allowed. Your account was kept on the Executor allow-list to prevent a lockout.', 'wteam-executor' ), 'warning' );
} else {
$output['access_mode'] = WTeam_Executor_Access_Control::MODE_ALL;
}
}
$output['ai_provider'] = self::sanitize_ai_provider( isset( $input['ai_provider'] ) ? $input['ai_provider'] : $existing['ai_provider'] );
$output['codex_model'] = self::sanitize_codex_model( isset( $input['codex_model'] ) ? $input['codex_model'] : $existing['codex_model'] );
$output['codex_reasoning_effort'] = self::normalize_reasoning_effort( isset( $input['codex_reasoning_effort'] ) ? $input['codex_reasoning_effort'] : $existing['codex_reasoning_effort'], 'medium' );
$new_api_key = isset( $input['api_key'] ) ? trim( sanitize_text_field( (string) $input['api_key'] ) ) : '';
$clear_key = ! empty( $input['clear_api_key'] );
$api_key = $clear_key ? '' : ( '' !== $new_api_key ? $new_api_key : $existing['api_key'] );
if ( '' === $api_key ) {
$output['api_key'] = '';
} else {
$encrypted_api_key = WTeam_Executor_Secret_Storage::encrypt_string( $api_key, 'openai_api_key' );
if ( is_wp_error( $encrypted_api_key ) ) {
$raw_settings = get_option( self::OPTION_NAME, [] );
$raw_settings = is_array( $raw_settings ) ? $raw_settings : [];
$output['api_key'] = isset( $raw_settings['api_key'] ) && WTeam_Executor_Secret_Storage::is_encrypted( $raw_settings['api_key'] ) ? $raw_settings['api_key'] : '';
add_settings_error( self::OPTION_NAME, 'wteam_executor_api_key_encryption_failed', $encrypted_api_key->get_error_message(), 'error' );
} else {
$output['api_key'] = $encrypted_api_key;
}
}
$output['api_temporary_chat'] = ! empty( $input['api_temporary_chat'] );
$output['model'] = self::sanitize_model_name( isset( $input['model'] ) ? $input['model'] : $existing['model'] );
$output['api_reasoning_effort'] = self::normalize_reasoning_effort( isset( $input['api_reasoning_effort'] ) ? $input['api_reasoning_effort'] : $existing['api_reasoning_effort'], 'low' );
$output['max_rounds'] = self::normalize_max_rounds( isset( $input['max_rounds'] ) ? $input['max_rounds'] : $existing['max_rounds'] );
$output['ask_to_continue'] = ! empty( $input['ask_to_continue'] );
$output['system_prompt'] = self::normalize_prompt( isset( $input['system_prompt'] ) ? $input['system_prompt'] : $existing['system_prompt'] );
$output['assistant_launcher_position'] = self::normalize_assistant_launcher_position( isset( $input['assistant_launcher_position'] ) ? $input['assistant_launcher_position'] : $existing['assistant_launcher_position'] );
$output['assistant_backend_tools_enabled'] = ! empty( $input['assistant_backend_tools_enabled'] );
$output['file_reads_enabled'] = ! empty( $input['file_reads_enabled'] );
$output['database_reads_enabled'] = ! empty( $input['database_reads_enabled'] );
$output['redact_sensitive_data'] = ! empty( $input['redact_sensitive_data'] );
$output['database_max_read_rows'] = self::normalize_database_rows(
isset( $input['database_max_read_rows'] ) ? $input['database_max_read_rows'] : $existing['database_max_read_rows'],
WTeam_Executor_Data_Policy::MAX_ALLOWED_READ_ROWS
);
foreach ( self::settings_extensions() as $extension ) {
if ( isset( $extension['sanitize'] ) && is_callable( $extension['sanitize'] ) ) {
$output = call_user_func( $extension['sanitize'], $output, $input, $existing );
}
}
return is_array( $output ) ? $output : [];
}
/** @return string */
private static function sanitize_ai_provider( $provider ) {
$provider = sanitize_key( (string) $provider );
if ( 'chatgpt_codex' === $provider && class_exists( WTeam_Executor_Codex_Runtime::class ) ) {
return 'chatgpt_codex';
}
return 'openai_api';
}
/** @return string */
private static function sanitize_codex_model( $model ) {
$model = trim( sanitize_text_field( (string) $model ) );
if ( '' === $model ) {
return '';
}
return preg_match( '/^[A-Za-z0-9._:\/-]{1,120}$/', $model ) ? $model : '';
}
/**
* @param mixed $model
* @return string
*/
private static function sanitize_model_name( $model ) {
$model = trim( sanitize_text_field( (string) $model ) );
if ( '' === $model || ! preg_match( '/^[A-Za-z0-9._:-]{1,100}$/', $model ) || null === WTeam_Executor_Model_Catalog::get_model( $model ) ) {
return WTeam_Executor_Model_Catalog::get_default_model();
}
return $model;
}
/**
* Normalize an OpenAI reasoning effort value.
*
* @param mixed $value
* @param string $default
* @return string
*/
public static function normalize_reasoning_effort( $value, $default = 'medium' ) {
$allowed = [ 'low', 'medium', 'high' ];
$default = sanitize_key( (string) $default );
if ( ! in_array( $default, $allowed, true ) ) {
$default = 'medium';
}
$value = sanitize_key( (string) $value );
return in_array( $value, $allowed, true ) ? $value : $default;
}
/**
* @param mixed $value
* @return int
*/
public static function normalize_max_rounds( $value ) {
$rounds = is_numeric( $value ) ? (int) $value : self::DEFAULT_MAX_ROUNDS;
return max( 1, min( self::MAX_ALLOWED_ROUNDS, $rounds ) );
}
/**
* @param mixed $value
* @return string
*/
private static function normalize_assistant_launcher_position( $value ) {
$position = sanitize_key( (string) $value );
return in_array( $position, [ 'left', 'right' ], true ) ? $position : 'right';
}
private static function normalize_database_rows( $value, $maximum ) {
$rows = is_numeric( $value ) ? (int) $value : 100;
return max( 1, min( (int) $maximum, $rows ) );
}
/**
* @param mixed $prompt
* @return string
*/
private static function normalize_prompt( $prompt ) {
$prompt = trim( sanitize_textarea_field( (string) $prompt ) );
return '' === $prompt ? self::DEFAULT_SYSTEM_PROMPT : $prompt;
}
/** @return void */
public function render_page() {
if ( ! WTeam_Executor_Access_Control::can_current_user() ) {
wp_die( esc_html__( 'You are not allowed to use Executor.', 'wteam-executor' ) );
}
$settings = self::get_settings();
$provider_value = isset( $settings['ai_provider'] ) && 'chatgpt_codex' === $settings['ai_provider'] ? __( 'ChatGPT account', 'wteam-executor' ) : __( 'OpenAI API', 'wteam-executor' );
$tabs = [
'security' => [ 'label' => __( 'Security', 'wteam-executor' ), 'icon' => 'dashicons-shield', 'sections' => [ 'wteam_executor_security_section' ] ],
'ai' => [ 'label' => __( 'AI Connection', 'wteam-executor' ), 'icon' => 'dashicons-cloud', 'sections' => [ 'wteam_executor_api_section', 'wteam_executor_analysis_section' ] ],
'assistant'=> [ 'label' => __( 'Assistant', 'wteam-executor' ), 'icon' => 'dashicons-admin-tools', 'sections' => [ 'wteam_executor_assistant_section' ] ],
'database' => [ 'label' => __( 'Database', 'wteam-executor' ), 'icon' => 'dashicons-database', 'sections' => [ 'wteam_executor_database_section' ] ],
];
foreach ( self::settings_extensions() as $extension ) {
if ( isset( $extension['tabs'] ) && is_array( $extension['tabs'] ) ) {
$tabs = array_merge( $tabs, $extension['tabs'] );
}
}
?>
$section_ids
* @return void
*/
private function render_settings_sections( array $section_ids ) {
global $wp_settings_sections, $wp_settings_fields;
if ( empty( $wp_settings_sections[ self::PAGE_SLUG ] ) ) {
return;
}
foreach ( $section_ids as $section_id ) {
if ( empty( $wp_settings_sections[ self::PAGE_SLUG ][ $section_id ] ) ) {
continue;
}
$section = $wp_settings_sections[ self::PAGE_SLUG ][ $section_id ];
?>
' . esc_html( $message ) . '';
}
/** @return void */
public function render_access_mode_field() {
$settings = self::get_settings();
$mode = isset( $settings['access_mode'] ) ? (string) $settings['access_mode'] : WTeam_Executor_Access_Control::MODE_ALL;
?>
/>
/>
display_name,
(string) $admin->user_login,
(string) $admin->user_email
);
?>
ID, $selected, true ) ); ?>>
' . esc_html__( 'Choose the existing OpenAI API integration or connect your own ChatGPT account. ChatGPT account mode is built into Executor and requires no API key, Node.js, Python, or shell access. Your ChatGPT password is entered only on OpenAI\'s website and is never received by WordPress.', 'wteam-executor' ) . '';
}
/** @return void */
public function render_analysis_section() {
echo '' . esc_html__( 'The maximum rounds value controls the wp-admin assistant and diagnosis flow.', 'wteam-executor' ) . '
';
}
/** @return void */
public function render_assistant_section() {
echo '' . esc_html__( 'The wp-admin assistant can inspect the current WordPress environment, use supported diagnostic tools, and operate supported wp-admin interfaces.', 'wteam-executor' ) . '
';
}
/** @return void */
public function render_assistant_launcher_position_field() {
$settings = self::get_settings();
$position = isset( $settings['assistant_launcher_position'] ) ? (string) $settings['assistant_launcher_position'] : 'right';
?>
>
>
/>
/>
Settings.', 'wteam-executor' ); ?>
' . esc_html__( 'Executor can inspect tables in the active WordPress database when database reads are enabled. Read queries are bounded, access is limited to the active WordPress database, and sensitive values can be redacted before remote analysis.', 'wteam-executor' ) . '';
}
/** @return void */
public function render_database_reads_enabled_field() {
$settings = self::get_settings();
?>
/>
/>
>
>
data-price-input=""
data-price-cached-input=""
data-price-output=""
data-currency=""
data-unit=""
data-description=""
data-notes=""
data-context-window=""
data-max-output-tokens=""
>
>
>
>
:
>
/>