feat: consolidate docs, backend/session infra, and settings updates

This commit is contained in:
Dwindi Ramadhana
2026-05-28 00:58:20 +07:00
parent 2424acf726
commit 44e06eed88
102 changed files with 35423 additions and 11181 deletions

View File

@@ -43,6 +43,41 @@ class WP_Agentic_Writer_Image_Manager {
// Private constructor for singleton.
}
/**
* Check if required tables exist.
*
* @since 0.1.0
* @return bool True if tables exist, false otherwise.
*/
public function tables_exist() {
global $wpdb;
$table_images = $wpdb->prefix . 'wpaw_images';
// Check if table exists using SHOW TABLES
$result = $wpdb->get_var( "SHOW TABLES LIKE '{$table_images}'" );
return $result === $table_images;
}
/**
* Ensure tables exist, create if missing.
*
* @since 0.1.0
* @return true|WP_Error True on success, WP_Error on failure.
*/
public function ensure_tables() {
if ( ! $this->tables_exist() ) {
$result = $this->create_tables();
if ( ! $result ) {
return new WP_Error(
'table_creation_failed',
__( 'Failed to create image database tables. Please check database permissions.', 'wp-agentic-writer' )
);
}
}
return true;
}
/**
* Create database tables on plugin activation.
*/
@@ -110,6 +145,8 @@ class WP_Agentic_Writer_Image_Manager {
// Create temp directory.
$this->create_temp_directory();
return true;
}
/**
@@ -145,7 +182,7 @@ class WP_Agentic_Writer_Image_Manager {
*/
public function analyze_article_for_images( $article_markdown, $post_id ) {
$settings = get_option( 'wp_agentic_writer_settings', array() );
$writing_model = $settings['writing_model'] ?? 'anthropic/claude-3.5-sonnet';
$writing_model = $settings['writing_model'] ?? WPAW_Model_Registry::get_default_model( 'writing' );
$system_prompt = "You are an expert content strategist analyzing articles for optimal image placement.
@@ -178,7 +215,8 @@ Return JSON:
),
);
$provider = WP_Agentic_Writer_Provider_Manager::get_provider_for_task( 'planning' );
$provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task( 'planning' );
$provider = $provider_result->provider;
$response = $provider->chat( $messages, array( 'temperature' => 0.3 ), 'planning' );
if ( is_wp_error( $response ) ) {
@@ -207,8 +245,8 @@ Return JSON:
*/
public function generate_image_prompts( $article_markdown, $placement_data, $post_id ) {
$settings = get_option( 'wp_agentic_writer_settings', array() );
$writing_model = $settings['writing_model'] ?? 'anthropic/claude-3.5-sonnet';
$image_model = $settings['image_model'] ?? 'openai/gpt-4o';
$writing_model = $settings['writing_model'] ?? WPAW_Model_Registry::get_default_model( 'writing' );
$image_model = $settings['image_model'] ?? WPAW_Model_Registry::get_default_model( 'image' );
// Get model-specific prompt guidance.
$prompt_guidance = $this->get_prompt_guidance_for_model( $image_model );
@@ -255,7 +293,8 @@ Return JSON:
),
);
$provider = WP_Agentic_Writer_Provider_Manager::get_provider_for_task( 'planning' );
$provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task( 'planning' );
$provider = $provider_result->provider;
$response = $provider->chat( $messages, array( 'temperature' => 0.7 ), 'planning' );
if ( is_wp_error( $response ) ) {
@@ -318,6 +357,13 @@ Return JSON:
* @param array $images Image specifications.
*/
private function save_image_recommendations( $post_id, $images ) {
// Ensure tables exist before saving
$check = $this->ensure_tables();
if ( is_wp_error( $check ) ) {
error_log( 'WPAW Image Manager: Cannot save recommendations - tables not available' );
return;
}
global $wpdb;
$table = $wpdb->prefix . 'wpaw_images';
@@ -348,14 +394,20 @@ Return JSON:
* @param string $section_title Section title.
* @param string $prompt Image prompt/description.
* @param string $alt_text Alt text for image.
* @return int|false Insert ID or false on failure.
* @return int|false|WP_Error Insert ID, false on failure, or WP_Error if tables don't exist.
*/
public function save_image_recommendation( $post_id, $agent_image_id, $placement, $section_title, $prompt, $alt_text ) {
// Ensure tables exist before saving
$check = $this->ensure_tables();
if ( is_wp_error( $check ) ) {
return $check;
}
global $wpdb;
$table = $wpdb->prefix . 'wpaw_images';
$settings = get_option( 'wp_agentic_writer_settings', array() );
$image_model = $settings['image_model'] ?? 'openai/gpt-4o';
$image_model = $settings['image_model'] ?? WPAW_Model_Registry::get_default_model( 'image' );
$result = $wpdb->insert(
$table,
@@ -383,9 +435,15 @@ Return JSON:
* Get image recommendations for a post.
*
* @param int $post_id Post ID.
* @return array Image recommendations.
* @return array|WP_Error Image recommendations or error if tables don't exist.
*/
public function get_image_recommendations( $post_id ) {
// Ensure tables exist before querying
$check = $this->ensure_tables();
if ( is_wp_error( $check ) ) {
return $check;
}
global $wpdb;
$table = $wpdb->prefix . 'wpaw_images';
@@ -410,10 +468,17 @@ Return JSON:
* @return array|WP_Error Generated variants or error.
*/
public function generate_image_variants( $post_id, $agent_image_id, $prompt, $variant_count = 2 ) {
$settings = get_option( 'wp_agentic_writer_settings', array() );
$image_model = $settings['image_model'] ?? 'openai/gpt-4o';
// Ensure tables exist before proceeding
$check = $this->ensure_tables();
if ( is_wp_error( $check ) ) {
return $check;
}
$provider = WP_Agentic_Writer_Provider_Manager::get_provider_for_task( 'image' );
$settings = get_option( 'wp_agentic_writer_settings', array() );
$image_model = $settings['image_model'] ?? WPAW_Model_Registry::get_default_model( 'image' );
$provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task( 'image' );
$provider = $provider_result->provider;
$variants = array();
@@ -480,20 +545,36 @@ Return JSON:
wp_mkdir_p( $temp_dir );
}
// Download image.
$response = wp_remote_get( $image_url, array( 'timeout' => 30 ) );
$image_data = '';
$extension = 'jpg';
if ( is_wp_error( $response ) ) {
return $response;
}
if ( preg_match( '#^data:image/([a-zA-Z0-9.+-]+);base64,(.+)$#', (string) $image_url, $matches ) ) {
$extension = strtolower( $matches[1] );
$extension = 'jpeg' === $extension ? 'jpg' : $extension;
$image_data = base64_decode( $matches[2] );
if ( false === $image_data ) {
return new WP_Error(
'invalid_image_data',
__( 'Generated image data could not be decoded.', 'wp-agentic-writer' )
);
}
} else {
// Download image.
$response = wp_remote_get( $image_url, array( 'timeout' => 30 ) );
$image_data = wp_remote_retrieve_body( $response );
if ( is_wp_error( $response ) ) {
return $response;
}
// Determine file extension from content type.
$content_type = wp_remote_retrieve_header( $response, 'content-type' );
$extension = 'jpg';
if ( strpos( $content_type, 'png' ) !== false ) {
$extension = 'png';
$image_data = wp_remote_retrieve_body( $response );
// Determine file extension from content type.
$content_type = wp_remote_retrieve_header( $response, 'content-type' );
if ( strpos( $content_type, 'png' ) !== false ) {
$extension = 'png';
} elseif ( strpos( $content_type, 'webp' ) !== false ) {
$extension = 'webp';
}
}
$filename = sprintf(
@@ -591,19 +672,37 @@ Return JSON:
return new WP_Error( 'variant_not_found', 'Variant not found' );
}
if ( empty( $variant['temp_file_path'] ) || ! file_exists( $variant['temp_file_path'] ) ) {
return new WP_Error(
'variant_file_missing',
__( 'Generated image file is missing. Please generate the variant again.', 'wp-agentic-writer' )
);
}
// Upload to Media Library.
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
$sideload_tmp = wp_tempnam( basename( $variant['temp_file_path'] ) );
if ( ! $sideload_tmp || ! copy( $variant['temp_file_path'], $sideload_tmp ) ) {
return new WP_Error(
'variant_copy_failed',
__( 'Generated image could not be prepared for upload.', 'wp-agentic-writer' )
);
}
$file_array = array(
'name' => basename( $variant['temp_file_path'] ),
'tmp_name' => $variant['temp_file_path'],
'tmp_name' => $sideload_tmp,
);
$attachment_id = media_handle_sideload( $file_array, $post_id );
if ( is_wp_error( $attachment_id ) ) {
if ( file_exists( $sideload_tmp ) ) {
@unlink( $sideload_tmp );
}
return $attachment_id;
}