plugin_name = $plugin_name; $this->version = $version; // Ajax calls // AJAX endpoints for image generation (authenticated users only) add_action( 'wp_ajax_allsi_generate_image', array(&$this, 'ALLSI_ajax_call') ); $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( FALSE ) ); $auto_image_settings = wp_parse_args( get_option( 'ALLSI_plugin_auto_image_settings' ), $this->ALLSI_default_options_auto_image_settings( FALSE ) ); $auto_image_enabled = ( ! empty( $auto_image_settings['enabled'] ) && 'enable' === $auto_image_settings['enabled'] ); // Enable save_post hook if ( isset( $main_settings['enable_save_post_hook'] ) && 'enable' == $main_settings['enable_save_post_hook'] && ! $auto_image_enabled ) { add_action( 'save_post', array(&$this, 'ALLSI_check_post_type'), 10, 3 ); } } /** * Retrieve the shared source manager and register built-in sources on demand. * * @return ALLSI_Source_Manager|null */ public function ALLSI_get_source_manager_instance() { if ( ! class_exists( 'ALLSI_Source_Manager' ) ) { return null; } if ( null === $this->source_manager ) { $this->source_manager = ALLSI_Source_Manager::instance(); } if ( false === $this->sources_registered ) { $this->ALLSI_register_builtin_sources(); $this->sources_registered = true; } return $this->source_manager; } /** * Register core sources shipped with the plugin. */ private function ALLSI_register_builtin_sources() { if ( ! $this->source_manager ) { return; } if ( class_exists( 'ALLSI_Source_Gemini' ) && ! $this->source_manager->has_source( 'gemini' ) ) { $this->source_manager->register_source( new ALLSI_Source_Gemini() ); } if ( class_exists( 'ALLSI_Source_Workers_AI' ) && ! $this->source_manager->has_source( 'workers_ai' ) ) { $this->source_manager->register_source( new ALLSI_Source_Workers_AI() ); } if ( class_exists( 'ALLSI_Source_Pexels' ) && ! $this->source_manager->has_source( 'pexels' ) ) { $this->source_manager->register_source( new ALLSI_Source_Pexels() ); } if ( class_exists( 'ALLSI_Source_Pixabay' ) && ! $this->source_manager->has_source( 'pixabay' ) ) { $this->source_manager->register_source( new ALLSI_Source_Pixabay() ); } if ( class_exists( 'ALLSI_Source_Flickr' ) && ! $this->source_manager->has_source( 'flickr' ) ) { $this->source_manager->register_source( new ALLSI_Source_Flickr() ); } if ( class_exists( 'ALLSI_Source_Giphy' ) && ! $this->source_manager->has_source( 'giphy' ) ) { $this->source_manager->register_source( new ALLSI_Source_Giphy() ); } if ( class_exists( 'ALLSI_Source_Stability' ) && ! $this->source_manager->has_source( 'stability' ) ) { $this->source_manager->register_source( new ALLSI_Source_Stability() ); } if ( class_exists( 'ALLSI_Source_Replicate' ) && ! $this->source_manager->has_source( 'replicate' ) ) { $this->source_manager->register_source( new ALLSI_Source_Replicate() ); } if ( class_exists( 'ALLSI_Source_Google_Image' ) && ! $this->source_manager->has_source( 'google_image' ) ) { $this->source_manager->register_source( new ALLSI_Source_Google_Image() ); } if ( class_exists( 'ALLSI_Source_Youtube' ) && ! $this->source_manager->has_source( 'youtube' ) ) { $this->source_manager->register_source( new ALLSI_Source_Youtube() ); } if ( class_exists( 'ALLSI_Source_Dallev1' ) && ! $this->source_manager->has_source( 'dallev1' ) ) { $this->source_manager->register_source( new ALLSI_Source_Dallev1() ); } if ( class_exists( 'ALLSI_Source_Unsplash' ) && ! $this->source_manager->has_source( 'unsplash' ) ) { $this->source_manager->register_source( new ALLSI_Source_Unsplash() ); } if ( class_exists( 'ALLSI_Source_Openverse' ) ) { if ( ! $this->source_manager->has_source( 'openverse' ) ) { $this->source_manager->register_source( new ALLSI_Source_Openverse( 'openverse' ) ); } if ( ! $this->source_manager->has_source( 'cc_search' ) ) { $this->source_manager->register_source( new ALLSI_Source_Openverse( 'cc_search' ) ); } } } /** * Ajax call for bulk generation * * @since 4.0.0 */ public function ALLSI_ajax_call() { // Security check: Verify nonce first before processing any input // phpcs:ignore WordPress.Security.NonceVerification.Missing -- This line is where nonce is retrieved for verification $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ''; if ( ! wp_verify_nonce( $nonce, 'ajax_nonce_All_Sources_Images' ) ) { wp_send_json_error( array( 'message' => __( 'Security check failed.', 'all-sources-images' ) ) ); } // Security check: Verify user capability if ( ! current_user_can( 'edit_posts' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'all-sources-images' ) ) ); } // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above with wp_verify_nonce // Check if button "Generate Automatically" is clicked $button_autogenerate = ( isset( $_POST['buttonAutoGenerate'] ) ? filter_var( wp_unslash( $_POST['buttonAutoGenerate'] ), FILTER_VALIDATE_BOOLEAN ) : false ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above // Convert the JSON-encoded post IDs into an array and sanitize them. $ids_json = isset( $_POST['ids_mpt_generation'] ) ? sanitize_text_field( wp_unslash( $_POST['ids_mpt_generation'] ) ) : '[]'; $post_ids = array_map( 'absint', json_decode( $ids_json ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above // Validate the presence of post IDs. if ( ! isset( $_POST['ids_mpt_generation'] ) ) { wp_send_json_error( array( 'message' => __( 'No posts selected.', 'all-sources-images' ) ) ); } // Exit if no post IDs are provided. // Count the number of posts for bulk processing. $count = count( $post_ids ); // Re-index post IDs starting from 1 for consistency. foreach ( $post_ids as $key => $val ) { $post_ids_with_keys[$key + 1] = $val; } // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above // Retrieve the current post index and ID from the AJAX request. $current_post_index = isset( $_POST['currentPostIndex'] ) ? absint( $_POST['currentPostIndex'] ) : 0; $current_post_id = $post_ids_with_keys[$current_post_index]; // Load plugin settings for image generation (with defaults). $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( true ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above // Check if forceRewrite is set from AJAX request (user confirmed replacement) $force_rewrite = isset( $_POST['forceRewrite'] ) && filter_var( wp_unslash( $_POST['forceRewrite'] ), FILTER_VALIDATE_BOOLEAN ); // Check if the 'rewrite featured image' option is enabled or forceRewrite is set. if ( $force_rewrite || ( isset( $main_settings['rewrite_featured'] ) && $main_settings['rewrite_featured'] == true ) ) { $rewrite_featured = true; } else { $rewrite_featured = false; } $int_blockIndex = isset( $_POST['blockIndex'] ) ? absint( wp_unslash( $_POST['blockIndex'] ) ) : 0; $img_blocks = isset( $main_settings['image_block'] ) && is_array( $main_settings['image_block'] ) ? $main_settings['image_block'] : array( 1 => array( 'image_location' => 'featured', 'based_on' => 'title', 'translation_EN' => 'true', 'title_selection' => 'full_title', 'selected_image' => 'first_result', ), ); $counter_blocks = count( $img_blocks ); if ( 0 === $counter_blocks ) { $img_blocks = array( 1 => array( 'image_location' => 'featured', 'based_on' => 'title', 'translation_EN' => 'true', 'title_selection' => 'full_title', 'selected_image' => 'first_result', ), ); $counter_blocks = 1; } if ( $int_blockIndex >= $counter_blocks ) { $int_blockIndex = 0; } $speed = '500'; // Default speed for image generation. $current_image_index = $int_blockIndex; // Current image block index. $counter_img = $counter_blocks; // Total number of image blocks. $keys = array_keys( $img_blocks ); $img_block = $img_blocks[$keys[$current_image_index]]; // Current image block data. // display all infos under $img_block // Determine image location (featured or content). $image_location = ( !empty( $img_block['image_location'] ) ? $img_block['image_location'] : 'featured' ); $generation_status = 'pending'; $ALLSI_return = null; $image_generation_result = null; // Handle generation of the featured image. if ( has_post_thumbnail( $current_post_id ) && $rewrite_featured == false && $image_location == 'featured' ) { $generation_status = 'already-done'; // Image already exists and rewriting is not needed. } elseif ( (!has_post_thumbnail( $current_post_id ) || $rewrite_featured == true || $image_location != 'featured') && $current_post_id != 0 ) { // Generate featured image if not present or if rewriting is enabled. $image_generation_result = $this->ALLSI_create_thumb( $current_post_id, // $id '0', // $check_value_enable '0', // $check_post_type '0', // $check_category $rewrite_featured, // $rewrite_featured false, // $get_only_thumb null, // $extracted_search_term null, // $api_chosen null, // $key_img_block null, // $avoid_revision null, // $include_datas $button_autogenerate // $button_autogenerate ); if ( is_array( $image_generation_result ) ) { $ALLSI_return = isset( $image_generation_result['id'] ) ? $image_generation_result['id'] : null; $generation_status = $ALLSI_return ? 'successful' : 'error'; } else { $ALLSI_return = $image_generation_result; $generation_status = $ALLSI_return ? 'successful' : 'error'; } } else { $generation_status = 'error'; } $thumbnail_url = ''; if ( ($generation_status == 'already-done' || $generation_status == 'successful') && !empty( $ALLSI_return ) ) { // Display the newly generated image. $new_image = wp_get_attachment_image_src( $ALLSI_return, array(70, 70) ); $thumbnail_preview_html = ''; $datas['thumbnail_id'] = $ALLSI_return; $datas['postimagediv'] = _wp_post_thumbnail_html( $ALLSI_return, $current_post_id ); } elseif ( $generation_status == 'already-done' && "featured" === $image_location ) { // Display existing featured image. $thumbnail_preview_html = '' . get_the_post_thumbnail( $current_post_id, array('70', '70') ) . ''; } else { // Display a placeholder image if generation fails. $thumbnail_preview_html = ''; } // Prepare data for the next image block iteration. $current_image_index++; $datas['id'] = $current_post_id; $datas['status'] = $generation_status; $datas['img'] = $thumbnail_url; $datas['fimg'] = $thumbnail_preview_html; $datas['speed'] = $speed; $datas['blockIndex'] = $current_image_index; if ( is_array( $image_generation_result ) ) { $datas['keyword'] = ( isset( $image_generation_result['keyword'] ) ? $image_generation_result['keyword'] : '' ); $datas['img_resolution'] = ( isset( $image_generation_result['img_resolution'] ) ? $image_generation_result['img_resolution'] : '' ); $datas['img_size'] = ( isset( $image_generation_result['img_size'] ) ? $image_generation_result['img_size'] : '' ); $datas['api_chosen'] = ( isset( $image_generation_result['api_chosen'] ) ? $image_generation_result['api_chosen'] : '' ); } // If more image blocks are remaining, continue processing. if ( $current_image_index < $counter_img ) { $datas['nextPost'] = true; wp_send_json_success( $datas ); // Send successful response for next iteration. } else { $datas['nextPost'] = false; // Send final response or error if data is incomplete. if ( !empty( $datas['id'] ) ) { wp_send_json_success( $datas ); } else { wp_send_json_error( $datas ); } } } public function ALLSI_check_post_type( $ID, $post, $update ) { // Checks whether the capacity has already been checked for this session if ( get_option( 'ALLSI_hook_checked' ) ) { // Deletes the option immediately after execution delete_option( 'ALLSI_hook_checked' ); return; // Exits the function if it has already been executed } // Set capacity as verified to avoid additional calls update_option( 'ALLSI_hook_checked', true ); $transient_key = 'ALLSI_wp_insert_processing_post_' . $ID; if ( wp_is_post_revision( $ID ) || wp_is_post_autosave( $ID ) ) { return; } if ( get_transient( $transient_key ) ) { return; // This post is already being processed } else { // Defines the transient to indicate that the post is being processed set_transient( $transient_key, true, 120 ); // Expires after 2 minutes } global $pagenow; // Avoid not selected post types $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( FALSE ) ); if ( empty( $main_settings['choosed_save_post_post_type'] ) ) { $choosed_post_type = $this->ALLSI_default_posts_types(); $main_settings['choosed_save_post_post_type'] = $choosed_post_type["choosed_post_type"]; } if ( !in_array( get_post_type( $ID ), $main_settings['choosed_save_post_post_type'] ) ) { return false; } //$active_posts_types = wp_parse_args( get_option( 'ALLSI_plugin_posts_settings' ), $this->ALLSI_default_options_posts_settings( FALSE ) ); $active_posts_types = $this->ALLSI_default_posts_types(); // Avoid generation when click "Add New" if ( ($pagenow == 'index.php' || $pagenow == 'post.php') && in_array( get_post_type( $ID ), $active_posts_types['choosed_post_type'] ) ) { $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( true ) ); if ( isset( $main_settings['rewrite_featured'] ) && $main_settings['rewrite_featured'] == true ) { $rewrite_featured = true; } else { $rewrite_featured = false; } $img_blocks = isset( $main_settings['image_block'] ) && is_array( $main_settings['image_block'] ) ? $main_settings['image_block'] : $this->ALLSI_default_options_main_settings( true )['image_block']; foreach ( $img_blocks as $key_img_block => $img_block ) { $this->ALLSI_create_thumb( $ID, '0', '1', '0', $rewrite_featured ); } } } /** * based on the provided title and filename. It first cleans the filename * by removing numbers and extension, then performs a search in the * WordPress database. * * @since 6.0.5 * @param string $title The title of the image to search for * @param string $filename The filename of the image to search for * * @return int|false Returns the attachment ID if found, false otherwise * * @access private */ private function ALLSI_check_existing_image( $title, $filename ) { // Clean the base filename (remove extension and numbers) $base_filename = preg_replace( '/[0-9]+\\./', '.', $filename ); $base_filename = pathinfo( $base_filename, PATHINFO_FILENAME ); // Search in media library $args = array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'posts_per_page' => 1, 'meta_query' => array(array( 'key' => '_wp_attached_file', 'value' => $base_filename, 'compare' => 'LIKE', )), ); $query = new WP_Query($args); if ( $query->have_posts() ) { // If image already exists, return its ID return $query->posts[0]->ID; } return false; } /** * Retrieve Image from Database, save it into Media Library, and attach it to the post as featured image * * @since 4.0.0 */ public function ALLSI_create_thumb( $id, $check_value_enable = 0, $check_post_type = 1, $check_category = 1, $rewrite_featured = 0, $get_only_thumb = false, $extracted_search_term = null, $api_chosen = null, $key_img_block = null, $avoid_revision = null, $include_datas = null, $button_autogenerate = false, $additional_context = array() ) { ALLSI_log( array( 'id' => $id, 'get_only_thumb' => $get_only_thumb, 'api_chosen' => $api_chosen, 'extracted_search_term' => $extracted_search_term ), 'CREATE_THUMB_START' ); // Launch logs $log = $this->ALLSI_monolog_call(); $log->info( 'New generation starting', array( 'post' => $id, ) ); //Avoid revision post type if ( 'revision' == get_post_type( $id ) && true !== $avoid_revision ) { ALLSI_log( 'Post is revision, avoiding', 'CREATE_THUMB_SKIP' ); $log->error( 'This post is a revision. Avoided.', array( 'post' => $id, ) ); return false; } // Settings $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( true ) ); // For Gutenberg block (get_only_thumb), we don't need image_block config if ( TRUE == $get_only_thumb ) { // Create a minimal img_block array for Gutenberg / Abilities API $img_block = array( 'api_chosen' => $api_chosen, 'based_on' => 'title', // Not used in get_only_thumb mode 'selected_image' => isset( $additional_context['selected_image'] ) ? $additional_context['selected_image'] : 'random_result', ); } else { // one shot generation - use saved configuration if ( null == $key_img_block ) { if ( !isset($main_settings['image_block']) || empty($main_settings['image_block']) ) { ALLSI_log( 'No image_block configuration found', 'CREATE_THUMB_ERROR' ); return false; } $key_img_block = array_key_first( $main_settings['image_block'] ); } $img_block = $main_settings['image_block'][$key_img_block]; if ( !isset( $img_block ) ) { return false; } // Merge with default block settings to ensure all fields have defaults $default_block = array( 'image_location' => 'featured', 'based_on' => 'title', 'translation_EN' => 'true', // Default to ON for translation 'title_selection' => 'full_title', 'selected_image' => 'first_result', ); $img_block = wp_parse_args( $img_block, $default_block ); // Ensure api_chosen is set from banks settings if not in img_block if ( !isset( $img_block['api_chosen'] ) || empty( $img_block['api_chosen'] ) ) { $banks_settings = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( true ) ); $img_block['api_chosen'] = isset( $banks_settings['api_chosen_auto'] ) ? $banks_settings['api_chosen_auto'] : array( 'openverse' ); } } // Skip most validations for Gutenberg block mode (get_only_thumb) if ( TRUE !== $get_only_thumb ) { // Image location $image_location = ( !empty( $img_block['image_location'] ) ? $img_block['image_location'] : 'featured' ); if ( "featured" !== $image_location ) { // Check if image generation into content is already done $content_post = get_post( $id ); /*$image_generated = strpos( $content_post->post_content, 'mpt-img' ) ? true : false; if( $image_generated ) { return false; }*/ } // Check if thumbnail already exists if ( has_post_thumbnail( $id ) && $rewrite_featured == false && "featured" === $image_location ) { ALLSI_log( 'Featured image already exists', 'CREATE_THUMB_SKIP' ); $log->error( 'Featured image already exists', array( 'post' => $id, ) ); return false; } /* Action 'save_post' triggered when deleting posts. Check if post not trashed */ if ( 'trash' == get_post_status( $id ) ) { ALLSI_log( 'Post is trashed', 'CREATE_THUMB_SKIP' ); $log->error( 'Post is in the trash', array( 'post' => $id, ) ); return false; } if ( ! current_user_can( 'ALLSI_manage' ) && ! wp_doing_cron() && ! class_exists( 'Main_WPeMatico' ) && ! class_exists( 'FeedWordPress' ) && ! class_exists( 'rssPostImporter' ) && ! class_exists( 'CyberSyn_Syndicator' ) && ! class_exists( 'wp_automatic' ) ) { ALLSI_log( 'User lacks permissions', 'CREATE_THUMB_SKIP' ); $log->error( 'The user does not have sufficient rights', array( 'post' => $id, ) ); return false; } // Choosed Post types $post_types_default = $this->ALLSI_default_posts_types(); $post_type_availables = $post_types_default['choosed_post_type']; $categories_availables = $post_types_default['choosed_categories']; /* $post_type_availables = ( ! empty( $posts_settings['choosed_post_type'] ) ) ? $posts_settings['choosed_post_type'] : ''; // Choosed Categories $categories_availables = ( ! empty( $posts_settings['choosed_categories'] ) ) ? $posts_settings['choosed_categories'] : '';*/ if ( !empty( $post_type_availables ) && $check_post_type ) { if ( !in_array( get_post_type( $id ), $post_type_availables ) ) { ALLSI_log( 'Post type not in allowed list', 'CREATE_THUMB_SKIP' ); $log->error( 'The post is not in selected post types', array( 'post' => $id, ) ); return false; } } // Check if category match and is a post if ( !empty( $categories_availables ) && $check_category && 'post' == get_post_type( $id ) ) { if ( !in_category( $categories_availables, $id ) ) { ALLSI_log( 'Post category not in allowed list', 'CREATE_THUMB_SKIP' ); $log->error( 'The post is not in selected categories', array( 'post' => $id, ) ); return false; } } } $options = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( TRUE ) ); $options_banks = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( TRUE ) ); $options_cron = wp_parse_args( get_option( 'ALLSI_plugin_cron_settings' ), $this->ALLSI_default_options_cron_settings( TRUE ) ); $options = array_merge( $options, $options_banks, $options_cron ); if ( isset( $api_chosen ) ) { $options['api_chosen'] = $api_chosen; $img_block['api_chosen'] = $api_chosen; } else { $options['api_chosen'] = $img_block['api_chosen']; } $executeElseBlock = true; $postcategories = get_the_category( $id ); if ( $executeElseBlock ) { if ( TRUE == $get_only_thumb ) { $search = $extracted_search_term; } else { // Handle all based_on options $based_on = isset( $img_block['based_on'] ) ? $img_block['based_on'] : 'title'; switch ( $based_on ) { case 'text_analyser': case 'text_analyser_previous_paragraph': case 'text_analyser_next_paragraph': $content = get_the_content( '', false, $id ); $content = str_replace( " ", ' ', $content ); // For paragraph-specific analysis, extract relevant paragraph if ( $based_on === 'text_analyser_previous_paragraph' || $based_on === 'text_analyser_next_paragraph' ) { $paragraphs = preg_split( '/\n\s*\n/', wp_strip_all_tags( $content ) ); $paragraphs = array_filter( array_map( 'trim', $paragraphs ) ); $paragraphs = array_values( $paragraphs ); // Get image position from settings (default to first paragraph) $image_position = isset( $img_block['image_location'] ) ? $img_block['image_location'] : 'featured'; $para_index = 0; if ( preg_match( '/after_paragraph_(\d+)/', $image_position, $matches ) ) { $para_index = intval( $matches[1] ); } if ( $based_on === 'text_analyser_previous_paragraph' ) { $content = isset( $paragraphs[ $para_index - 1 ] ) ? $paragraphs[ $para_index - 1 ] : ( isset( $paragraphs[0] ) ? $paragraphs[0] : '' ); } else { $content = isset( $paragraphs[ $para_index ] ) ? $paragraphs[ $para_index ] : ( isset( $paragraphs[0] ) ? $paragraphs[0] : '' ); } } $selected_lang = isset( $img_block['text_analyser_lang'] ) ? $img_block['text_analyser_lang'] : 'en'; $search = $this->get_extracted_term( $content, $selected_lang ); $log->info( 'Extracted search term from text analysis', array( 'post' => $id, 'based_on' => $based_on, 'search term' => $search, ) ); break; case 'tags': $tags = wp_get_post_tags( $id ); if ( ! empty( $tags ) ) { $tags_option = isset( $img_block['tags'] ) ? $img_block['tags'] : 'first_tag'; switch ( $tags_option ) { case 'last_tag': $tag = end( $tags ); break; case 'random_tag': $tag = $tags[ array_rand( $tags ) ]; break; case 'first_tag': default: $tag = reset( $tags ); break; } $search = $tag->name; $log->info( 'Search term from tag', array( 'post' => $id, 'tag_option' => $tags_option, 'search term' => $search, ) ); } else { // Fallback to title if no tags $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'No tags found, using title as fallback', array( 'post' => $id ) ); } break; case 'categories': $categories = get_the_category( $id ); if ( ! empty( $categories ) ) { $cat_option = isset( $img_block['categories'] ) ? $img_block['categories'] : 'first_category'; $cat_level = isset( $img_block['categories_level'] ) ? $img_block['categories_level'] : 'child'; // Select category based on option switch ( $cat_option ) { case 'last_category': $category = end( $categories ); break; case 'random_category': $category = $categories[ array_rand( $categories ) ]; break; case 'first_category': default: $category = reset( $categories ); break; } // Adjust for hierarchy level if ( $cat_level === 'parent' && $category->parent > 0 ) { $parent = get_category( $category->parent ); if ( $parent && ! is_wp_error( $parent ) ) { $category = $parent; } } elseif ( $cat_level === 'grandparent' ) { $ancestors = get_ancestors( $category->term_id, 'category' ); if ( ! empty( $ancestors ) ) { $top_ancestor = end( $ancestors ); $grandparent = get_category( $top_ancestor ); if ( $grandparent && ! is_wp_error( $grandparent ) ) { $category = $grandparent; } } } $search = $category->name; $log->info( 'Search term from category', array( 'post' => $id, 'cat_option' => $cat_option, 'cat_level' => $cat_level, 'search term' => $search, ) ); } else { // Fallback to title if no categories $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'No categories found, using title as fallback', array( 'post' => $id ) ); } break; case 'custom_field': $field_name = isset( $img_block['custom_field'] ) ? $img_block['custom_field'] : ''; if ( ! empty( $field_name ) ) { $field_value = get_post_meta( $id, $field_name, true ); if ( ! empty( $field_value ) ) { $search = $field_value; $log->info( 'Search term from custom field', array( 'post' => $id, 'field_name' => $field_name, 'search term' => $search, ) ); } else { // Fallback to title $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'Custom field empty, using title as fallback', array( 'post' => $id, 'field' => $field_name ) ); } } else { $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'Custom field name not specified, using title', array( 'post' => $id ) ); } break; case 'custom_request': $template = isset( $img_block['custom_request'] ) ? $img_block['custom_request'] : '%%Title%%'; $search = $template; // Replace %%Title%% $post_title = get_post_field( 'post_title', $id, 'raw' ); $search = str_replace( '%%Title%%', $post_title, $search ); // Replace %%Category%% $post_categories = get_the_category( $id ); $category_name = ! empty( $post_categories ) ? $post_categories[0]->name : ''; $search = str_replace( '%%Category%%', $category_name, $search ); // Replace %%Tag%% $post_tags = wp_get_post_tags( $id ); $tag_name = ! empty( $post_tags ) ? $post_tags[0]->name : ''; $search = str_replace( '%%Tag%%', $tag_name, $search ); // Replace %%Taxonomy%% (custom taxonomies) $taxonomies = get_object_taxonomies( get_post_type( $id ), 'names' ); $taxonomy_terms = array(); foreach ( $taxonomies as $taxonomy ) { if ( $taxonomy !== 'category' && $taxonomy !== 'post_tag' ) { $terms = wp_get_post_terms( $id, $taxonomy ); if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) { $taxonomy_terms[] = $terms[0]->name; } } } $taxonomy_value = ! empty( $taxonomy_terms ) ? implode( ' ', $taxonomy_terms ) : ''; $search = str_replace( '%%Taxonomy%%', $taxonomy_value, $search ); // Clean up multiple spaces $search = preg_replace( '/\s+/', ' ', trim( $search ) ); $log->info( 'Search term from custom request template', array( 'post' => $id, 'template' => $template, 'search term' => $search, ) ); break; case 'openai_extractor': $api_key = isset( $img_block['openai_extractor_apikey'] ) ? $img_block['openai_extractor_apikey'] : ''; $num_keywords = isset( $img_block['openai_number_of_keywords'] ) ? $img_block['openai_number_of_keywords'] : '2'; if ( ! empty( $api_key ) ) { $post_title = get_post_field( 'post_title', $id, 'raw' ); $post_content = get_the_content( '', false, $id ); $post_content = wp_strip_all_tags( $post_content ); $post_content = substr( $post_content, 0, 1000 ); // Limit content length $extracted = $this->ALLSI_openai_extract_keywords( $api_key, $post_title, $post_content, $num_keywords ); if ( $extracted ) { $search = $extracted; $log->info( 'Search term from OpenAI keyword extraction', array( 'post' => $id, 'search term' => $search, ) ); } else { // Fallback to title $search = $post_title; $log->info( 'OpenAI extraction failed, using title as fallback', array( 'post' => $id ) ); } } else { $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'OpenAI API key not provided, using title', array( 'post' => $id ) ); } break; case 'ai_image_prompt': $api_key = isset( $img_block['ai_prompt_apikey'] ) ? $img_block['ai_prompt_apikey'] : ''; $style = isset( $img_block['ai_prompt_style'] ) ? $img_block['ai_prompt_style'] : 'photorealistic'; $custom_instructions = isset( $img_block['ai_prompt_custom_instructions'] ) ? $img_block['ai_prompt_custom_instructions'] : ''; if ( ! empty( $api_key ) ) { $post_title = get_post_field( 'post_title', $id, 'raw' ); $post_content = get_the_content( '', false, $id ); $post_content = wp_strip_all_tags( $post_content ); $post_content = substr( $post_content, 0, 1500 ); // Limit content length $generated_prompt = $this->ALLSI_openai_generate_image_prompt( $api_key, $post_title, $post_content, $style, $custom_instructions ); if ( $generated_prompt ) { $search = $generated_prompt; $log->info( 'AI-generated image prompt', array( 'post' => $id, 'style' => $style, 'search term' => $search, ) ); } else { // Fallback to title $search = $post_title; $log->info( 'AI prompt generation failed, using title as fallback', array( 'post' => $id ) ); } } else { $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'AI prompt API key not provided, using title', array( 'post' => $id ) ); } break; case 'title': default: $search = get_post_field( 'post_title', $id, 'raw' ); $log->info( 'Using post title as search term', array( 'post' => $id, 'search term' => $search, ) ); break; } } } if ( isset( $img_block['title_selection'] ) && $img_block['title_selection'] == 'cut_title' && isset( $img_block['title_length'] ) ) { $length_title = (int) $img_block['title_length'] - 1; $search = preg_replace( '/((\\w+\\W*){' . $length_title . '}(\\w+))(.*)/', '${1}', $search ); } // Translate search keywords to English if enabled (defaults to ON if not set) $do_translation = ! isset( $img_block['translation_EN'] ) || $img_block['translation_EN'] === 'true'; ALLSI_log( array( 'post_id' => $id, 'translation_EN_value' => isset( $img_block['translation_EN'] ) ? $img_block['translation_EN'] : 'NOT SET (defaulting to true)', 'do_translation' => $do_translation ? 'YES' : 'NO', 'original_search' => $search, ), 'TRANSLATION_CHECK' ); if ( $do_translation ) { // Use configured source language or auto-detect from WordPress $block_settings = wp_parse_args( get_option( 'ALLSI_plugin_block_settings' ), array( 'source_lang' => '' ) ); if ( ! empty( $block_settings['source_lang'] ) ) { $source_lang = $block_settings['source_lang']; } else { $wp_lang = get_bloginfo('language'); $source_lang = substr( $wp_lang, 0, 2 ); } ALLSI_log( array( 'post_id' => $id, 'source_lang' => $source_lang, 'target_lang' => 'en', 'will_translate' => $source_lang !== 'en' ? 'YES' : 'NO (already English)', ), 'TRANSLATION_LANG_DETECT' ); if ( $source_lang !== 'en' ) { $translated_search = $this->ALLSI_translate_text( $search, $source_lang, 'en' ); ALLSI_log( array( 'post_id' => $id, 'original' => $search, 'translated' => $translated_search !== false ? $translated_search : 'TRANSLATION FAILED', 'success' => $translated_search !== false ? 'YES' : 'NO', ), 'TRANSLATION_RESULT' ); if ( $translated_search !== false ) { $search = $translated_search; $log->info( 'Search term translated to English', array( 'post' => $id, 'search' => $search, ) ); } } } if ( TRUE == $get_only_thumb ) { $source_manager = $this->ALLSI_get_source_manager_instance(); if ( $source_manager && $source_manager->has_source( $img_block['api_chosen'] ) ) { $source = $source_manager->get_source( $img_block['api_chosen'] ); $result = $source->generate( array( 'img_block' => $img_block, 'options' => $options, 'search' => $search, 'log' => $log, 'post_id' => $id, 'get_only_thumb' => true, 'selected_image' => $img_block['selected_image'], 'proxy_args' => $this->ALLSI_get_proxy_args(), 'generation' => $this, 'page' => isset( $additional_context['page'] ) ? max( 1, intval( $additional_context['page'] ) ) : 1, ) ); if ( is_wp_error( $result ) ) { $log->error( 'Source generation failed', array( 'post' => $id, 'error' => $result->get_error_message(), 'error_code' => $result->get_error_code(), 'error_data' => $result->get_error_data(), ) ); ALLSI_log( array( 'post' => $id, 'bank' => $img_block['api_chosen'], 'message' => $result->get_error_message(), 'code' => $result->get_error_code(), 'data' => $result->get_error_data(), ), 'GUTENBERG_BLOCK_SOURCE_ERROR' ); return false; } return $result; } /* SET ALL PARAMETERS */ $array_parameters = $this->ALLSI_Get_Parameters( $img_block, $options, $search ); ALLSI_log( array( 'array_parameters' => $array_parameters, 'has_url' => isset($array_parameters['url']) ), 'CREATE_THUMB_PARAMS' ); $api_url = $array_parameters['url']; unset($array_parameters['url']); if ( !isset( $api_url ) ) { ALLSI_log( 'API URL not provided for bank: ' . $img_block['api_chosen'], 'CREATE_THUMB_ERROR' ); $log->error( 'API URL not provided', array( 'post' => $id, ) ); return false; } $result_body = $this->ALLSI_Generate( $img_block['api_chosen'], $api_url, $array_parameters, $img_block['selected_image'], $get_only_thumb, $search ); return $result_body; } // Check if button "Generate Automatically" is clicked (but NOT for bulk cron processing) // When $button_autogenerate is 'bulk', we use the specific api_chosen from the image block if ( true === $button_autogenerate && is_array( $options_banks['api_chosen_auto'] ) ) { $log->info( 'Button "Generate Automatically" clicked', array( 'post' => $id, ) ); $last_bank_element = end( $options_banks['api_chosen_auto'] ); $proxy_args = $this->ALLSI_get_proxy_args(); foreach ( $options_banks['api_chosen_auto'] as $bank ) { // Reset options according new image bank $options['api_chosen'] = $bank; $source_manager = $this->ALLSI_get_source_manager_instance(); if ( $source_manager && $source_manager->has_source( $bank ) ) { $context_block = $img_block; $context_block['api_chosen'] = $bank; $source = $source_manager->get_source( $bank ); $result = $source->generate( array( 'img_block' => $context_block, 'options' => $options, 'search' => $search, 'log' => $log, 'post_id' => $id, 'get_only_thumb' => false, 'selected_image' => $context_block['selected_image'], 'proxy_args' => $proxy_args, 'generation' => $this, ) ); if ( is_wp_error( $result ) ) { $log->info( 'No results with ' . $bank, array( 'post' => $id, 'error' => $result->get_error_message(), ) ); if ( $bank === $last_bank_element ) { $log->info( 'No image found with all banks selected', array( 'post' => $id, ) ); return false; } continue; } $url_results = $result['url_results']; $file_media = $result['file_media']; $alt_img = isset( $result['alt_img'] ) ? $result['alt_img'] : ''; $caption_img = isset( $result['caption_img'] ) ? $result['caption_img'] : ''; if ( !isset( $url_results ) || !isset( $file_media ) ) { $log->info( 'No results with ' . $bank, array( 'post' => $id, ) ); // Return false with no results with each image bank if ( $bank === $last_bank_element ) { $log->info( 'No image found with all banks selected', array( 'post' => $id, ) ); return false; } } else { // OK break; } } } } else { // Log the search term before processing ALLSI_log( array( 'post_id' => $id, 'api_chosen' => $img_block['api_chosen'], 'search_term' => $search, 'based_on' => isset( $img_block['based_on'] ) ? $img_block['based_on'] : 'title', 'translation_EN' => isset( $img_block['translation_EN'] ) ? $img_block['translation_EN'] : 'not set', ), 'GENERATION_SEARCH_TERM' ); // Process the main image block $result = $this->ALLSI_Process_Image_Block( $img_block, $options, $search, $log, $id ); // If the first API call fails, try the second image bank if ( $result === false && isset( $img_block['api_chosen_2'] ) && $img_block['api_chosen_2'] !== 'none' ) { $log->info( 'Second image bank used', array( 'post' => $id, ) ); $img_block['api_chosen'] = $img_block['api_chosen_2']; $result = $this->ALLSI_Process_Image_Block( $img_block, $options, $search, $log, $id ); } // If both API calls fail, return false if ( $result === false ) { return false; } // Log the image result ALLSI_log( array( 'post_id' => $id, 'api_chosen' => $img_block['api_chosen'], 'image_url' => isset( $result['url_results'] ) ? $result['url_results'] : 'N/A', 'file_name' => isset( $result['file_media']['headers']['content-disposition'] ) ? $result['file_media']['headers']['content-disposition'] : 'N/A', ), 'GENERATION_IMAGE_RESULT' ); // Extract results and continue processing extract( $result ); } $path_parts = pathinfo( $url_results ); $filename = $path_parts['basename']; $wp_upload_dir = wp_upload_dir(); /* Get the good file extension */ $filetype = array( 'image/png', 'image/jpeg', 'image/gif', 'image/bmp', 'image/vnd.microsoft.icon', 'image/tiff', 'image/svg+xml', 'image/svg+xml', 'image/webp' ); $extensions = array( 'png', 'jpg', 'gif', 'bmp', 'ico', 'tif', 'svg', 'svgz', 'webp' ); if ( isset( $file_media['headers']['content-type'] ) ) { $imgextension = str_replace( $filetype, $extensions, $file_media['headers']['content-type'], $count_extension ); /* Default type if not found : jpg */ if ( (int) $count_extension == 0 ) { $imgextension = 'jpg'; } } else { $imgextension = $path_parts['extension']; } $keywords_search = $search; $log->info( 'Search term', array( 'post' => $id, 'Search term' => $keywords_search, ) ); /* Image filename : title extension */ $search = str_replace( '%', '', sanitize_title( $search ) ); // Remove % for non-latin characters // Check if the 'resuse image' option is enabled. if ( isset( $main_settings['image_reuse'] ) && $main_settings['image_reuse'] == true ) { // Check if image file already exist if option is set $proposed_filename = sanitize_title( $search ); $existing_image_id = $this->ALLSI_check_existing_image( get_the_title( $id ), $proposed_filename ); if ( $existing_image_id ) { // Use the existing image instead of downloading a new one $log->info( 'Featured image with existing image (option set)', array( 'post' => $id, 'image' => $existing_image_id, ) ); set_post_thumbnail( $id, $existing_image_id ); do_action( 'ALLSI_after_create_thumb', $id, $existing_image_id ); return $existing_image_id; } } if ( $options['image_filename'] == 'date' ) { $current_time = current_time( 'Y-m-d' ); $filename = wp_unique_filename( $wp_upload_dir['path'], $current_time . '.' . $imgextension ); } elseif ( $options['image_filename'] == 'random' ) { $filename_rand = wp_rand( 1, 999999 ); $filename = wp_unique_filename( $wp_upload_dir['path'], $filename_rand . '.' . $imgextension ); } else { $filename = wp_unique_filename( $wp_upload_dir['path'], $search . '.' . $imgextension ); } $folder = $wp_upload_dir['path'] . '/' . $filename; if ( $file_media['response']['code'] != '200' || empty( $file_media['body'] ) ) { $log->error( 'Problem with scrapping', array( 'post' => $id, ) ); return false; } if ( $file_media['body'] ) { /* Upload the file to wordpress directory */ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Writing image data to wp_upload_dir path. $file_upload = file_put_contents( $folder, $file_media['body'] ); /* Convert png to jpeg for dalle */ $png_jpg = ( !empty( $options['dallev1']['convert_jpg'] ) ? $options['dallev1']['convert_jpg'] : '' ); //if( ( true == $png_jpg ) && ( 'dallev1' == $options['api_chosen'] ) ) { if ( true == $png_jpg && 'dallev1' == $img_block['api_chosen'] ) { $image = imagecreatefrompng( $folder ); // Remove old png file wp_delete_file( $folder ); $folder = str_replace( ".png", ".jpg", $folder ); $filename = str_replace( ".png", ".jpg", $filename ); imagejpeg( $image, $folder, 90 ); imagedestroy( $image ); } if ( $file_upload ) { $wp_filetype = wp_check_filetype( basename( $filename ), null ); $wp_upload_dir = wp_upload_dir(); $attachment = array( 'guid' => $wp_upload_dir['url'] . '/' . urlencode( $filename ), 'post_mime_type' => $wp_filetype['type'], 'post_title' => $search, 'post_content' => '', 'post_status' => 'inherit', ); $attach_id = wp_insert_attachment( $attachment, $wp_upload_dir['path'] . '/' . urlencode( $filename ) ); // Add alt text for image update_post_meta( $attach_id, '_wp_attachment_image_alt', $alt_img ); // Add caption text for image if ( !empty( $caption_img ) ) { wp_update_post( array( 'ID' => $attach_id, 'post_excerpt' => $caption_img, ) ); } /* Allow integrations to react after attachment creation. */ $img_values = array( 'file' => $wp_upload_dir['path'] . '/' . urlencode( $filename ), 'url' => $wp_upload_dir['url'] . '/' . urlencode( $filename ), 'type' => $wp_filetype['type'], ); do_action( 'allsi_after_attachment_created', $attach_id, $img_values ); require_once ABSPATH . 'wp-admin/includes/image.php'; $attach_data = wp_generate_attachment_metadata( $attach_id, $wp_upload_dir['path'] . '/' . urlencode( $filename ) ); $update_attach_data = wp_update_attachment_metadata( $attach_id, $attach_data ); $executeElseBlock = true; $plugin_desactivated = false; $missing_field = false; // If a field plugin is disabled and should be used if ( true === $plugin_desactivated || true === $missing_field ) { return false; } if ( $executeElseBlock ) { if ( "custom" === $image_location ) { $tag = $img_block['image_custom_location_tag']; $placement = $img_block['image_custom_location_placement']; $position = $img_block['image_custom_location_position']; $image_size = $img_block['image_custom_image_size']; $content = $this->ALLSI_insert_content_image( $content_post->post_content, $attach_id, $tag, $placement, $position, $image_size ); } else { $log->info( 'Featured image added', array( 'post' => $id, 'image' => $attach_id, ) ); set_post_thumbnail( $id, $attach_id ); } } // Link the media to the post $media_link_uploaded_to = wp_update_post( array( 'ID' => $attach_id, 'post_parent' => $id, ), true ); if ( "custom" === $image_location ) { // Array of post category ids $arr_post_category = array(); foreach ( $postcategories as $postcategory ) { $arr_post_category[] = (int) $postcategory->cat_ID; } /* * Remove save_post Action to avoid infinite loop. * cf https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops * Use "remove_all_actions" instead of "remove_action". Otherwise the log file bug * remove_action( 'save_post', array( &$this, 'ALLSI_create_thumb' ) ); */ remove_all_actions( 'save_post' ); wp_insert_post( array( 'ID' => $id, 'post_content' => $content, 'post_category' => $arr_post_category, 'post_title' => $content_post->post_title, 'post_status' => $content_post->post_status, 'post_author' => $content_post->post_author, 'post_date' => $content_post->post_date, 'post_date_gmt' => $content_post->post_date_gmt, 'post_excerpt' => $content_post->post_excerpt, 'comment_status' => $content_post->comment_status, 'ping_status' => $content_post->ping_status, 'post_password' => $content_post->post_password, 'post_name' => $content_post->post_name, 'to_ping' => $content_post->to_ping, 'pinged' => $content_post->pinged, 'post_modified' => $content_post->post_modified, 'post_modified_gmt' => $content_post->post_modified_gmt, 'post_content_filtered' => $content_post->post_content_filtered, 'post_parent' => $content_post->post_parent, 'menu_order' => $content_post->menu_order, 'post_type' => $content_post->post_type, 'post_mime_type' => $content_post->post_mime_type, ) ); add_action( 'save_post', array(&$this, 'ALLSI_create_thumb') ); $log->info( 'Image added into the post', array( 'post' => $id, 'image' => $attach_id, ) ); } do_action( 'ALLSI_after_create_thumb', $id, $attach_id ); if ( true === $include_datas ) { return array( 'id' => $attach_id, 'keyword' => $keywords_search, 'img_resolution' => $attach_data['width'] . 'x' . $attach_data['height'] . 'px', 'img_size' => $this->ALLSI_get_image_size_in_bytes( $attach_id ), 'api_chosen' => $img_block['api_chosen'], ); } else { return $attach_id; } } } } /** * Generate an image and handle related errors * * @param array $img_block Image block settings * @param array $options Plugin options * @param string $search Search term * @param object $log Logger instance * @param int $id Post ID * @return array|false Returns generated image data or false on failure */ private function ALLSI_Process_Image_Block( $img_block, $options, $search, $log, $id ) { $source_manager = $this->ALLSI_get_source_manager_instance(); // Debug logging for source resolution $api_chosen = isset( $img_block['api_chosen'] ) ? $img_block['api_chosen'] : null; ALLSI_log( array( 'post_id' => $id, 'api_chosen' => $api_chosen, 'api_chosen_type' => gettype( $api_chosen ), 'source_manager_exists' => ( $source_manager !== null ), 'has_source' => ( $source_manager && is_string( $api_chosen ) ) ? $source_manager->has_source( $api_chosen ) : false, 'all_sources' => $source_manager ? array_keys( $source_manager->all() ) : array(), ), 'PROCESS_IMAGE_BLOCK_DEBUG' ); if ( $source_manager && $source_manager->has_source( $img_block['api_chosen'] ) ) { $source = $source_manager->get_source( $img_block['api_chosen'] ); $result = $source->generate( array( 'img_block' => $img_block, 'options' => $options, 'search' => $search, 'log' => $log, 'post_id' => $id, 'get_only_thumb' => false, 'selected_image' => $img_block['selected_image'], 'proxy_args' => $this->ALLSI_get_proxy_args(), 'generation' => $this, ) ); if ( is_wp_error( $result ) ) { $log->error( 'Source generation failed', array( 'post' => $id, 'error' => $result->get_error_message(), 'error_code' => $result->get_error_code(), 'error_data' => $result->get_error_data(), ) ); return false; } // Log the source result with image URL ALLSI_log( array( 'post_id' => $id, 'source' => $img_block['api_chosen'], 'search_term' => $search, 'image_url' => isset( $result['url_results'] ) ? $result['url_results'] : 'N/A', 'alt_img' => isset( $result['alt_img'] ) ? $result['alt_img'] : 'N/A', ), 'SOURCE_GENERATION_SUCCESS' ); return $result; } // Source manager did not find the source - falling back to legacy ALLSI_Get_Parameters ALLSI_log( array( 'post_id' => $id, 'api_chosen' => isset( $img_block['api_chosen'] ) ? $img_block['api_chosen'] : null, 'message' => 'Source not found in source_manager, falling back to ALLSI_Get_Parameters', ), 'PROCESS_IMAGE_BLOCK_FALLBACK' ); // Set all parameters $array_parameters = $this->ALLSI_Get_Parameters( $img_block, $options, $search ); ALLSI_log( array( 'post_id' => $id, 'api_chosen' => isset( $img_block['api_chosen'] ) ? $img_block['api_chosen'] : null, 'array_parameters' => $array_parameters, 'has_url' => isset( $array_parameters['url'] ), ), 'PROCESS_IMAGE_BLOCK_LEGACY_PARAMS' ); $api_url = ( isset( $array_parameters['url'] ) ? $array_parameters['url'] : null ); unset($array_parameters['url']); // Check if API URL is provided if ( !$api_url ) { $log->error( 'API URL not provided', array( 'post' => $id, ) ); return false; } // Get the image URL list( $url_results, $file_media, $alt_img, $caption_img ) = $this->ALLSI_Generate( $img_block['api_chosen'], $api_url, $array_parameters, $img_block['selected_image'], false, $search ); // Check if results are valid if ( !isset( $url_results ) || !isset( $file_media ) ) { $log->error( 'No results', array( 'post' => $id, ) ); return false; } // Return the generated image data return compact( 'url_results', 'file_media', 'alt_img', 'caption_img' ); } /** * Get Image size in ko * * @since 6.0.0 */ private function ALLSI_get_image_size_in_bytes( $attachment_id ) { // Full path of the image $image_path = get_attached_file( $attachment_id ); if ( $image_path && file_exists( $image_path ) ) { // File size in bytes $image_size = filesize( $image_path ); } // Convert to kilobytes $image_size_kb = round( $image_size / 1024, 2 ); return $image_size_kb . 'ko'; } /** * Insert an image before or after a specific Gutenberg block * * @since 5.2.0 */ private function ALLSI_insert_content_image( $content, $attach_id, $tag = 'p', $placement = 'after', $position = '1', $image_size = 'large' ) { // If content is plain text without HTML tags, apply wpautop first // This handles cases like WP All Import where content comes as plain text if ( ! preg_match('/<[^>]+>/', $content) || ( $tag == 'p' && stripos($content, 'ALLSI_is_using_classic_editor(); $match = false; $loop_count = 0; $max_loops = 2; // Prevent infinite loops // Variable to track if the image was inserted successfully // Loop until the image insertion is successful while ( !$match && $loop_count < $max_loops ) { $loop_count++; // Prepare the HTML block for the image depending on the editor type if ( $classic_editor ) { $match = true; // Set match to true since we'll insert the image for Classic Editor $image = wp_get_attachment_image( $attach_id, $image_size, false, array( 'class' => 'wp-image-' . $attach_id, ) ); $image_block = '

