get_supported_post_types(); foreach ( $post_types as $post_type ) { register_post_meta( $post_type, self::META_ORIGIN, array( 'type' => 'string', 'single' => true, 'default' => 'undeclared', 'sanitize_callback' => array( $this, 'sanitize_origin' ), 'show_in_rest' => false, 'auth_callback' => static function (): bool { return current_user_can( 'edit_posts' ); }, ) ); register_post_meta( $post_type, self::META_NOTE, array( 'type' => 'string', 'single' => true, 'default' => '', 'sanitize_callback' => 'sanitize_textarea_field', 'show_in_rest' => false, 'auth_callback' => static function (): bool { return current_user_can( 'edit_posts' ); }, ) ); } } public function sanitize_origin( $value ): string { $allowed = array_keys( $this->get_origin_choices() ); return in_array( $value, $allowed, true ) ? $value : 'undeclared'; } public function add_meta_box(): void { $post_types = $this->get_supported_post_types(); foreach ( $post_types as $post_type ) { add_meta_box( 'aiactaest-ai-usage', __( 'AI usage', 'ai-acta-est' ), array( $this, 'render_meta_box' ), $post_type, 'side', 'default' ); } } public function register_shortcodes(): void { add_shortcode( 'aiactaest_badge', array( $this, 'render_badge_shortcode' ) ); add_shortcode( 'aiactaest_trasparenza', array( $this, 'render_transparency_shortcode' ) ); add_shortcode( 'aiactaest_strumenti', array( $this, 'render_tools_shortcode' ) ); } public function add_settings_page(): void { add_options_page( __( 'Ai Acta Est Settings', 'ai-acta-est' ), __( 'Ai Acta Est', 'ai-acta-est' ), 'manage_options', 'ai-acta-est', array( $this, 'render_settings_page' ) ); } public function add_plugin_action_links( array $links ): array { $settings_link = sprintf( '%2$s', esc_url( admin_url( 'options-general.php?page=ai-acta-est' ) ), esc_html__( 'Settings', 'ai-acta-est' ) ); array_unshift( $links, $settings_link ); return $links; } public function add_admin_body_class( string $classes ): string { $screen = get_current_screen(); return $screen && 'settings_page_ai-acta-est' === $screen->id ? $classes . ' aiactaest-admin-page' : $classes; } public function capture_settings_notices(): void { $screen = get_current_screen(); if ( ! $screen || 'settings_page_ai-acta-est' !== $screen->id ) { return; } $this->settings_notices = get_settings_errors(); $GLOBALS['wp_settings_errors'] = array(); } public function register_settings(): void { register_setting( 'aiactaest_settings_group', self::OPTION_SETTINGS, array( 'type' => 'array', 'default' => $this->get_default_settings(), 'sanitize_callback' => array( $this, 'sanitize_settings' ), ) ); } public function sanitize_settings( $settings ): array { $defaults = $this->get_default_settings(); $settings = is_array( $settings ) ? $settings : array(); $position = isset( $settings['position'] ) ? sanitize_key( $settings['position'] ) : $defaults['position']; if ( ! in_array( $position, array( 'before', 'after' ), true ) ) { $position = $defaults['position']; } $assisted_text = isset( $settings['assisted_text'] ) ? sanitize_text_field( $settings['assisted_text'] ) : ''; $generated_text = isset( $settings['generated_text'] ) ? sanitize_text_field( $settings['generated_text'] ) : ''; $page_id = isset( $settings['page_id'] ) ? absint( $settings['page_id'] ) : 0; if ( $page_id && 'page' !== get_post_type( $page_id ) ) { $page_id = 0; } $sanitized = array( 'enabled' => empty( $settings['enabled'] ) ? 0 : 1, 'position' => $position, 'assisted_text' => $assisted_text, 'generated_text' => $generated_text, 'introduction' => isset( $settings['introduction'] ) ? sanitize_textarea_field( $settings['introduction'] ) : '', 'purposes' => isset( $settings['purposes'] ) ? sanitize_textarea_field( $settings['purposes'] ) : '', 'supervision' => isset( $settings['supervision'] ) ? sanitize_textarea_field( $settings['supervision'] ) : '', 'tools' => isset( $settings['tools'] ) ? sanitize_textarea_field( $settings['tools'] ) : '', 'contact' => isset( $settings['contact'] ) ? sanitize_text_field( $settings['contact'] ) : '', 'page_id' => $page_id, 'delete_data' => empty( $settings['delete_data'] ) ? 0 : 1, 'updated_at' => current_time( 'mysql', true ), ); return apply_filters( 'aiactaest_sanitized_settings', $sanitized, $settings, $defaults ); } public function render_settings_page(): void { if ( ! current_user_can( 'manage_options' ) ) { return; } $settings = $this->get_settings(); $page_id = absint( $settings['page_id'] ); $page_status = $page_id ? get_post_status( $page_id ) : false; $has_page = $page_id && 'page' === get_post_type( $page_id ) && false !== $page_status && 'trash' !== $page_status; $selected_page_id = $has_page ? $page_id : 0; $page_dropdown = wp_dropdown_pages( array( 'id' => 'aiactaest-page-id', 'name' => esc_attr( self::OPTION_SETTINGS . '[page_id]' ), 'selected' => absint( $selected_page_id ), 'post_status' => array( 'publish', 'draft', 'pending', 'private', 'future' ), 'show_option_none' => esc_html__( 'No page selected', 'ai-acta-est' ), 'option_none_value' => '0', 'echo' => 0, ) ); $create_page_url = wp_nonce_url( add_query_arg( 'action', 'aiactaest_create_transparency_page', admin_url( 'admin-post.php' ) ), 'aiactaest_create_transparency_page' ); $edit_page_url = $has_page ? get_edit_post_link( $page_id, '' ) : ''; $view_page_url = $has_page ? get_preview_post_link( $page_id ) : ''; $admin_notices = $this->get_admin_notices(); ?>
__( 'Transparency on the Use of Artificial Intelligence', 'ai-acta-est' ), 'post_content' => '[aiactaest_trasparenza]', 'post_status' => 'draft', 'post_type' => 'page', ), true ); if ( is_wp_error( $page_id ) ) { $notice = array( 'type' => 'error', 'message' => __( 'The transparency page could not be created.', 'ai-acta-est' ), ); } else { $settings = $this->get_settings(); $settings['page_id'] = (int) $page_id; update_option( self::OPTION_SETTINGS, $settings ); $notice = array( 'type' => 'success', 'message' => __( 'Transparency page created and selected.', 'ai-acta-est' ), ); } set_transient( 'aiactaest_admin_notice_' . get_current_user_id(), $notice, MINUTE_IN_SECONDS ); wp_safe_redirect( add_query_arg( array( 'page' => 'ai-acta-est', 'aiactaest_tab' => 'information', ), admin_url( 'options-general.php' ) ) ); exit; } private function get_admin_notices(): array { $notices = array(); $transient_key = 'aiactaest_admin_notice_' . get_current_user_id(); $notice = get_transient( $transient_key ); if ( is_array( $notice ) && ! empty( $notice['message'] ) ) { delete_transient( $transient_key ); $notices[] = array( 'type' => isset( $notice['type'] ) && 'error' === $notice['type'] ? 'error' : 'success', 'message' => (string) $notice['message'], ); } foreach ( $this->settings_notices as $settings_notice ) { if ( empty( $settings_notice['message'] ) ) { continue; } $type = isset( $settings_notice['type'] ) ? $settings_notice['type'] : 'success'; $notices[] = array( 'type' => in_array( $type, array( 'error', 'warning', 'info' ), true ) ? $type : 'success', 'message' => wp_strip_all_tags( (string) $settings_notice['message'] ), ); } return $notices; } public function render_meta_box( WP_Post $post ): void { $origin = get_post_meta( $post->ID, self::META_ORIGIN, true ); $note = get_post_meta( $post->ID, self::META_NOTE, true ); $choices = $this->get_origin_choices(); if ( ! isset( $choices[ $origin ] ) ) { $origin = 'undeclared'; } wp_nonce_field( 'aiactaest_save_ai_usage', 'aiactaest_nonce' ); ?>
sanitize_origin( sanitize_text_field( wp_unslash( $_POST['aiactaest_origin'] ) ) ) : 'undeclared'; $note = isset( $_POST['aiactaest_note'] ) ? sanitize_textarea_field( wp_unslash( $_POST['aiactaest_note'] ) ) : ''; update_post_meta( $post_id, self::META_ORIGIN, $origin ); if ( '' === $note ) { delete_post_meta( $post_id, self::META_NOTE ); } else { update_post_meta( $post_id, self::META_NOTE, $note ); } $user_id = get_current_user_id(); $updated_at = current_time( 'mysql', true ); update_post_meta( $post_id, self::META_UPDATED_BY, $user_id ); update_post_meta( $post_id, self::META_UPDATED_AT, $updated_at ); do_action( 'aiactaest_declaration_saved', $post_id, $origin, $note, $user_id, $updated_at ); } public function enqueue_public_assets(): void { $style_version = $this->get_asset_version( 'assets/css/public.css' ); wp_register_style( 'aiactaest-public', AIACTAEST_URL . 'assets/css/public.css', array(), $style_version ); if ( is_singular() ) { wp_enqueue_style( 'aiactaest-public' ); } } public function enqueue_admin_assets( string $hook_suffix ): void { if ( ! in_array( $hook_suffix, array( 'post.php', 'post-new.php', 'settings_page_ai-acta-est' ), true ) ) { return; } $style_version = $this->get_asset_version( 'assets/css/admin.css' ); wp_enqueue_style( 'aiactaest-admin', AIACTAEST_URL . 'assets/css/admin.css', array(), $style_version ); if ( 'settings_page_ai-acta-est' === $hook_suffix ) { $script_version = $this->get_asset_version( 'assets/js/admin.js' ); wp_enqueue_script( 'aiactaest-admin', AIACTAEST_URL . 'assets/js/admin.js', array(), $script_version, true ); } } private function get_asset_version( string $relative_path ): string { $file = AIACTAEST_PATH . $relative_path; return is_file( $file ) ? AIACTAEST_VERSION . '.' . (string) filemtime( $file ) : AIACTAEST_VERSION; } public function append_badge_to_content( string $content ): string { if ( ! is_singular() || ! in_the_loop() || ! is_main_query() ) { return $content; } $settings = $this->get_settings(); if ( empty( $settings['enabled'] ) ) { return $content; } $badge = $this->get_badge_html( get_the_ID(), array( 'source' => 'automatic', 'style' => 'standard', ) ); if ( '' === $badge ) { return $content; } return 'before' === $settings['position'] ? $badge . $content : $content . $badge; } public function render_badge_shortcode( $atts = array() ): string { $settings = $this->get_settings(); if ( empty( $settings['enabled'] ) ) { return ''; } $post_id = get_the_ID(); if ( ! $post_id ) { return ''; } $atts = shortcode_atts( array( 'style' => 'standard', ), is_array( $atts ) ? $atts : array(), 'aiactaest_badge' ); return $this->get_badge_html( $post_id, array( 'source' => 'shortcode', 'style' => sanitize_key( $atts['style'] ), ) ); } public function render_transparency_shortcode(): string { $settings = $this->get_settings(); $sections = array(); if ( '' !== $settings['introduction'] ) { $sections[] = $this->render_text_section( '', $settings['introduction'] ); } if ( '' !== $settings['purposes'] ) { $sections[] = $this->render_text_section( __( 'Purposes of use', 'ai-acta-est' ), $settings['purposes'] ); } if ( '' !== $settings['supervision'] ) { $sections[] = $this->render_text_section( __( 'Human oversight', 'ai-acta-est' ), $settings['supervision'] ); } $tools = $this->render_tools_shortcode(); if ( '' !== $tools ) { $sections[] = sprintf( '
%1$s: %2$s
', esc_html__( 'Last updated', 'ai-acta-est' ), esc_html( $timestamp ) ); } $sections = apply_filters( 'aiactaest_transparency_sections', $sections, $settings ); if ( empty( $sections ) ) { return ''; } wp_enqueue_style( 'aiactaest-public' ); return '%2$s
', esc_attr( $origin ), esc_html( $label ) ); return apply_filters( 'aiactaest_badge_html', $html, $origin, $post_id, $settings, $context ); } private function get_supported_post_types(): array { $post_types = get_post_types( array( 'public' => true ), 'names' ); unset( $post_types['attachment'] ); $post_types = apply_filters( 'aiactaest_supported_post_types', array_values( $post_types ) ); $post_types = is_array( $post_types ) ? array_map( 'sanitize_key', $post_types ) : array(); return array_values( array_unique( array_filter( $post_types, 'post_type_exists' ) ) ); } private function get_origin_choices(): array { $choices = apply_filters( 'aiactaest_origin_choices', array( 'undeclared' => __( 'Not declared', 'ai-acta-est' ), 'assisted' => __( 'AI-assisted', 'ai-acta-est' ), 'generated' => __( 'AI-generated', 'ai-acta-est' ), ) ); $clean = array(); foreach ( is_array( $choices ) ? $choices : array() as $value => $label ) { $value = sanitize_key( $value ); if ( '' !== $value && is_scalar( $label ) ) { $clean[ $value ] = sanitize_text_field( (string) $label ); } } if ( ! isset( $clean['undeclared'] ) ) { $clean = array( 'undeclared' => __( 'Not declared', 'ai-acta-est' ) ) + $clean; } return $clean; } private function get_default_settings(): array { $defaults = array( 'enabled' => 1, 'position' => 'after', 'assisted_text' => '', 'generated_text' => '', 'introduction' => '', 'purposes' => '', 'supervision' => '', 'tools' => '', 'contact' => '', 'page_id' => 0, 'delete_data' => 0, 'updated_at' => '', ); return apply_filters( 'aiactaest_default_settings', $defaults ); } private function get_settings(): array { $settings = get_option( self::OPTION_SETTINGS, array() ); $settings = wp_parse_args( is_array( $settings ) ? $settings : array(), $this->get_default_settings() ); if ( 'Contenuto realizzato con assistenza AI' === $settings['assisted_text'] ) { $settings['assisted_text'] = ''; } if ( 'Contenuto generato con AI' === $settings['generated_text'] ) { $settings['generated_text'] = ''; } return apply_filters( 'aiactaest_settings', $settings ); } private function get_tools(): array { $settings = $this->get_settings(); $tools = preg_split( '/\R/u', $settings['tools'] ); $tools = is_array( $tools ) ? array_map( 'trim', $tools ) : array(); return array_values( array_unique( array_filter( $tools ) ) ); } private function render_text_section( string $title, string $text ): string { $heading = '' === $title ? '' : '