__('Not AI-generated / no label', 'aiactify-compliance'), 'ai' => __('AI-generated', 'aiactify-compliance'), 'ai_assisted' => __('AI-assisted (human edited)', 'aiactify-compliance'), ); } /* ───────────────────────────────────────────── * Meta box * ───────────────────────────────────────────── */ function aiactify_add_meta_box() { $post_types = get_post_types(array('public' => true)); unset($post_types['attachment']); foreach ($post_types as $post_type) { add_meta_box( 'aiactify_label_box', __('AI Content Label (EU AI Act)', 'aiactify-compliance'), 'aiactify_render_meta_box', $post_type, 'side', 'default' ); } } add_action('add_meta_boxes', 'aiactify_add_meta_box'); function aiactify_render_meta_box($post) { $current = get_post_meta($post->ID, '_aiactify_ai_status', true); wp_nonce_field('aiactify_save_label', 'aiactify_label_nonce'); echo '
' . esc_html__('Adds a visible label and machine-readable metadata (Schema.org / IPTC) to this post.', 'aiactify-compliance') . '
'; foreach (aiactify_valid_statuses() as $value => $label) { printf( '', esc_attr($value), checked($current, $value, false), esc_html($label) ); } echo '' . esc_html__('Transparency obligations under Art. 50 EU AI Act apply from 2 August 2026.', 'aiactify-compliance') . '
'; } function aiactify_save_meta_box($post_id) { if (!isset($_POST['aiactify_label_nonce']) || !wp_verify_nonce(sanitize_key($_POST['aiactify_label_nonce']), 'aiactify_save_label')) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (!current_user_can('edit_post', $post_id)) { return; } $status = isset($_POST['aiactify_ai_status']) ? sanitize_key($_POST['aiactify_ai_status']) : ''; if (!array_key_exists($status, aiactify_valid_statuses())) { $status = ''; } if ('' === $status) { delete_post_meta($post_id, '_aiactify_ai_status'); } else { update_post_meta($post_id, '_aiactify_ai_status', $status); } aiactify_sync_status_to_platform($post_id, $status); } add_action('save_post', 'aiactify_save_meta_box'); /** * v2.1: Mirror the editor's decision to the AIActify platform (optional). * * Only runs when the site is connected (Site ID + API Key configured). * Fire-and-forget (non-blocking) so saving a post is never slowed down. * Status mapping: 'ai' stays AI; 'ai_assisted' (AI-edited human content) maps * to 'ai_modified' — the EU publishes a dedicated "AI MODIFIED" label for it. * Note: the Art. 50(4) editorial carve-out only covers TEXT on matters of * public interest, so AI-edited images/videos still need a visible label * (Commission guidelines, 20 July 2026). No selection maps to 'pending'. */ function aiactify_sync_status_to_platform($post_id, $status) { if (wp_is_post_revision($post_id) || 'publish' !== get_post_status($post_id)) { return; } $site_id = get_option('aiactify_site_id'); $api_key = get_option('aiactify_api_key'); if (empty($site_id) || empty($api_key)) { return; // Not connected — local labels work standalone. } $map = array( 'ai' => 'ai', 'ai_assisted' => 'ai_modified', '' => 'pending', ); if (!isset($map[$status])) { return; } wp_remote_post(AIACTIFY_API_BASE . '/wordpress/validate', array( 'timeout' => 3, 'blocking' => false, 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . sanitize_text_field($api_key), ), 'body' => wp_json_encode(array( 'siteKey' => sanitize_text_field($site_id), 'url' => get_permalink($post_id), 'status' => $map[$status], )), )); } /* ───────────────────────────────────────────── * Frontend: visible badge + JSON-LD * ───────────────────────────────────────────── */ /** * Official EU AI Office pictogram (basic "AI" icon) from the European * Commission's asset kit (Code of Practice on Transparency of AI-Generated * Content, June 2026): https://digital-strategy.ec.europa.eu/en/policies/ * eu-icons-labelling-ai-generated-content — embedded 1:1 as the official vector * (a single even-odd path; the "AI" is knocked out) and recoloured to the badge * text colour. Identical to the icon rendered by the AIActify snippet, so the * WordPress badge matches the platform exactly. $acronym is kept for call * compatibility but is now part of the official vector and no longer drawn. */ function aiactify_eu_icon_svg($acronym, $color) { $path = 'M272.03,100.72c100.92,0,182.74,81.82,182.74,182.75s-81.82,182.74-182.74,182.74-182.75-81.82-182.75-182.74,81.82-182.75,182.75-182.75ZM170.79,353.74c-1.08,0-2.05-.43-2.92-1.31-.88-.87-1.31-1.84-1.31-2.92,0-.67.07-1.27.2-1.81l47.34-129.32c.4-1.48,1.24-2.79,2.52-3.93,1.27-1.14,3.05-1.71,5.34-1.71h29.81c2.28,0,4.06.57,5.34,1.71,1.27,1.14,2.11,2.45,2.52,3.93l47.14,129.32c.27.54.4,1.14.4,1.81,0,1.08-.44,2.05-1.31,2.92s-1.91,1.31-3.12,1.31h-24.78c-2.01,0-3.52-.5-4.53-1.51-1.01-1.01-1.65-1.91-1.91-2.72l-7.86-20.55h-53.78l-7.65,20.55c-.27.81-.88,1.71-1.81,2.72-.94,1.01-2.55,1.51-4.83,1.51h-24.78ZM218.13,299.96h37.47l-18.93-53.18-18.53,53.18ZM328.11,353.74c-1.48,0-2.69-.47-3.63-1.41-.94-.94-1.41-2.15-1.41-3.63v-130.93c0-1.48.47-2.68,1.41-3.63s2.15-1.41,3.63-1.41h26.99c1.48,0,2.68.47,3.63,1.41.94.94,1.41,2.15,1.41,3.63v130.93c0,1.48-.47,2.69-1.41,3.63-.94.94-2.15,1.41-3.63,1.41h-26.99Z'; return ''; } function aiactify_badge_html($status) { /* translators: short acronym shown inside the EU AI pictogram */ $acronym = _x('AI', 'pictogram acronym', 'aiactify-compliance'); $text = ('ai_assisted' === $status) ? __('AI-assisted content', 'aiactify-compliance') : __('AI-generated content', 'aiactify-compliance'); // Variante A: offizielles EU-Label 1:1 (Option 'aiactify_label_style'). // Die Labels der Kommission sind fertige Zeichen inkl. Text - sie werden // bewusst nicht eingefaerbt und nicht uebersetzt, genau wie das CE-Zeichen. if ('official' === get_option('aiactify_label_style', 'custom')) { $key = ('ai_assisted' === $status) ? 'modified' : 'generated'; $svg = function_exists('aiactify_eu_official_label_svg') ? aiactify_eu_official_label_svg($key, 20, false) : ''; if ('' !== $svg) { return '