' . $image . '

'; } else { // Get image details for Gutenberg $image_src = wp_get_attachment_image_src( $attach_id, $image_size, false ); $alt_text = get_post_meta( $attach_id, '_wp_attachment_image_alt', true ); $image = '' . esc_attr( $alt_text ) . ''; // Include caption if enabled in settings $options = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( TRUE ) ); if ( isset( $options['enable_caption'] ) && 'enable' == $options['enable_caption'] ) { $caption_text = wp_get_attachment_caption( $attach_id ); $image .= '
' . esc_html( $caption_text ) . '
'; } // Wrap the image in a Gutenberg image block format $image_block = ''; $image_block .= '
' . $image . '
'; $image_block .= ''; } // Define the tag-specific search pattern if ( $classic_editor ) { // Patterns for Classic Editor content $start_pattern = '<' . $tag; $end_pattern = ''; $pattern = '/(' . preg_quote( $start_pattern, '/' ) . '.*?' . preg_quote( $end_pattern, '/' ) . ')/s'; $parts = preg_split( $pattern, $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); // Remove empty content $filtered_array = array_filter( $parts, function ( $value ) { return trim( $value ) !== ''; } ); // Re-indexing of table keys if necessary $parts = array_values( $filtered_array ); // Restart the loop if can not find paragraphs if ( 'p' == $tag && count( $parts ) < 2 && $loop_count == 1 ) { //Apply wpautop() for next loop $content = wpautop( $content ); $match = false; continue; } elseif ( 'p' == $tag && count( $parts ) < 2 ) { // If still no paragraphs after wpautop, insert at beginning of content $new_content = $image_block . $content; return $new_content; } } else { // Patterns for Gutenberg Editor, ensuring separate blocks if ( $tag == 'p' ) { $start_pattern = ''; } elseif ( $tag == 'a' ) { $start_pattern = ''; $end_pattern = ''; } else { $start_pattern = ''; } $pattern = '/(' . preg_quote( $start_pattern, '/' ) . '.*?' . $end_pattern . ')/s'; $parts = preg_split( $pattern, $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); } // Initialize variables for constructing the new content $new_content = ''; $counter = 0; $total_tags = substr_count( $content, $start_pattern ); // Loop through each part to build the new content with the image block inserted foreach ( $parts as $part ) { // Check if part contains the target tag $contains_tag = preg_match( $pattern, $part ); // Insert image before tag if 'before' placement is specified if ( $placement == 'before' && $contains_tag ) { $counter++; if ( $position == 'last' && $counter == $total_tags || $counter == $position ) { if ( $classic_editor ) { $new_content .= '

