$source, 'placement' => 'featured', 'generation_size' => '1024x1024', 'display_size' => 'large', 'custom_width' => 800, 'custom_height' => 0, 'alignment' => 'none', 'mobile_behavior' => 'full_width', 'replace_existing' => 'no', 'style' => get_option('aiwest_image_style', 'Create professional, bright and visually consistent featured images that match the website topic and brand tone. Avoid text, watermarks, clutter and unrelated elements. Use a clean modern composition suitable for a professional website.'), ]; } public static function get() { $saved = get_option(self::OPTION, []); return self::sanitize(array_merge(self::defaults(), is_array($saved) ? $saved : []), false); } public static function save_from_post($raw) { $raw = is_array($raw) ? wp_unslash($raw) : []; $rules = self::sanitize($raw, false); update_option(self::OPTION, $rules, false); update_option('aiwest_image_style', $rules['style'], false); update_option('aiwest_auto_images_enabled', $rules['source'] === 'ai' ? 'yes' : 'no', false); update_option('aiwest_auto_images_library_enabled', $rules['source'] === 'library' ? 'yes' : 'no', false); return $rules; } public static function sanitize($raw, $allow_site_default = true) { $raw = is_array($raw) ? $raw : []; $defaults = self::defaults(); $source_key = isset($raw['action']) ? 'action' : 'source'; $source = sanitize_key($raw[$source_key] ?? ($allow_site_default ? 'site_default' : $defaults['source'])); $allowed_sources = $allow_site_default ? ['site_default', 'none', 'ai', 'library'] : ['none', 'ai', 'library']; if (!in_array($source, $allowed_sources, true)) { $source = $allow_site_default ? 'site_default' : 'none'; } $placement = sanitize_key($raw['placement'] ?? $defaults['placement']); if (!in_array($placement, self::placement_values(), true)) { $placement = $defaults['placement']; } $generation_size = sanitize_text_field($raw['generation_size'] ?? ($raw['size'] ?? $defaults['generation_size'])); if (!in_array($generation_size, self::generation_sizes(), true)) { $generation_size = $defaults['generation_size']; } $display_size = sanitize_key($raw['display_size'] ?? $defaults['display_size']); if (!in_array($display_size, self::display_sizes(), true)) { $display_size = $defaults['display_size']; } $alignment = sanitize_key($raw['alignment'] ?? $defaults['alignment']); if (!in_array($alignment, self::alignment_values(), true)) { $alignment = $defaults['alignment']; } $mobile_behavior = sanitize_key($raw['mobile_behavior'] ?? $defaults['mobile_behavior']); if (!in_array($mobile_behavior, ['full_width', 'content_width'], true)) { $mobile_behavior = $defaults['mobile_behavior']; } $replace_existing = sanitize_key($raw['replace_existing'] ?? $defaults['replace_existing']); if (!in_array($replace_existing, ['no', 'yes'], true)) { $replace_existing = 'no'; } $custom_width = absint($raw['custom_width'] ?? $defaults['custom_width']); $custom_height = absint($raw['custom_height'] ?? $defaults['custom_height']); if ($custom_width < 80) $custom_width = 80; if ($custom_width > 2400) $custom_width = 2400; if ($custom_height > 2400) $custom_height = 2400; $attachment_id = absint($raw['attachment_id'] ?? 0); // UX guard: when an administrator selects a Media Library asset in a compact // per-post form, that explicit choice must not fall back to global AI rules. if ($allow_site_default && $source === 'site_default' && $attachment_id > 0) { $source = 'library'; } return [ 'action' => $source, 'source' => $source, 'placement' => $placement, 'generation_size' => $generation_size, 'size' => $generation_size, 'display_size' => $display_size, 'custom_width' => $custom_width, 'custom_height' => $custom_height, 'alignment' => $alignment, 'mobile_behavior' => $mobile_behavior, 'replace_existing' => $replace_existing, 'attachment_id' => $attachment_id, 'auto_select_library' => sanitize_key($raw['auto_select_library'] ?? 'no') === 'yes' ? 'yes' : 'no', 'prompt' => sanitize_textarea_field($raw['prompt'] ?? ''), 'style' => sanitize_textarea_field($raw['style'] ?? $defaults['style']), ]; } public static function resolve($raw) { $options = self::sanitize($raw, true); if (($options['action'] ?? '') !== 'site_default') { return $options; } $global = self::get(); $global['attachment_id'] = absint($options['attachment_id'] ?? 0); $global['prompt'] = sanitize_textarea_field($options['prompt'] ?? ''); $global['action'] = $global['source']; $global['size'] = $global['generation_size']; if (($global['source'] ?? '') === 'library' && empty($global['attachment_id'])) { $global['auto_select_library'] = 'yes'; } return $global; } public static function generation_sizes() { return ['1024x1024', '1536x1024', '1024x1536']; } public static function placement_values() { return ['featured', 'content_top', 'featured_and_content_top', 'after_first_paragraph', 'content_end']; } public static function display_sizes() { return ['thumbnail', 'medium', 'large', 'full', 'custom']; } public static function alignment_values() { return ['none', 'left', 'right', 'center', 'random']; } public static function wp_image_size($options) { $display = sanitize_key($options['display_size'] ?? 'large'); if ($display === 'custom') { $width = absint($options['custom_width'] ?? 800); if ($width <= 300) return 'thumbnail'; if ($width <= 768) return 'medium'; if ($width <= 1200) return 'large'; return 'full'; } return in_array($display, self::display_sizes(), true) ? $display : 'large'; } public static function alignment_class($options) { $alignment = sanitize_key($options['alignment'] ?? 'none'); if ($alignment === 'random') { $alignment = wp_rand(0, 1) ? 'left' : 'right'; } if ($alignment === 'left') return 'alignleft'; if ($alignment === 'right') return 'alignright'; if ($alignment === 'center') return 'aligncenter'; return ''; } public static function image_attrs($options) { $classes = ['aiwest-content-image']; $mobile = sanitize_key($options['mobile_behavior'] ?? 'full_width'); $classes[] = $mobile === 'full_width' ? 'aiwest-media-mobile-full' : 'aiwest-media-content-width'; $attrs = [ 'class' => implode(' ', $classes), 'loading' => 'lazy', ]; if (($options['display_size'] ?? '') === 'custom') { $width = absint($options['custom_width'] ?? 800); $height = absint($options['custom_height'] ?? 0); if ($width) { $style = 'max-width:' . $width . 'px;width:100%;height:auto;'; if ($height) { $style .= 'max-height:' . $height . 'px;object-fit:cover;'; } $attrs['style'] = $style; } } return $attrs; } public static function figure_class($options) { $size = sanitize_key($options['display_size'] ?? 'large'); $size_class = $size === 'custom' ? 'size-custom' : 'size-' . $size; $classes = ['wp-block-image', $size_class, 'aiwest-managed-media']; $source = sanitize_key($options['source'] ?? ($options['action'] ?? 'ai')); $classes[] = $source === 'library' ? 'aiwest-library-media' : 'aiwest-generated-media'; $align = self::alignment_class($options); if ($align) $classes[] = $align; return implode(' ', array_map('sanitize_html_class', $classes)); } }