' . $image_block . '

'; } else { $new_content .= $image_block; } $match = true; } } // Add the current part to new content $new_content .= $part; // Insert image after tag if 'after' placement is specified if ( $placement == 'after' && $contains_tag ) { $counter++; if ( $position == 'last' && $counter == $total_tags || $counter == $position ) { if ( $classic_editor ) { $new_content .= '

' . $image_block . '

'; } else { $new_content .= $image_block; } $match = true; } } } // If no match found, switch to Classic Editor as a fallback if ( !$match ) { $classic_editor = true; } } return $new_content; } /** * Extract a specific paragraph from the post content. * * @since 6.0.0 */ private function ALLSI_extract_adjacent_element( $content, $element = 'p', $element_number = 1, $direction = 'text_analyser_previous_paragraph' ) { // Define the pattern to match the specified element $pattern = '/<(' . preg_quote( $element, '/' ) . ')(.*?)>(.*?)<\\/\\1>/s'; // Find all matches of the specified element preg_match_all( $pattern, $content, $matches ); // Check if the element_number is "last" if ( $element_number === 'last' ) { // Ensure the index is valid and points to the last element $index = count( $matches[0] ) - 1; } else { // Convert to zero-based index $index = $element_number - 1; } // Check if we have a valid index if ( isset( $matches[0][$index] ) ) { if ( $direction === 'text_analyser_previous_paragraph' || $element_number === 'last' ) { // Get the position of the target element in the content if ( 'p' == $element ) { $target_position = strpos( $content, $matches[0][$index + 1] ); } else { $target_position = strpos( $content, $matches[0][$index] ); } // Get the content before the target element $content_before = substr( $content, 0, $target_position ); // Match all paragraphs before the target element $paragraph_pattern = '/]*>(.*?)<\\/p>/s'; preg_match_all( $paragraph_pattern, $content_before, $paragraph_matches ); // Remove too shorts paragraphs. For exemple "

 

" if ( strlen( $paragraph_matches[0][0] ) < 15 ) { unset($paragraph_matches[0][0]); $paragraph_matches[0] = array_values( $paragraph_matches[0] ); } // Return the last paragraph found before the target element if ( !empty( $paragraph_matches[0] ) ) { // Return only the last paragraph, cleaned of HTML tags return ( is_string( $paragraph_matches[0][count( $paragraph_matches[0] ) - 1] ) ? trim( wp_strip_all_tags( $paragraph_matches[0][count( $paragraph_matches[0] ) - 1] ) ) : '' ); } } elseif ( $direction === 'text_analyser_next_paragraph' ) { // Get the position of the target element in the content $target_position = strpos( $content, $matches[0][$index] ); // Get the content before the target element $content_before = substr( $content, 0, $target_position ); // Get the content after the target element $content_after = substr( $content, $target_position + strlen( $matches[0][$index] ) ); // Match the first paragraph after the target element $paragraph_pattern = '/]*>(.*?)<\\/p>/s'; preg_match_all( $paragraph_pattern, $content_after, $paragraph_matches ); // Remove too shorts paragraphs. For exemple "

 

" if ( strlen( $paragraph_matches[0][0] ) < 15 ) { unset($paragraph_matches[0][0]); $paragraph_matches[0] = array_values( $paragraph_matches[0] ); } // Return the first paragraph found after the target element if ( !empty( $paragraph_matches[0] ) ) { return ( is_string( $paragraph_matches[0][0] ) ? trim( wp_strip_all_tags( $paragraph_matches[0][0] ) ) : '' ); } } } return ''; // Return empty if not found } /** * Check Classic Editor plugin * * @since 5.2.0 */ private function ALLSI_is_using_classic_editor() { // Include the is_plugin_active function if it's not already defined if ( !function_exists( 'is_plugin_active' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin.php'; } // Check if the Classic Editor plugin is active return is_plugin_active( 'classic-editor/classic-editor.php' ); } /** * Get all settings from user * * @since 4.0.0 */ private function ALLSI_Get_Parameters( $img_block, $options, $search ) { ALLSI_log( array( 'bank' => $img_block['api_chosen'], 'search' => $search ), 'GET_PARAMETERS' ); if ( isset( $img_block['api_chosen'] ) && $img_block['api_chosen'] === 'replicate' ) { $api_key = ( !empty( $options['replicate']['apikey'] ) ? $options['replicate']['apikey'] : '' ); $model = ( !empty( $options['replicate']['model'] ) ? $options['replicate']['model'] : 'black-forest-labs/flux-schnell' ); $output_format = ( !empty( $options['replicate']['output_format'] ) ? $options['replicate']['output_format'] : 'webp' ); $aspect_ratio = ( !empty( $options['replicate']['aspect_ratio'] ) ? $options['replicate']['aspect_ratio'] : '16:9' ); // Get version ID from model name (simplified - use latest version) $version_map = array( 'black-forest-labs/flux-schnell' => 'latest', 'stability-ai/sdxl' => 'latest', ); $version = isset( $version_map[$model] ) ? $version_map[$model] : 'latest'; $array_parameters = array( 'url' => 'https://api.replicate.com/v1/predictions', 'method' => 'POST', 'timeout' => 30, 'headers' => array( 'Authorization' => 'Token ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => json_encode( array( 'version' => $version, 'input' => array( 'prompt' => $search, 'output_format' => $output_format, 'aspect_ratio' => $aspect_ratio, ), ) ), ); } elseif ( $img_block['api_chosen'] == 'stability' ) { $api_key = ( !empty( $options['stability']['apikey'] ) ? $options['stability']['apikey'] : '' ); $model = ( !empty( $options['stability']['model'] ) ? $options['stability']['model'] : 'sd3-large' ); $aspect_ratio = ( !empty( $options['stability']['aspect_ratio'] ) ? $options['stability']['aspect_ratio'] : '16:9' ); $output_format = ( !empty( $options['stability']['output_format'] ) ? $options['stability']['output_format'] : 'jpeg' ); $use_negative_prompt = ( !empty( $options['stability']['use_negative_prompt'] ) && 'true' === $options['stability']['use_negative_prompt'] ); $endpoint_map = array( 'sd3-large' => 'sd3', 'sd3-large-turbo' => 'sd3-turbo', 'sd3-medium' => 'sd3', 'sd3.5-large-turbo' => 'sd3', 'sd3.5-large' => 'sd3', 'core' => 'core', 'ultra' => 'ultra', ); $endpoint = isset( $endpoint_map[$model] ) ? $endpoint_map[$model] : 'sd3'; $payload = array( 'prompt' => $search, 'model' => $model, 'aspect_ratio' => $aspect_ratio, 'output_format' => $output_format, ); if ( in_array( $endpoint, array('core', 'ultra'), true ) ) { $aspect_map = array( '21:9' => array('width' => 2560, 'height' => 1097), '16:9' => array('width' => 2560, 'height' => 1440), '3:2' => array('width' => 2304, 'height' => 1536), '5:4' => array('width' => 2048, 'height' => 1638), '1:1' => array('width' => 2048, 'height' => 2048), '4:5' => array('width' => 1638, 'height' => 2048), '2:3' => array('width' => 1536, 'height' => 2304), '9:16' => array('width' => 1440, 'height' => 2560), '9:21' => array('width' => 1097, 'height' => 2560), ); $dimensions = isset( $aspect_map[$aspect_ratio] ) ? $aspect_map[$aspect_ratio] : $aspect_map['16:9']; $payload['width'] = $dimensions['width']; $payload['height'] = $dimensions['height']; } if ( $use_negative_prompt ) { $payload['negative_prompt'] = 'blurry, low quality, distorted, disfigured, ugly, low resolution'; } $boundary = 'ASI-' . wp_generate_password( 24, false ); $body = ''; foreach ( $payload as $field => $value ) { if ( $value === '' ) { continue; } $body .= '--' . $boundary . "\r\n"; $body .= 'Content-Disposition: form-data; name="' . $field . '"' . "\r\n\r\n"; $body .= $value . "\r\n"; } $body .= '--' . $boundary . "--\r\n"; $array_parameters = array( 'url' => 'https://api.stability.ai/v2beta/stable-image/generate/' . $endpoint, 'method' => 'POST', 'timeout' => 60, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Accept' => 'image/*', 'Content-Type' => 'multipart/form-data; boundary=' . $boundary, ), 'body' => $body, ); } else { ALLSI_log( 'Unknown bank: ' . $img_block['api_chosen'], 'GET_PARAMETERS_ERROR' ); return false; } ALLSI_log( array( 'url' => isset($array_parameters['url']) ? $array_parameters['url'] : 'NO URL', 'params_count' => count($array_parameters) ), 'GET_PARAMETERS_SUCCESS' ); return $array_parameters; } /** * Generate image process * * @since 4.0.0 */ public function ALLSI_Generate( $service, $url, $url_parameters, $selected_image, $get_only_thumb = false, $search = '' ) { ALLSI_log( array( 'service' => $service, 'url' => $url, 'search' => $search, 'get_only_thumb' => $get_only_thumb ), 'ALLSI_GENERATE_START' ); $log = $this->ALLSI_monolog_call(); list( $result_body, $result ) = $this->ALLSI_get_results( $service, $url, $url_parameters ); // In case of API problem if ( empty( $result_body ) ) { ALLSI_log( 'Empty result_body from API: ' . $service, 'ALLSI_GENERATE_ERROR' ); return false; } ALLSI_log( 'API response received for: ' . $service, 'ALLSI_GENERATE_RESPONSE' ); $log = $this->ALLSI_monolog_call(); $log->info( 'Source used', array( 'Service' => $service, ) ); // ── INSERT REPLICATE POLLING HERE ──────────────────────────────────────── if ( $service === 'replicate' ) { // extract prediction ID and status URL $predictionId = $result_body['id']; $getUrl = $result_body['urls']['get']; // retrieve API token from settings $options = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( true ) ); $apiToken = ( !empty( $options['replicate']['apikey'] ) ? $options['replicate']['apikey'] : '' ); // poll until prediction is complete do { usleep( 500000 ); // wait 0.5s $request_args = array( 'headers' => array( 'Authorization' => 'Token ' . $apiToken, 'Content-Type' => 'application/json', ), 'timeout' => 10, ); $resp = $this->ALLSI_remote_get( 'replicate', $getUrl, $request_args ); // DEBUG /* $log->info( 'Replicate polling status', [ 'http_code' => wp_remote_retrieve_response_code( $resp ), 'body' => substr( wp_remote_retrieve_body( $resp ), 0, 100 ) // Start of JSON ] );*/ if ( is_wp_error( $resp ) ) { return false; } $body = json_decode( wp_remote_retrieve_body( $resp ), true ); $status = isset( $body['status'] ) ? $body['status'] : ''; } while ( in_array( $status, array('starting', 'processing'), true ) ); // on success, replace output so subsequent logic sees the final URL if ( $status === 'succeeded' && !empty( $body['output'][0] ) ) { $result_body['output'] = $body['output']; } else { return false; } } // ── END OF REPLICATE POLLING ──────────────────────────────────────────── if ( $service === 'stability' ) { $loop_results = $result_body; $url_path = 'image'; } elseif ( $service == 'replicate' ) { $loop_results = ( isset( $result_body['output'] ) ? (array) $result_body['output'] : array() ); $url_path = null; } else { return false; } // Check if function is launch for Gutenberg block if ( TRUE == $get_only_thumb ) { return $result_body; } /* Random Image */ if ( $selected_image == 'random_result' && $service != 'stability' ) { @shuffle( $loop_results ); } // Testing images if ( !empty( $loop_results ) ) { $loop_count = 0; $numUrl = count( $loop_results ); foreach ( $loop_results as $fetch_result_key => $fetch_result ) { if ( 'image' != $fetch_result_key && $service == 'stability' ) { continue; } if ( $service == 'replicate' ) { $url_result = $fetch_result; } elseif ( $service !== 'stability' ) { $url_result = $fetch_result[$url_path]; } // Change default url image if ( $service == 'stability' ) { $url_result = $fetch_result; } elseif ( $service == 'replicate' ) { // For replicate, $fetch_result is already the final URL $url_result = $fetch_result; } else { $url_result = $fetch_result[$url_path]; } $options = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( TRUE ) ); // ALT text generation $alt = ''; if ( isset( $options['enable_alt'] ) && 'enable' == $options['enable_alt'] ) { // Get ALT text source if ( isset( $options['alt_from'] ) && $options['alt_from'] == 'source' ) { // Use image bank name as ALT $alt = ucfirst( $service ); } elseif ( isset( $options['alt_from'] ) && $options['alt_from'] == 'based_on' ) { // Use search term as ALT $alt = $search; } // Translate ALT text if enabled if ( !empty( $alt ) && isset( $options['translate_alt'] ) && $options['translate_alt'] == 'true' ) { $target_lang = ( !empty( $options['translate_alt_lang'] ) ? $options['translate_alt_lang'] : 'en' ); if ( $target_lang !== 'en' ) { $translated_alt = $this->ALLSI_translate_text( $alt, 'en', $target_lang ); if ( $translated_alt !== false ) { $alt = $translated_alt; } } } } // Caption texts if ( isset( $options['enable_caption'] ) && 'enable' == $options['enable_caption'] ) { $caption = ''; if ( 'author_bank' == $options['caption_from'] ) { $caption .= esc_html__( ' from ', 'all-sources-images' ) . ucfirst( $service ); } } else { $caption = ''; } if ( empty( $url_result ) ) { continue; } // Avoid unknown image type if ( $service != 'stability' ) { $url_result = $url_result; $wp_filetype = wp_check_filetype( $url_result ); if ( false == $wp_filetype['type'] ) { continue; } } if ( TRUE == $get_only_thumb ) { $url_result_ar['photos'][]['url'] = $url_result; } else { if ( 'stability' == $service ) { if ( base64_decode( $url_result, true ) !== false ) { // Decoding the image in Base64 $image_data = base64_decode( $url_result ); $options_banks = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( TRUE ) ); // Specify a file path for the image in the download directory $upload_dir = wp_upload_dir(); $file_path = $upload_dir['path'] . '/temp_mpt_stability_' . uniqid() . '.' . $options_banks['stability']['output_format']; // Save the decoded image in the file // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Saving temporary image to uploads. file_put_contents( $file_path, $image_data ); if ( file_exists( $file_path ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading local temp file. $file_content = file_get_contents( $file_path ); } $file_media['response']['code'] = '200'; $file_media['body'] = $file_content; $file_media['headers']['content-type'] = 'image/' . $options_banks['stability']['output_format']; // Remove temporary file wp_delete_file( $file_path ); } } else { $proxy_args = $this->ALLSI_get_proxy_args(); $file_media = @wp_remote_request( $url_result, $proxy_args ); if ( isset( $file_media->errors ) || $file_media['response']['code'] != 200 || strpos( $file_media['headers']['content-type'], 'text/html' ) !== false ) { if ( ++$loop_count === $numUrl ) { return false; } else { continue; } } else { break; } } } } if ( TRUE == $get_only_thumb ) { return $url_result_ar; } } else { return false; } return array( $url_result, $file_media, $alt, $caption ); } /** * Image results to get thumbnails * * @since 4.0.0 */ private function ALLSI_get_results( $service, $url, $url_parameters ) { if ( $service == 'stability' || $service == 'replicate' ) { $defaults = $url_parameters; } else { /* Retrieve 3 images as result */ $url = add_query_arg( $url_parameters, $url ); // Simulate Default Browser $defaults = array( 'redirection' => 9, 'user-agent' => 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96', 'reject_unsafe_urls' => false, 'sslverify' => false, ); } $proxy_args = $this->ALLSI_get_proxy_args(); ALLSI_log( array( 'service' => $service, 'url' => $url, 'has_proxy' => ! empty( $proxy_args ), 'proxy_mode' => $this->ALLSI_current_proxy_mode(), ), 'HTTP_REQUEST' ); $result = $this->ALLSI_remote_request( $service, $url, $defaults ); $response_code = is_wp_error( $result ) ? 'ERROR' : wp_remote_retrieve_response_code( $result ); $body_preview = ''; if ( ! is_wp_error( $result ) && isset( $result['body'] ) ) { $body_preview = substr( $result['body'], 0, 1200 ); } ALLSI_log( array( 'response_code' => $response_code, 'is_error' => is_wp_error( $result ), 'error_message' => is_wp_error( $result ) ? $result->get_error_message() : '', 'body_preview' => $body_preview, ), 'HTTP_RESPONSE' ); // If error happen if ( !empty( $result->errors['http_request_failed'] ) ) { return false; } if ( $service == 'stability' ) { $code = intval( $result['response']['code'] ); if ( 200 !== $code ) { return false; } $result_body = array( 'image' => base64_encode( $result['body'] ), ); } else { $result_body = json_decode( $result['body'], true ); // accept 200 for most services, 201 for replicate $code = intval( $result['response']['code'] ); if ( $service === 'replicate' && $code !== 201 || $service !== 'replicate' && $code !== 200 ) { return false; } } return array($result_body, $result); } /** * Remove gstatic images * * @since 4.0.0 */ public function ALLSI_order_array_urls( $str, $str_alt, $str_caption ) { // Get only the url and exclude Google image url (domain gstatic) $pattern = '/,\\["(http[^"]((?!gstatic).)*)",\\d+?,\\d+?\\]/'; $replacement = '$1'; // Check if $str is not null before using preg_replace $real_url = ( $str !== null ? preg_replace( $pattern, $replacement, $str ) : '' ); return array( 'url' => $real_url, 'alt' => $str_alt, 'caption' => $str_caption, ); } /** * Function to get the depth of a category * * @since 5.2.11 */ private function get_category_depth( $cat_id, $current_depth = 0 ) { $category = get_category( $cat_id ); if ( $category->parent == 0 ) { return $current_depth; } else { return $this->get_category_depth( $category->parent, $current_depth + 1 ); } } /** * Function to get the desired category based on the user's choice * * @since 5.2.11 */ private function get_desired_category( $post_id, $category_choice ) { // Retrieve the categories of the post $postcategories = get_the_category( $post_id ); $categories_with_depth = array(); // Check if the post has any categories if ( empty( $postcategories ) ) { // Handle the case where no categories are associated return null; } // Get the depth of each category associated with the post foreach ( $postcategories as $category ) { $depth = $this->get_category_depth( $category->term_id ); // Store the category with its depth as the key $categories_with_depth[$depth] = $category; } // Find the category with the greatest depth (most specific) $max_depth = max( array_keys( $categories_with_depth ) ); $child_category = $categories_with_depth[$max_depth]; // Determine the category to use based on the user's choice $desired_category = $child_category; if ( $category_choice && $child_category ) { if ( $category_choice == 'second_level' ) { if ( $child_category->parent ) { $desired_category = get_category( $child_category->parent ); } } elseif ( $category_choice == 'third_level' ) { if ( $child_category->parent ) { $parent_category = get_category( $child_category->parent ); if ( $parent_category->parent ) { $desired_category = get_category( $parent_category->parent ); } else { $desired_category = $parent_category; } } } } return $desired_category; } /** * Function to get the desired term based on the user's choice and a custom taxonomy * * @since 6.0.0 */ private function get_desired_taxonomy( $post_id, $taxonomy, $term_choice ) { // Retrieve the terms of the post in the specified taxonomy $post_terms = get_the_terms( $post_id, $taxonomy ); $terms_with_depth = array(); // Check if the post has any terms in the taxonomy if ( empty( $post_terms ) || is_wp_error( $post_terms ) ) { // Handle the case where no terms are associated or there's an error return null; } // Get the depth of each term associated with the post foreach ( $post_terms as $term ) { $depth = $this->get_term_depth( $term->term_id, $taxonomy ); // Store the term with its depth as the key $terms_with_depth[$depth] = $term; } // Find the term with the greatest depth (most specific) $max_depth = max( array_keys( $terms_with_depth ) ); $child_term = $terms_with_depth[$max_depth]; // Determine the term to use based on the user's choice $desired_term = $child_term; if ( $term_choice && $child_term ) { if ( $term_choice == 'second_level' ) { if ( $child_term->parent ) { $desired_term = get_term( $child_term->parent, $taxonomy ); } } elseif ( $term_choice == 'third_level' ) { if ( $child_term->parent ) { $parent_term = get_term( $child_term->parent, $taxonomy ); if ( $parent_term->parent ) { $desired_term = get_term( $parent_term->parent, $taxonomy ); } else { $desired_term = $parent_term; } } } } return $desired_term; } /** * Helper function to get the depth of a term in a custom taxonomy. * * @since 6.0.0 */ private function get_term_depth( $term_id, $taxonomy ) { $depth = 0; $term = get_term( $term_id, $taxonomy ); while ( $term && $term->parent ) { $term = get_term( $term->parent, $taxonomy ); $depth++; } return $depth; } /** * Helper function to get the depth of a term in a custom taxonomy. * * @since 6.0.0 */ private function get_extracted_term( $text, $selected_lang = 'en' ) { require_once dirname( __FILE__ ) . '/../includes/php-ml/index.php'; $extractor = new ALLSI_KeywordExtractor( $selected_lang ); $keywords = $extractor->extractKeywords( $text ); return $keywords[0]; } /** * Calculate dimensions from aspect ratio for models that use width/height * * @since 6.0.0 * @param string $aspect_ratio The aspect ratio (e.g., '16:9', '4:3') * @param int $max_resolution Maximum resolution for the model * @return array Array with 'width' and 'height' keys */ private function calculate_dimensions_from_aspect_ratio( $aspect_ratio, $max_resolution = 2048 ) { // Seedream-4 specific dimensions as per official documentation $seedream_dimensions = array( '1:1' => array( 'width' => 2048, 'height' => 2048, ), '4:3' => array( 'width' => 2304, 'height' => 1728, ), '16:9' => array( 'width' => 2560, 'height' => 1440, ), '3:2' => array( 'width' => 2304, 'height' => 1536, ), '9:16' => array( 'width' => 1440, 'height' => 2560, ), ); // Check if we have specific dimensions for this aspect ratio if ( isset( $seedream_dimensions[$aspect_ratio] ) ) { return $seedream_dimensions[$aspect_ratio]; } // Fallback to calculated dimensions for other ratios $ratio_parts = explode( ':', $aspect_ratio ); if ( count( $ratio_parts ) !== 2 ) { // Default to 16:9 if invalid format $ratio_parts = array(16, 9); } $ratio_width = (int) $ratio_parts[0]; $ratio_height = (int) $ratio_parts[1]; // Calculate base dimensions $base_width = $max_resolution; $base_height = round( $max_resolution * $ratio_height / $ratio_width ); // Ensure we don't exceed max resolution if ( $base_height > $max_resolution ) { $base_height = $max_resolution; $base_width = round( $max_resolution * $ratio_width / $ratio_height ); } // Round to even numbers for better compatibility $width = $base_width - $base_width % 2; $height = $base_height - $base_height % 2; return array( 'width' => $width, 'height' => $height, ); } /** * Translate text using Google Translate * * @since 6.2.0 * @param string $text Text to translate * @param string $source_lang Source language code (default: auto) * @param string $target_lang Target language code (default: en) * @return string|false Translated text or false on error */ public function ALLSI_translate_text( $text, $source_lang = 'auto', $target_lang = 'en' ) { if ( empty( $text ) || $source_lang === $target_lang ) { return $text; } $log = $this->ALLSI_monolog_call(); $options_banks = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( TRUE ) ); $api_key = ( !empty( $options_banks['google_translate']['apikey'] ) ? $options_banks['google_translate']['apikey'] : '' ); // Use official Google Translate API if API key is provided if ( !empty( $api_key ) ) { $url = 'https://translation.googleapis.com/language/translate/v2'; $params = array( 'key' => $api_key, 'q' => $text, 'source' => $source_lang, 'target' => $target_lang, 'format' => 'text', ); $response = $this->ALLSI_remote_post( 'google_translate', $url, array( 'body' => $params, 'timeout' => 10, ) ); if ( is_wp_error( $response ) ) { $log->error( 'Google Translate API error', array( 'error' => $response->get_error_message(), ) ); return false; } $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( isset( $body['data']['translations'][0]['translatedText'] ) ) { $translated = $body['data']['translations'][0]['translatedText']; $log->info( 'Text translated (API)', array( 'from' => $text, 'to' => $translated, ) ); return $translated; } } // Fallback to free Google Translate scraping method $url = 'https://translate.googleapis.com/translate_a/single'; $params = array( 'client' => 'gtx', 'sl' => $source_lang, 'tl' => $target_lang, 'dt' => 't', 'q' => $text, ); $url = add_query_arg( $params, $url ); $response = $this->ALLSI_remote_get( 'google_translate', $url, array( 'timeout' => 10, ) ); if ( is_wp_error( $response ) ) { $log->error( 'Google Translate scraping error', array( 'error' => $response->get_error_message(), ) ); return false; } $body = wp_remote_retrieve_body( $response ); $result = json_decode( $body, true ); if ( isset( $result[0][0][0] ) ) { $translated = $result[0][0][0]; $log->info( 'Text translated (free)', array( 'from' => $text, 'to' => $translated, ) ); return $translated; } return false; } /** * Extract keywords using OpenAI GPT * * @since 6.2.0 * @param string $api_key OpenAI API key * @param string $title Post title * @param string $content Post content (optional) * @param string $num_keywords Number of keywords to extract ('1-2', '2', '3') * @return string|false Extracted keywords or false on failure */ public function ALLSI_openai_extract_keywords( $api_key, $title, $content = '', $num_keywords = '2' ) { $log = $this->ALLSI_monolog_call(); if ( empty( $api_key ) ) { return false; } // Determine keyword count $keyword_count = 2; if ( $num_keywords === '1-2' ) { $keyword_count = '1 or 2'; } elseif ( $num_keywords === '3' ) { $keyword_count = 3; } $prompt = "Extract the {$keyword_count} most relevant keywords for image search from the following content. Return ONLY the keywords separated by spaces, nothing else. The keywords should be suitable for searching stock photos or generating AI images.\n\nTitle: {$title}"; if ( ! empty( $content ) ) { $prompt .= "\n\nContent excerpt: {$content}"; } $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', array( 'timeout' => 30, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => json_encode( array( 'model' => 'gpt-3.5-turbo', 'messages' => array( array( 'role' => 'system', 'content' => 'You are a keyword extraction assistant. Extract concise, relevant keywords for image search. Return only the keywords, nothing else.', ), array( 'role' => 'user', 'content' => $prompt, ), ), 'max_tokens' => 50, 'temperature' => 0.3, ) ), ) ); if ( is_wp_error( $response ) ) { $log->error( 'OpenAI keyword extraction error', array( 'error' => $response->get_error_message(), ) ); return false; } $body = wp_remote_retrieve_body( $response ); $result = json_decode( $body, true ); if ( isset( $result['choices'][0]['message']['content'] ) ) { $keywords = trim( $result['choices'][0]['message']['content'] ); // Clean up any punctuation or formatting $keywords = preg_replace( '/[,;:\-\n]/', ' ', $keywords ); $keywords = preg_replace( '/\s+/', ' ', $keywords ); $log->info( 'OpenAI keywords extracted', array( 'title' => $title, 'keywords' => $keywords, ) ); return $keywords; } if ( isset( $result['error'] ) ) { $log->error( 'OpenAI API error', array( 'error' => $result['error']['message'], ) ); } return false; } /** * Generate optimized image prompt using OpenAI GPT * * @since 6.2.0 * @param string $api_key OpenAI API key * @param string $title Post title * @param string $content Post content (optional) * @param string $style Image style (photorealistic, illustration, etc.) * @param string $custom_instructions Additional user instructions * @return string|false Generated prompt or false on failure */ public function ALLSI_openai_generate_image_prompt( $api_key, $title, $content = '', $style = 'photorealistic', $custom_instructions = '' ) { $log = $this->ALLSI_monolog_call(); if ( empty( $api_key ) ) { return false; } // Style descriptions $style_descriptions = array( 'photorealistic' => 'a highly realistic photograph', 'illustration' => 'a detailed illustration', 'digital_art' => 'digital art style', '3d_render' => 'a 3D rendered image', 'oil_painting' => 'an oil painting style', 'watercolor' => 'a watercolor painting', 'sketch' => 'a pencil sketch or drawing', 'minimalist' => 'a minimalist design', 'vintage' => 'a vintage or retro style', 'comic' => 'a comic or cartoon style', 'anime' => 'anime or manga art style', 'cinematic' => 'a cinematic movie-like shot', 'custom' => 'a professional image', ); $style_desc = isset( $style_descriptions[ $style ] ) ? $style_descriptions[ $style ] : $style_descriptions['photorealistic']; $system_prompt = "You are an expert at creating image generation prompts for AI tools like DALL-E, Stable Diffusion, and Midjourney. Create detailed, visually descriptive prompts that will generate beautiful, relevant images."; $user_prompt = "Create an optimized image generation prompt for the following blog post. The image should be {$style_desc}.\n\n"; $user_prompt .= "Title: {$title}\n"; if ( ! empty( $content ) ) { $user_prompt .= "Content summary: {$content}\n"; } if ( ! empty( $custom_instructions ) ) { $user_prompt .= "Additional requirements: {$custom_instructions}\n"; } $user_prompt .= "\nReturn ONLY the image prompt, no explanations. The prompt should be detailed but under 200 characters for best results."; $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', array( 'timeout' => 30, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => json_encode( array( 'model' => 'gpt-3.5-turbo', 'messages' => array( array( 'role' => 'system', 'content' => $system_prompt, ), array( 'role' => 'user', 'content' => $user_prompt, ), ), 'max_tokens' => 150, 'temperature' => 0.7, ) ), ) ); if ( is_wp_error( $response ) ) { $log->error( 'OpenAI image prompt generation error', array( 'error' => $response->get_error_message(), ) ); return false; } $body = wp_remote_retrieve_body( $response ); $result = json_decode( $body, true ); if ( isset( $result['choices'][0]['message']['content'] ) ) { $prompt = trim( $result['choices'][0]['message']['content'] ); // Remove quotes if present $prompt = trim( $prompt, '"\''); $log->info( 'AI image prompt generated', array( 'title' => $title, 'style' => $style, 'prompt' => $prompt, ) ); return $prompt; } if ( isset( $result['error'] ) ) { $log->error( 'OpenAI API error', array( 'error' => $result['error']['message'], ) ); } return false; } }