Changeset 3490375
- Timestamp:
- 03/24/2026 09:18:30 PM (12 days ago)
- Location:
- 1platform-content-ai
- Files:
-
- 10 added
- 6 deleted
- 40 edited
- 1 copied
-
tags/2.9.0 (copied) (copied from 1platform-content-ai/trunk)
-
tags/2.9.0/.git/FETCH_HEAD (modified) (1 diff)
-
tags/2.9.0/.git/ORIG_HEAD (modified) (1 diff)
-
tags/2.9.0/.git/config (modified) (1 diff)
-
tags/2.9.0/.git/index (modified) (previous)
-
tags/2.9.0/.git/logs/HEAD (modified) (1 diff)
-
tags/2.9.0/.git/logs/refs/heads/main (modified) (1 diff)
-
tags/2.9.0/.git/logs/refs/remotes/origin/main (modified) (1 diff)
-
tags/2.9.0/.git/objects/pack/pack-51404a2c9ec36e0b80213079ab64990416b38e0c.idx (deleted)
-
tags/2.9.0/.git/objects/pack/pack-51404a2c9ec36e0b80213079ab64990416b38e0c.pack (deleted)
-
tags/2.9.0/.git/objects/pack/pack-51404a2c9ec36e0b80213079ab64990416b38e0c.rev (deleted)
-
tags/2.9.0/.git/objects/pack/pack-8b8c0789a386aeca139c1d6186c9fedc06ef6db3.idx (added)
-
tags/2.9.0/.git/objects/pack/pack-8b8c0789a386aeca139c1d6186c9fedc06ef6db3.pack (added)
-
tags/2.9.0/.git/objects/pack/pack-8b8c0789a386aeca139c1d6186c9fedc06ef6db3.rev (added)
-
tags/2.9.0/.git/refs/heads/main (modified) (1 diff)
-
tags/2.9.0/.git/refs/remotes/origin/main (modified) (1 diff)
-
tags/2.9.0/.git/refs/tags/qa-v2.8.0-rc14 (added)
-
tags/2.9.0/.git/refs/tags/v2.9.0 (added)
-
tags/2.9.0/1platform-content-ai.php (modified) (1 diff)
-
tags/2.9.0/includes/admin/admin-ai-site-generator.php (modified) (7 diffs)
-
tags/2.9.0/includes/admin/ai-site-generator/site-generator-form.php (modified) (11 diffs)
-
tags/2.9.0/includes/admin/assets/css/admin-ai-site-generator.css (modified) (33 diffs)
-
tags/2.9.0/includes/admin/content-generator/handlers/KeywordExtractionHandler.php (modified) (3 diffs)
-
tags/2.9.0/includes/admin/content-generator/panels/keyword-extractor.php (modified) (5 diffs)
-
tags/2.9.0/includes/services/api/OnePlatformEndpoints.php (modified) (1 diff)
-
tags/2.9.0/includes/services/jobs/KeywordExtractionJob.php (modified) (3 diffs)
-
tags/2.9.0/includes/services/jobs/SiteGenerationJob.php (modified) (1 diff)
-
tags/2.9.0/includes/services/keyword/KeywordExtractorService.php (modified) (2 diffs)
-
tags/2.9.0/readme.txt (modified) (1 diff)
-
trunk/.git/FETCH_HEAD (modified) (1 diff)
-
trunk/.git/ORIG_HEAD (modified) (1 diff)
-
trunk/.git/config (modified) (1 diff)
-
trunk/.git/index (modified) (previous)
-
trunk/.git/logs/HEAD (modified) (1 diff)
-
trunk/.git/logs/refs/heads/main (modified) (1 diff)
-
trunk/.git/logs/refs/remotes/origin/main (modified) (1 diff)
-
trunk/.git/objects/pack/pack-51404a2c9ec36e0b80213079ab64990416b38e0c.idx (deleted)
-
trunk/.git/objects/pack/pack-51404a2c9ec36e0b80213079ab64990416b38e0c.pack (deleted)
-
trunk/.git/objects/pack/pack-51404a2c9ec36e0b80213079ab64990416b38e0c.rev (deleted)
-
trunk/.git/objects/pack/pack-8b8c0789a386aeca139c1d6186c9fedc06ef6db3.idx (added)
-
trunk/.git/objects/pack/pack-8b8c0789a386aeca139c1d6186c9fedc06ef6db3.pack (added)
-
trunk/.git/objects/pack/pack-8b8c0789a386aeca139c1d6186c9fedc06ef6db3.rev (added)
-
trunk/.git/refs/heads/main (modified) (1 diff)
-
trunk/.git/refs/remotes/origin/main (modified) (1 diff)
-
trunk/.git/refs/tags/qa-v2.8.0-rc14 (added)
-
trunk/.git/refs/tags/v2.9.0 (added)
-
trunk/1platform-content-ai.php (modified) (1 diff)
-
trunk/includes/admin/admin-ai-site-generator.php (modified) (7 diffs)
-
trunk/includes/admin/ai-site-generator/site-generator-form.php (modified) (11 diffs)
-
trunk/includes/admin/assets/css/admin-ai-site-generator.css (modified) (33 diffs)
-
trunk/includes/admin/content-generator/handlers/KeywordExtractionHandler.php (modified) (3 diffs)
-
trunk/includes/admin/content-generator/panels/keyword-extractor.php (modified) (5 diffs)
-
trunk/includes/services/api/OnePlatformEndpoints.php (modified) (1 diff)
-
trunk/includes/services/jobs/KeywordExtractionJob.php (modified) (3 diffs)
-
trunk/includes/services/jobs/SiteGenerationJob.php (modified) (1 diff)
-
trunk/includes/services/keyword/KeywordExtractorService.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
1platform-content-ai/tags/2.9.0/.git/FETCH_HEAD
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1branch 'main' of https://github.com/1platformlabs/1platform-content-ai1 d0f02faf2b07912251edc6729f937622150be15e branch 'main' of https://github.com/1platformlabs/1platform-content-ai -
1platform-content-ai/tags/2.9.0/.git/ORIG_HEAD
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1 1 d0f02faf2b07912251edc6729f937622150be15e -
1platform-content-ai/tags/2.9.0/.git/config
r3488242 r3490375 10 10 auto = 0 11 11 [http "https://github.com/"] 12 extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzX zZmZ1hBU01NQ25ORDF3aHA1aE5Rczl2dVpsRzBYMDNNcUZzVA==12 extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzX20yVVRQdDlDdEdZdjVHOXNDZ0ZlelJGTXExV0N0VTNsSHI0Sw== 13 13 [branch "main"] 14 14 remote = origin -
1platform-content-ai/tags/2.9.0/.git/logs/HEAD
r3488242 r3490375 1 0000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052+0000 checkout: moving from master to main1 0000000000000000000000000000000000000000 d0f02faf2b07912251edc6729f937622150be15e runner <runner@runnervm46oaq.ajpjuzvd0pcu5m1ughqrvmkcxa.bx.internal.cloudapp.net> 1774387066 +0000 checkout: moving from master to main -
1platform-content-ai/tags/2.9.0/.git/logs/refs/heads/main
r3488242 r3490375 1 0000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052+0000 branch: Created from refs/remotes/origin/main1 0000000000000000000000000000000000000000 d0f02faf2b07912251edc6729f937622150be15e runner <runner@runnervm46oaq.ajpjuzvd0pcu5m1ughqrvmkcxa.bx.internal.cloudapp.net> 1774387066 +0000 branch: Created from refs/remotes/origin/main -
1platform-content-ai/tags/2.9.0/.git/logs/refs/remotes/origin/main
r3488242 r3490375 1 0000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052+0000 fetch --prune --no-recurse-submodules origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*: storing head1 0000000000000000000000000000000000000000 d0f02faf2b07912251edc6729f937622150be15e runner <runner@runnervm46oaq.ajpjuzvd0pcu5m1ughqrvmkcxa.bx.internal.cloudapp.net> 1774387066 +0000 fetch --prune --no-recurse-submodules origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*: storing head -
1platform-content-ai/tags/2.9.0/.git/refs/heads/main
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1 1 d0f02faf2b07912251edc6729f937622150be15e -
1platform-content-ai/tags/2.9.0/.git/refs/remotes/origin/main
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1 1 d0f02faf2b07912251edc6729f937622150be15e -
1platform-content-ai/tags/2.9.0/1platform-content-ai.php
r3488242 r3490375 5 5 * Plugin URI: https://1platform.pro/ 6 6 * Description: SaaS client for AI-powered content generation, SEO optimization, and site management. All AI processing happens on 1Platform external servers. Includes free local tools: Table of Contents and Internal Links. 7 * Version: 2. 7.07 * Version: 2.9.0 8 8 * Author: 1Platform 9 9 * License: GPLv2 or later -
1platform-content-ai/tags/2.9.0/includes/admin/admin-ai-site-generator.php
r3488242 r3490375 52 52 'page' => 'contai-ai-site-generator', 53 53 'error' => 1, 54 'message' => urlencode( 'Please select a category before starting the site generation process.' ),54 'message' => 'Please select a category before starting the site generation process.', 55 55 ), 56 56 admin_url( 'admin.php' ) … … 69 69 'page' => 'contai-ai-site-generator', 70 70 'error' => 1, 71 'message' => urlencode( 'There is already an active site generation process running.' ),71 'message' => 'There is already an active site generation process running.', 72 72 ), 73 73 admin_url( 'admin.php' ) … … 93 93 ), 94 94 'keyword_extraction' => array( 95 'source_ url' => esc_url_raw( wp_unslash( $_POST['contai_source_url'] ?? '' ) ),95 'source_topic' => sanitize_text_field( wp_unslash( $_POST['contai_source_topic'] ?? '' ) ), 96 96 'target_country' => sanitize_text_field( wp_unslash( $_POST['contai_target_country'] ?? 'us' ) ), 97 97 'target_language' => sanitize_text_field( wp_unslash( $_POST['contai_target_language'] ?? 'en' ) ), … … 129 129 'page' => 'contai-ai-site-generator', 130 130 'error' => 1, 131 'message' => urlencode( 'Failed to start site generation process.' ),131 'message' => 'Failed to start site generation process.', 132 132 ), 133 133 admin_url( 'admin.php' ) … … 141 141 if ( ! empty( $_POST['contai_site_category'] ) ) { 142 142 update_option( 'contai_site_category', sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ) ) ); 143 } 144 145 // Save AdSense publisher ID immediately so it appears in Ads Manager 146 // before the background job completes (fixes #12) 147 $adsense_publisher = sanitize_text_field( wp_unslash( $_POST['contai_adsense_publisher'] ?? '' ) ); 148 if ( ! empty( $adsense_publisher ) && preg_match( '/^pub-\d+$/', $adsense_publisher ) ) { 149 update_option( 'contai_adsense_publishers', $adsense_publisher ); 150 if ( function_exists( 'contai_generate_adsense_ads' ) ) { 151 contai_generate_adsense_ads(); 152 } 143 153 } 144 154 … … 170 180 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 171 181 $msg = isset( $_GET['message'] ) ? sanitize_text_field( wp_unslash( $_GET['message'] ) ) : 'Success'; 172 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( urldecode( $msg )) . '</p></div>';182 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $msg ) . '</p></div>'; 173 183 } 174 184 … … 177 187 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 178 188 $msg = isset( $_GET['message'] ) ? sanitize_text_field( wp_unslash( $_GET['message'] ) ) : 'Error'; 179 echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( urldecode( $msg )) . '</p></div>';189 echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $msg ) . '</p></div>'; 180 190 } 181 191 -
1platform-content-ai/tags/2.9.0/includes/admin/ai-site-generator/site-generator-form.php
r3488242 r3490375 12 12 $categories = $category_service->getActiveCategories(); 13 13 $saved_category = get_option( 'contai_site_category', '' ); 14 $site_domain = wp_parse_url( home_url(), PHP_URL_HOST ); 15 $default_email = 'info@' . preg_replace( '/^www\./', '', $site_domain ); 14 16 15 17 ?> … … 17 19 <?php wp_nonce_field( 'contai_site_generator_nonce', 'contai_site_generator_nonce' ); ?> 18 20 <input type="hidden" name="contai_start_site_generation" value="1"> 19 20 21 <input type="hidden" id="contai_wordpress_theme" name="contai_wordpress_theme" value="astra"> 21 22 22 23 <!-- Step 1: Website Identity --> 23 <div class="contai-wizard-section" >24 <div class="contai-wizard-section" data-step="1"> 24 25 <div class="contai-section-header"> 25 26 <div class="contai-step-indicator"> 26 27 <span class="contai-step-number">1</span> 28 <span class="contai-step-line"></span> 27 29 </div> 28 30 <div class="contai-section-title-group"> 29 <h2 class="contai-section-title"><?php esc_html_e( 'Website Identity', '1platform-content-ai' ); ?></h2> 31 <h2 class="contai-section-title"> 32 <span class="dashicons dashicons-admin-site-alt3 contai-section-icon"></span> 33 <?php esc_html_e( 'Website Identity', '1platform-content-ai' ); ?> 34 </h2> 30 35 <p class="contai-section-description"><?php esc_html_e( 'Define what your website is about and who it targets.', '1platform-content-ai' ); ?></p> 31 36 </div> 32 37 </div> 33 38 <div class="contai-section-body"> 34 <div class="contai-form-grid contai-grid- 3">35 <div class="contai-form-group ">39 <div class="contai-form-grid contai-grid-2"> 40 <div class="contai-form-group contai-span-full"> 36 41 <label for="contai_site_topic" class="contai-label"> 37 42 <?php esc_html_e( 'Site Topic', '1platform-content-ai' ); ?> 38 43 <span class="contai-required">*</span> 39 44 </label> 40 <input type="text" id="contai_site_topic" name="contai_site_topic" class="contai-input" placeholder="e.g., Technology News" autocomplete="off" required> 45 <div class="contai-input-wrap contai-input-icon"> 46 <span class="dashicons dashicons-edit"></span> 47 <input type="text" id="contai_site_topic" name="contai_site_topic" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., Indoor gardening, Personal finance, Pet care...', '1platform-content-ai' ); ?>" autocomplete="off" required> 48 </div> 41 49 <span class="contai-help-text"><?php esc_html_e( 'The main subject of your website', '1platform-content-ai' ); ?></span> 42 50 </div> … … 91 99 </div> 92 100 93 <div class="contai-form-group contai-span-2">101 <div class="contai-form-group"> 94 102 <label for="contai_adsense_publisher" class="contai-label"> 95 103 <?php esc_html_e( 'AdSense Publisher ID', '1platform-content-ai' ); ?> 96 104 <span class="contai-required">*</span> 97 105 </label> 98 <input type="text" id="contai_adsense_publisher" name="contai_adsense_publisher" class="contai-input" placeholder="pub-1234567890123456" autocomplete="off" spellcheck="false" required> 99 <span class="contai-help-text"><?php esc_html_e( 'Find it in your Google AdSense account under Account > Account information', '1platform-content-ai' ); ?></span> 106 <div class="contai-input-wrap contai-input-icon"> 107 <span class="dashicons dashicons-money-alt"></span> 108 <input type="text" id="contai_adsense_publisher" name="contai_adsense_publisher" class="contai-input" placeholder="pub-1234567890123456" autocomplete="off" spellcheck="false" required> 109 </div> 110 <span class="contai-help-text"><?php esc_html_e( 'Account > Account information in AdSense', '1platform-content-ai' ); ?></span> 100 111 </div> 101 112 </div> … … 104 115 105 116 <!-- Step 2: Legal Information --> 106 <div class="contai-wizard-section" >117 <div class="contai-wizard-section" data-step="2"> 107 118 <div class="contai-section-header"> 108 119 <div class="contai-step-indicator"> 109 120 <span class="contai-step-number">2</span> 121 <span class="contai-step-line"></span> 110 122 </div> 111 123 <div class="contai-section-title-group"> 112 <h2 class="contai-section-title"><?php esc_html_e( 'Legal Information', '1platform-content-ai' ); ?></h2> 124 <h2 class="contai-section-title"> 125 <span class="dashicons dashicons-shield contai-section-icon"></span> 126 <?php esc_html_e( 'Legal Information', '1platform-content-ai' ); ?> 127 </h2> 113 128 <p class="contai-section-description"><?php esc_html_e( 'Used to generate privacy policy, terms of service, and cookie consent.', '1platform-content-ai' ); ?></p> 114 129 </div> 115 130 </div> 116 131 <div class="contai-section-body"> 117 <div class="contai-form-grid contai-grid- 3">132 <div class="contai-form-grid contai-grid-2"> 118 133 <div class="contai-form-group"> 119 134 <label for="contai_legal_owner" class="contai-label"> … … 121 136 <span class="contai-required">*</span> 122 137 </label> 123 <input type="text" id="contai_legal_owner" name="contai_legal_owner" class="contai-input" placeholder="<?php esc_attr_e( 'John Doe', '1platform-content-ai' ); ?>" autocomplete="name" required> 138 <div class="contai-input-wrap contai-input-icon"> 139 <span class="dashicons dashicons-businessperson"></span> 140 <input type="text" id="contai_legal_owner" name="contai_legal_owner" class="contai-input" placeholder="<?php esc_attr_e( 'John Doe', '1platform-content-ai' ); ?>" autocomplete="name" required> 141 </div> 124 142 </div> 125 143 … … 129 147 <span class="contai-required">*</span> 130 148 </label> 131 <input type="email" id="contai_legal_email" name="contai_legal_email" class="contai-input" placeholder="<?php esc_attr_e( 'contact@example.com', '1platform-content-ai' ); ?>" autocomplete="email" spellcheck="false" required> 149 <div class="contai-input-wrap contai-input-icon"> 150 <span class="dashicons dashicons-email"></span> 151 <input type="email" id="contai_legal_email" name="contai_legal_email" class="contai-input" value="<?php echo esc_attr( $default_email ); ?>" placeholder="<?php esc_attr_e( 'info@domain.com', '1platform-content-ai' ); ?>" autocomplete="email" spellcheck="false" required> 152 </div> 132 153 </div> 133 154 … … 137 158 <span class="contai-required">*</span> 138 159 </label> 139 <input type="text" id="contai_legal_activity" name="contai_legal_activity" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., Digital publishing', '1platform-content-ai' ); ?>" autocomplete="organization-title" required> 140 </div> 141 142 <div class="contai-form-group contai-span-full"> 160 <div class="contai-input-wrap contai-input-icon"> 161 <span class="dashicons dashicons-building"></span> 162 <input type="text" id="contai_legal_activity" name="contai_legal_activity" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., Digital publishing', '1platform-content-ai' ); ?>" autocomplete="organization-title" required> 163 </div> 164 </div> 165 166 <div class="contai-form-group"> 143 167 <label for="contai_legal_address" class="contai-label"> 144 168 <?php esc_html_e( 'Business Address', '1platform-content-ai' ); ?> 145 169 <span class="contai-required">*</span> 146 170 </label> 147 <input type="text" id="contai_legal_address" name="contai_legal_address" class="contai-input" placeholder="<?php esc_attr_e( '123 Main St, City, Country', '1platform-content-ai' ); ?>" autocomplete="street-address" required> 171 <div class="contai-input-wrap contai-input-icon"> 172 <span class="dashicons dashicons-location"></span> 173 <input type="text" id="contai_legal_address" name="contai_legal_address" class="contai-input" placeholder="<?php esc_attr_e( '123 Main St, City, Country', '1platform-content-ai' ); ?>" autocomplete="street-address" required> 174 </div> 148 175 </div> 149 176 </div> … … 152 179 153 180 <!-- Step 3: Content Generation Settings --> 154 <div class="contai-wizard-section" >181 <div class="contai-wizard-section" data-step="3"> 155 182 <div class="contai-section-header"> 156 183 <div class="contai-step-indicator"> … … 158 185 </div> 159 186 <div class="contai-section-title-group"> 160 <h2 class="contai-section-title"><?php esc_html_e( 'Content Generation', '1platform-content-ai' ); ?></h2> 187 <h2 class="contai-section-title"> 188 <span class="dashicons dashicons-admin-post contai-section-icon"></span> 189 <?php esc_html_e( 'Content Generation', '1platform-content-ai' ); ?> 190 </h2> 161 191 <p class="contai-section-description"><?php esc_html_e( 'Configure how AI generates your website content, keywords, and images.', '1platform-content-ai' ); ?></p> 162 192 </div> 163 193 </div> 164 194 <div class="contai-section-body"> 165 <div class="contai-form-grid contai-grid- 3">195 <div class="contai-form-grid contai-grid-2"> 166 196 <div class="contai-form-group contai-span-full"> 167 <label for="contai_source_url" class="contai-label"> 168 <?php esc_html_e( 'Competitor Website (for keyword extraction)', '1platform-content-ai' ); ?> 169 <span class="contai-required">*</span> 170 </label> 171 <input type="url" id="contai_source_url" name="contai_source_url" class="contai-input" placeholder="https://example.com" autocomplete="url" spellcheck="false" required> 172 <span class="contai-help-text"><?php esc_html_e( 'We\'ll analyze this site to extract relevant keywords for your content.', '1platform-content-ai' ); ?></span> 197 <label for="contai_source_topic" class="contai-label"> 198 <?php esc_html_e( 'Keyword Topic', '1platform-content-ai' ); ?> 199 <span class="contai-required">*</span> 200 </label> 201 <div class="contai-input-wrap contai-input-icon"> 202 <span class="dashicons dashicons-search"></span> 203 <input type="text" id="contai_source_topic" name="contai_source_topic" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., indoor plants care, home workout routines...', '1platform-content-ai' ); ?>" autocomplete="off" spellcheck="false" required> 204 </div> 205 <span class="contai-help-text"><?php esc_html_e( 'We\'ll research this topic to extract relevant keywords for your content.', '1platform-content-ai' ); ?></span> 173 206 </div> 174 207 … … 191 224 <div class="contai-form-group"> 192 225 <label for="contai_image_provider" class="contai-label"> 193 <?php esc_html_e( 'Image Provider', '1platform-content-ai' ); ?>226 <?php esc_html_e( 'Image Source', '1platform-content-ai' ); ?> 194 227 <span class="contai-required">*</span> 195 228 </label> … … 206 239 <div class="contai-wizard-section contai-wizard-submit"> 207 240 <div class="contai-section-body"> 208 <div class="contai-notice contai-notice-info"> 209 <span class="dashicons dashicons-clock"></span> 210 <div> 211 <strong><?php esc_html_e( 'Background Process', '1platform-content-ai' ); ?></strong> 212 <p><?php esc_html_e( 'This process runs in the background and may take several hours depending on the number of posts. You can safely close this page and check back later.', '1platform-content-ai' ); ?></p> 213 </div> 214 </div> 215 216 <div class="contai-submit-area"> 217 <button type="submit" id="contai_submit_btn" class="contai-btn contai-btn-primary contai-btn-lg"> 218 <span class="dashicons dashicons-controls-play"></span> 219 <?php esc_html_e( 'Start Site Generation', '1platform-content-ai' ); ?> 220 </button> 241 <div class="contai-launch-card"> 242 <div class="contai-launch-info"> 243 <div class="contai-launch-icon"> 244 <span class="dashicons dashicons-clock"></span> 245 </div> 246 <div class="contai-launch-text"> 247 <strong><?php esc_html_e( 'Background Process', '1platform-content-ai' ); ?></strong> 248 <p><?php esc_html_e( 'Generation runs in the background. You can safely close this page and check progress later.', '1platform-content-ai' ); ?></p> 249 </div> 250 </div> 251 <div class="contai-submit-area"> 252 <button type="submit" id="contai_submit_btn" class="contai-btn contai-btn-primary contai-btn-lg"> 253 <span class="dashicons dashicons-controls-play"></span> 254 <?php esc_html_e( 'Launch Site Generation', '1platform-content-ai' ); ?> 255 </button> 256 </div> 221 257 </div> 222 258 </div> -
1platform-content-ai/tags/2.9.0/includes/admin/assets/css/admin-ai-site-generator.css
r3488242 r3490375 1 1 /* ======================================================== 2 Site Wizard - Modern Admin UI 2 Site Wizard — Refined Admin UI 3 Design: Precision minimalism with connected timeline 3 4 ======================================================== */ 4 5 5 6 /* -- Wizard Wrapper -- */ 6 7 .contai-wizard-wrap { 7 max-width: 960px;8 margin: 2 0px auto 40px;8 max-width: 860px; 9 margin: 24px auto 48px; 9 10 padding: 0; 10 11 background: transparent; … … 16 17 /* -- Hero Header -- */ 17 18 .contai-wizard-header { 18 background: linear-gradient(135deg, # 1e3a5f 0%, var(--contai-primary) 50%, var(--contai-primary-light) 100%);19 background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 40%, var(--contai-primary) 100%); 19 20 border-radius: var(--contai-radius-lg) var(--contai-radius-lg) 0 0; 20 padding: 3 2px 36px;21 padding: 36px 40px; 21 22 margin-bottom: 0; 22 23 position: relative; … … 27 28 content: ''; 28 29 position: absolute; 29 top: -40%; 30 right: -10%; 31 width: 300px; 32 height: 300px; 33 background: radial-gradient(circle, rgba(255,255,255,0.08) 0%, transparent 70%); 34 border-radius: 50%; 30 inset: 0; 31 background: 32 radial-gradient(ellipse 600px 400px at 80% 20%, rgba(59, 130, 246, 0.2) 0%, transparent 70%), 33 radial-gradient(ellipse 300px 300px at 20% 80%, rgba(37, 99, 235, 0.1) 0%, transparent 70%); 35 34 pointer-events: none; 36 35 } … … 39 38 content: ''; 40 39 position: absolute; 41 bottom: -60%; 42 left: 20%; 43 width: 200px; 44 height: 200px; 45 background: radial-gradient(circle, rgba(255,255,255,0.05) 0%, transparent 70%); 46 border-radius: 50%; 40 inset: 0; 41 background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 47 42 pointer-events: none; 48 43 } … … 57 52 58 53 .contai-wizard-icon { 59 width: 5 6px;60 height: 5 6px;61 background: rgba(255, 255, 255, 0.1 5);62 border-radius: 14px;54 width: 52px; 55 height: 52px; 56 background: rgba(255, 255, 255, 0.1); 57 border-radius: var(--contai-radius-lg); 63 58 display: flex; 64 59 align-items: center; 65 60 justify-content: center; 66 61 flex-shrink: 0; 67 backdrop-filter: blur(1 0px);68 border: 1px solid rgba(255, 255, 255, 0. 2);62 backdrop-filter: blur(12px); 63 border: 1px solid rgba(255, 255, 255, 0.15); 69 64 } 70 65 71 66 .contai-wizard-icon .dashicons { 72 font-size: 2 8px;73 width: 2 8px;74 height: 2 8px;67 font-size: 26px; 68 width: 26px; 69 height: 26px; 75 70 color: #fff; 76 71 } 77 72 78 73 .contai-wizard-header-text h1 { 79 margin: 0 0 6px 0;80 font-size: 2 6px;74 margin: 0 0 4px 0; 75 font-size: 22px; 81 76 font-weight: 700; 82 77 color: #fff; 83 letter-spacing: -0. 3px;78 letter-spacing: -0.4px; 84 79 line-height: 1.2; 85 80 padding: 0; … … 88 83 .contai-wizard-header-text p { 89 84 margin: 0; 90 color: rgba(255, 255, 255, 0. 85);91 font-size: 1 4px;85 color: rgba(255, 255, 255, 0.7); 86 font-size: 13.5px; 92 87 line-height: 1.5; 93 max-width: 520px;88 max-width: 480px; 94 89 } 95 90 96 91 /* -- Form Container -- */ 97 92 .contai-site-generator-form { 98 background: var(--contai-neutral- 100);93 background: var(--contai-neutral-50); 99 94 border-radius: 0 0 var(--contai-radius-lg) var(--contai-radius-lg); 100 padding: 28px;95 padding: 32px; 101 96 display: flex; 102 97 flex-direction: column; 103 gap: 24px;98 gap: 0; 104 99 } 105 100 … … 107 102 .contai-wizard-section { 108 103 background: #fff; 109 border-radius: var(--contai-radius- md);104 border-radius: var(--contai-radius-lg); 110 105 border: 1px solid var(--contai-neutral-200); 111 106 overflow: hidden; 112 transition: box-shadow var(--contai-duration-fast) ease; 107 transition: border-color var(--contai-duration-fast) ease, 108 box-shadow var(--contai-duration-fast) ease; 109 margin-bottom: 0; 110 position: relative; 111 } 112 113 .contai-wizard-section:not(.contai-wizard-submit) { 114 margin-bottom: 24px; 113 115 } 114 116 115 117 .contai-wizard-section:hover { 118 border-color: var(--contai-neutral-300); 116 119 box-shadow: var(--contai-shadow-sm); 117 120 } 118 121 119 /* -- Section Header with Step Indicator -- */ 122 .contai-wizard-section:focus-within { 123 border-color: var(--contai-primary-border); 124 box-shadow: 0 0 0 3px var(--contai-primary-glow), var(--contai-shadow-sm); 125 } 126 127 /* -- Section Header with Timeline -- */ 120 128 .contai-section-header { 121 129 display: flex; 122 130 align-items: flex-start; 123 131 gap: 16px; 124 padding: 20px 24px ;125 b order-bottom: 1px solid var(--contai-neutral-200);126 b ackground: var(--contai-neutral-50);132 padding: 20px 24px 16px; 133 background: #fff; 134 border-bottom: none; 127 135 } 128 136 129 137 .contai-step-indicator { 138 display: flex; 139 flex-direction: column; 140 align-items: center; 130 141 flex-shrink: 0; 142 gap: 0; 131 143 } 132 144 … … 135 147 align-items: center; 136 148 justify-content: center; 137 width: 3 6px;138 height: 3 6px;139 background: linear-gradient(135deg, var(--contai-primary), var(--contai-primary-dark));149 width: 32px; 150 height: 32px; 151 background: var(--contai-primary); 140 152 color: #fff; 141 border-radius: var(--contai-radius-md);142 font-size: 1 5px;153 border-radius: 50%; 154 font-size: 13px; 143 155 font-weight: 700; 144 156 line-height: 1; 157 position: relative; 158 z-index: 1; 159 box-shadow: 0 0 0 4px var(--contai-primary-glow); 160 } 161 162 .contai-step-line { 163 display: block; 164 width: 2px; 165 height: 16px; 166 background: var(--contai-neutral-200); 167 margin-top: 4px; 145 168 } 146 169 … … 148 171 flex: 1; 149 172 min-width: 0; 150 padding-top: 2px;173 padding-top: 4px; 151 174 } 152 175 153 176 .contai-section-title { 154 margin: 0 0 4px 0;155 font-size: 1 7px;156 font-weight: 6 00;177 margin: 0 0 2px 0; 178 font-size: 15px; 179 font-weight: 650; 157 180 color: var(--contai-neutral-700); 158 181 line-height: 1.3; 182 letter-spacing: -0.2px; 183 display: flex; 184 align-items: center; 185 gap: 8px; 186 } 187 188 .contai-section-icon { 189 font-size: 17px; 190 width: 17px; 191 height: 17px; 192 color: var(--contai-primary); 193 opacity: 0.85; 159 194 } 160 195 161 196 .contai-section-description { 162 197 margin: 0; 163 color: var(--contai-neutral- 500);164 font-size: 1 3px;198 color: var(--contai-neutral-400); 199 font-size: 12.5px; 165 200 line-height: 1.5; 166 201 } … … 168 203 /* -- Section Body -- */ 169 204 .contai-section-body { 170 padding: 24px;205 padding: 4px 24px 24px; 171 206 } 172 207 … … 174 209 .contai-form-grid { 175 210 display: grid; 176 gap: 20px; 211 gap: 18px; 212 } 213 214 .contai-grid-2 { 215 grid-template-columns: repeat(2, 1fr); 177 216 } 178 217 … … 189 228 } 190 229 191 /* -- Form Divider -- */192 .contai-form-divider {193 height: 1px;194 background: var(--contai-neutral-200);195 margin: 8px 0;196 }197 198 230 /* -- Form Group -- */ 199 231 .contai-form-group { … … 206 238 align-items: center; 207 239 gap: 4px; 208 font-weight: 600;209 font-size: 1 3px;240 font-weight: 550; 241 font-size: 12.5px; 210 242 margin-bottom: 6px; 211 color: var(--contai-neutral- 700);243 color: var(--contai-neutral-600); 212 244 line-height: 1.4; 245 letter-spacing: 0.01em; 246 text-transform: uppercase; 213 247 } 214 248 … … 216 250 color: var(--contai-error); 217 251 font-weight: 700; 218 font-size: 14px; 252 font-size: 13px; 253 } 254 255 /* -- Input Wrapper with Icon -- */ 256 .contai-input-wrap { 257 position: relative; 258 display: flex; 259 align-items: center; 260 } 261 262 .contai-input-icon > .dashicons { 263 position: absolute; 264 left: 12px; 265 top: 50%; 266 transform: translateY(-50%); 267 font-size: 16px; 268 width: 16px; 269 height: 16px; 270 color: var(--contai-neutral-400); 271 pointer-events: none; 272 transition: color var(--contai-duration-fast) ease; 273 z-index: 1; 274 } 275 276 .contai-input-icon > .contai-input { 277 padding-left: 38px; 278 } 279 280 .contai-input-icon:focus-within > .dashicons { 281 color: var(--contai-primary); 219 282 } 220 283 … … 223 286 .contai-select { 224 287 width: 100%; 225 padding: 10px 14px;226 border: 1.5px solid var(--contai-neutral- 300);227 border-radius: var(--contai-radius- lg);228 font-size: 1 4px;288 padding: 9px 13px; 289 border: 1.5px solid var(--contai-neutral-200); 290 border-radius: var(--contai-radius-md); 291 font-size: 13.5px; 229 292 font-family: inherit; 230 293 color: var(--contai-neutral-700); 231 background: #fff; 232 transition: border-color var(--contai-duration-fast) ease, box-shadow var(--contai-duration-fast) ease; 294 background: var(--contai-neutral-50); 295 transition: border-color var(--contai-duration-fast) ease, 296 box-shadow var(--contai-duration-fast) ease, 297 background-color var(--contai-duration-fast) ease; 233 298 -webkit-appearance: none; 234 299 appearance: none; 235 300 box-sizing: border-box; 301 line-height: 1.5; 236 302 } 237 303 238 304 .contai-select { 239 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23 646970' d='M6 8.825L1.175 4 2.238 2.938 6 6.7l3.763-3.763L10.825 4z'/%3E%3C/svg%3E");305 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M6 8.825L1.175 4 2.238 2.938 6 6.7l3.763-3.763L10.825 4z'/%3E%3C/svg%3E"); 240 306 background-repeat: no-repeat; 241 background-position: right 1 4px center;307 background-position: right 12px center; 242 308 background-size: 12px; 243 padding-right: 36px; 309 background-color: var(--contai-neutral-50); 310 padding-right: 34px; 244 311 cursor: pointer; 245 312 } … … 247 314 .contai-input::placeholder { 248 315 color: var(--contai-neutral-400); 316 font-weight: 400; 249 317 } 250 318 251 319 .contai-input:hover, 252 320 .contai-select:hover { 253 border-color: var(--contai-neutral-400); 321 border-color: var(--contai-neutral-300); 322 background: #fff; 254 323 } 255 324 … … 258 327 outline: none; 259 328 border-color: var(--contai-primary); 329 background: #fff; 260 330 box-shadow: 0 0 0 3px var(--contai-primary-glow); 331 } 332 333 /* Number input refinement */ 334 .contai-input[type="number"] { 335 font-variant-numeric: tabular-nums; 336 font-family: var(--contai-font-mono); 337 font-size: 13px; 338 letter-spacing: -0.01em; 261 339 } 262 340 … … 264 342 .contai-input-error { 265 343 border-color: var(--contai-error) !important; 266 box-shadow: 0 0 0 3px rgba(220, 38, 38, 0. 1) !important;344 box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.08) !important; 267 345 } 268 346 … … 270 348 display: block; 271 349 color: var(--contai-error); 272 font-size: 1 2px;350 font-size: 11.5px; 273 351 margin-top: 5px; 274 352 font-weight: 500; … … 279 357 .contai-help-text { 280 358 display: block; 281 color: var(--contai-neutral-500); 359 color: var(--contai-neutral-400); 360 font-size: 11.5px; 361 margin-top: 5px; 362 line-height: 1.5; 363 } 364 365 /* -- Launch Card (Submit Section) -- */ 366 .contai-wizard-submit { 367 border: none; 368 background: transparent; 369 box-shadow: none !important; 370 margin-top: 4px; 371 } 372 373 .contai-wizard-submit:hover { 374 box-shadow: none !important; 375 border-color: transparent !important; 376 } 377 378 .contai-wizard-submit:focus-within { 379 box-shadow: none !important; 380 border-color: transparent !important; 381 } 382 383 .contai-wizard-submit .contai-section-body { 384 padding: 0; 385 } 386 387 .contai-launch-card { 388 display: flex; 389 align-items: center; 390 justify-content: space-between; 391 gap: 24px; 392 padding: 20px 24px; 393 background: linear-gradient(135deg, var(--contai-neutral-700) 0%, #1e3a5f 100%); 394 border-radius: var(--contai-radius-lg); 395 position: relative; 396 overflow: hidden; 397 } 398 399 .contai-launch-card::before { 400 content: ''; 401 position: absolute; 402 inset: 0; 403 background: 404 radial-gradient(ellipse 300px 200px at 90% 50%, rgba(37, 99, 235, 0.15) 0%, transparent 70%); 405 pointer-events: none; 406 } 407 408 .contai-launch-info { 409 display: flex; 410 align-items: center; 411 gap: 14px; 412 position: relative; 413 z-index: 1; 414 flex: 1; 415 min-width: 0; 416 } 417 418 .contai-launch-icon { 419 width: 40px; 420 height: 40px; 421 background: rgba(255, 255, 255, 0.1); 422 border-radius: 50%; 423 display: flex; 424 align-items: center; 425 justify-content: center; 426 flex-shrink: 0; 427 border: 1px solid rgba(255, 255, 255, 0.1); 428 } 429 430 .contai-launch-icon .dashicons { 431 font-size: 18px; 432 width: 18px; 433 height: 18px; 434 color: rgba(255, 255, 255, 0.7); 435 } 436 437 .contai-launch-text { 438 flex: 1; 439 min-width: 0; 440 } 441 442 .contai-launch-text strong { 443 display: block; 444 color: #fff; 445 font-size: 13px; 446 font-weight: 600; 447 margin-bottom: 1px; 448 } 449 450 .contai-launch-text p { 451 margin: 0; 452 color: rgba(255, 255, 255, 0.55); 282 453 font-size: 12px; 283 margin-top: 6px;284 454 line-height: 1.5; 285 455 } 286 456 287 /* -- Info Notice -- */ 457 .contai-launch-card .contai-submit-area { 458 position: relative; 459 z-index: 1; 460 flex-shrink: 0; 461 } 462 463 /* -- Buttons -- */ 464 .contai-btn { 465 display: inline-flex; 466 align-items: center; 467 justify-content: center; 468 gap: 8px; 469 padding: 10px 24px; 470 font-size: 13px; 471 font-weight: 600; 472 font-family: inherit; 473 border: none; 474 border-radius: var(--contai-radius-md); 475 cursor: pointer; 476 transition: all var(--contai-duration-fast) var(--contai-ease); 477 line-height: 1; 478 text-decoration: none; 479 white-space: nowrap; 480 } 481 482 .contai-btn .dashicons { 483 font-size: 16px; 484 width: 16px; 485 height: 16px; 486 } 487 488 .contai-btn-primary { 489 background: #fff; 490 color: var(--contai-neutral-700); 491 box-shadow: var(--contai-shadow-sm); 492 } 493 494 .contai-btn-primary:hover { 495 background: #fff; 496 color: var(--contai-primary); 497 box-shadow: var(--contai-shadow-md), 0 0 0 1px rgba(255, 255, 255, 0.1); 498 transform: translateY(-1px); 499 } 500 501 .contai-btn-primary:active { 502 transform: translateY(0); 503 box-shadow: var(--contai-shadow-xs); 504 } 505 506 .contai-btn-lg { 507 padding: 12px 28px; 508 font-size: 13.5px; 509 border-radius: var(--contai-radius-md); 510 } 511 512 .contai-btn:disabled, 513 .contai-btn-loading { 514 opacity: 0.7; 515 cursor: not-allowed; 516 transform: none !important; 517 } 518 519 /* -- Spinner -- */ 520 .contai-spinning { 521 animation: contai-spin 1s linear infinite; 522 } 523 524 @keyframes contai-spin { 525 from { transform: rotate(0deg); } 526 to { transform: rotate(360deg); } 527 } 528 529 /* -- Legacy Notice (keep for backward compat) -- */ 288 530 .contai-notice { 289 531 display: flex; … … 323 565 } 324 566 325 /* -- Submit Area -- */326 .contai-submit-area {327 display: flex;328 justify-content: flex-end;329 }330 331 /* -- Buttons -- */332 .contai-btn {333 display: inline-flex;334 align-items: center;335 justify-content: center;336 gap: 8px;337 padding: 12px 28px;338 font-size: 14px;339 font-weight: 600;340 font-family: inherit;341 border: none;342 border-radius: var(--contai-radius-lg);343 cursor: pointer;344 transition: all var(--contai-duration-fast) ease;345 line-height: 1;346 text-decoration: none;347 }348 349 .contai-btn .dashicons {350 font-size: 18px;351 width: 18px;352 height: 18px;353 }354 355 .contai-btn-primary {356 background: linear-gradient(135deg, var(--contai-primary), var(--contai-primary-dark));357 color: #fff;358 box-shadow: var(--contai-shadow-md);359 }360 361 .contai-btn-primary:hover {362 background: linear-gradient(135deg, var(--contai-primary-dark), var(--contai-primary-darker));363 box-shadow: var(--contai-shadow-lg);364 color: #fff;365 transform: translateY(-1px);366 }367 368 .contai-btn-primary:active {369 transform: translateY(0);370 box-shadow: var(--contai-shadow-sm);371 }372 373 .contai-btn-lg {374 padding: 14px 36px;375 font-size: 15px;376 }377 378 .contai-btn:disabled,379 .contai-btn-loading {380 opacity: 0.75;381 cursor: not-allowed;382 transform: none !important;383 }384 385 /* -- Spinner -- */386 .contai-spinning {387 animation: contai-spin 1s linear infinite;388 }389 390 @keyframes contai-spin {391 from { transform: rotate(0deg); }392 to { transform: rotate(360deg); }393 }394 395 /* -- Submit Section Override -- */396 .contai-wizard-submit {397 border: none;398 background: transparent;399 box-shadow: none;400 }401 402 .contai-wizard-submit:hover {403 box-shadow: none;404 }405 406 .contai-wizard-submit .contai-section-body {407 padding: 0;408 }409 410 567 /* -- Progress Section (Active Job) -- */ 411 568 .contai-settings-panel { … … 450 607 .contai-progress-bar { 451 608 width: 100%; 452 height: 1 2px;609 height: 10px; 453 610 background-color: var(--contai-neutral-200); 454 border-radius: var(--contai-radius- md);611 border-radius: var(--contai-radius-pill); 455 612 overflow: hidden; 456 613 margin-bottom: 10px; … … 460 617 height: 100%; 461 618 background: linear-gradient(90deg, var(--contai-primary), var(--contai-primary-light)); 462 border-radius: var(--contai-radius- md);463 transition: width 0. 3s ease;619 border-radius: var(--contai-radius-pill); 620 transition: width 0.4s var(--contai-ease); 464 621 } 465 622 … … 467 624 text-align: center; 468 625 font-weight: 600; 469 font-size: 1 4px;626 font-size: 13px; 470 627 color: var(--contai-neutral-700); 628 font-variant-numeric: tabular-nums; 471 629 } 472 630 … … 484 642 display: inline-block; 485 643 padding: 3px 10px; 486 border-radius: 20px;644 border-radius: var(--contai-radius-pill); 487 645 font-weight: 600; 488 646 text-transform: uppercase; 489 font-size: 1 1px;490 letter-spacing: 0. 3px;647 font-size: 10.5px; 648 letter-spacing: 0.4px; 491 649 } 492 650 … … 517 675 .contai-completed-steps h3 { 518 676 margin: 0 0 12px; 519 font-size: 1 4px;677 font-size: 13px; 520 678 font-weight: 600; 521 679 color: var(--contai-neutral-700); 680 text-transform: uppercase; 681 letter-spacing: 0.02em; 522 682 } 523 683 … … 543 703 544 704 .contai-completed-steps li .dashicons { 545 color: #00a32a;705 color: var(--contai-success); 546 706 font-size: 18px; 547 707 width: 18px; … … 562 722 background: linear-gradient(135deg, var(--contai-primary), var(--contai-primary-dark)); 563 723 border: none; 564 border-radius: var(--contai-radius- lg);724 border-radius: var(--contai-radius-md); 565 725 color: #fff; 566 726 font-size: 13px; … … 660 820 } 661 821 822 .contai-grid-2, 662 823 .contai-grid-3 { 663 824 grid-template-columns: repeat(2, 1fr); … … 670 831 .contai-span-2 { 671 832 grid-column: 1 / -1; 833 } 834 835 .contai-launch-card { 836 flex-direction: column; 837 align-items: stretch; 838 text-align: center; 839 } 840 841 .contai-launch-info { 842 flex-direction: column; 843 } 844 845 .contai-submit-area { 846 display: flex; 847 justify-content: center; 672 848 } 673 849 } … … 690 866 691 867 .contai-wizard-header-text h1 { 692 font-size: 2 2px;868 font-size: 20px; 693 869 } 694 870 … … 700 876 border-radius: 0; 701 877 padding: 16px; 702 gap: 16px; 703 } 704 705 .contai-wizard-section { 706 border-radius: var(--contai-radius-lg); 878 } 879 880 .contai-wizard-section:not(.contai-wizard-submit) { 881 margin-bottom: 16px; 707 882 } 708 883 709 884 .contai-section-header { 710 padding: 16px ;885 padding: 16px 16px 12px; 711 886 } 712 887 713 888 .contai-section-body { 714 padding: 16px; 715 } 716 889 padding: 4px 16px 16px; 890 } 891 892 .contai-grid-2, 717 893 .contai-grid-3 { 718 894 grid-template-columns: 1fr; … … 726 902 .contai-select { 727 903 font-size: 16px; 728 padding: 1 2px 14px;729 } 730 731 .contai- submit-area{732 justify-content: stretch;904 padding: 11px 13px; 905 } 906 907 .contai-input-icon > .contai-input { 908 padding-left: 38px; 733 909 } 734 910 735 911 .contai-btn-lg { 736 912 width: 100%; 737 } 738 } 913 justify-content: center; 914 } 915 916 .contai-launch-card { 917 padding: 16px; 918 flex-direction: column; 919 gap: 16px; 920 } 921 922 .contai-launch-info { 923 flex-direction: column; 924 text-align: center; 925 } 926 927 .contai-submit-area { 928 display: flex; 929 } 930 931 .contai-submit-area .contai-btn { 932 width: 100%; 933 } 934 } -
1platform-content-ai/tags/2.9.0/includes/admin/content-generator/handlers/KeywordExtractionHandler.php
r3483422 r3490375 100 100 101 101 $payload = [ 102 ' domain' => $validation['domain'],102 'topic' => $validation['topic'], 103 103 'country' => $validation['country'], 104 'lang' => $validation['lang'] 104 'lang' => $validation['lang'], 105 105 ]; 106 106 … … 123 123 'success' => true, 124 124 'message' => sprintf( 125 /* translators: %s: domainname for keyword extraction */126 __('Keyword extraction job has been queued . Domain: %s. You can check the Keywords List page for results.', '1platform-content-ai'),127 $validation[' domain']125 /* translators: %s: topic name for keyword extraction */ 126 __('Keyword extraction job has been queued for: %s. You can check the Keywords List page for results.', '1platform-content-ai'), 127 $validation['topic'] 128 128 ) 129 129 ]; … … 132 132 private function validateExtractionRequest(): array { 133 133 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified in handleRequest() via verifyNonce(). 134 $ domain = esc_url_raw(wp_unslash($_POST['contai_source_url'] ?? ''));134 $topic = sanitize_text_field(wp_unslash($_POST['contai_topic'] ?? '')); 135 135 $country = sanitize_text_field(wp_unslash($_POST['contai_country'] ?? '')); 136 136 $lang = sanitize_text_field(wp_unslash($_POST['contai_target_language'] ?? '')); 137 137 // phpcs:enable WordPress.Security.NonceVerification.Missing 138 138 139 if (empty($domain) || empty($country) || empty($lang)) { 140 return [ 141 'valid' => false, 142 'message' => __('Please fill in all required fields.', '1platform-content-ai') 143 ]; 139 if (empty($topic)) { 140 return ['valid' => false, 'message' => __('Please enter a topic for keyword discovery.', '1platform-content-ai')]; 144 141 } 145 146 if (!filter_var($domain, FILTER_VALIDATE_URL)) { 147 return [ 148 'valid' => false, 149 'message' => __('Please enter a valid URL.', '1platform-content-ai') 150 ]; 142 if (mb_strlen($topic) < 3 || mb_strlen($topic) > 200) { 143 return ['valid' => false, 'message' => __('Topic must be between 3 and 200 characters.', '1platform-content-ai')]; 151 144 } 152 145 153 146 $validLanguages = ['en', 'es']; 154 147 if (!in_array($lang, $validLanguages, true)) { 155 return [ 156 'valid' => false, 157 'message' => __('Invalid language selected.', '1platform-content-ai') 158 ]; 148 return ['valid' => false, 'message' => __('Invalid language selected.', '1platform-content-ai')]; 159 149 } 160 150 161 151 $validCountries = ['us', 'es']; 162 152 if (!in_array($country, $validCountries, true)) { 163 return [ 164 'valid' => false, 165 'message' => __('Invalid country selected.', '1platform-content-ai') 166 ]; 153 return ['valid' => false, 'message' => __('Invalid country selected.', '1platform-content-ai')]; 167 154 } 168 155 169 156 return [ 170 157 'valid' => true, 171 ' domain' => $domain,158 'topic' => $topic, 172 159 'country' => $country, 173 'lang' => $lang 160 'lang' => $lang, 174 161 ]; 175 162 } -
1platform-content-ai/tags/2.9.0/includes/admin/content-generator/panels/keyword-extractor.php
r3483422 r3490375 24 24 <div class="contai-form-grid contai-grid-2"> 25 25 <div class="contai-form-group"> 26 <label for="contai_ source_url" class="contai-label">27 <span class="dashicons dashicons- admin-site-alt3"></span>28 <?php esc_html_e(' Source Website', '1platform-content-ai'); ?>26 <label for="contai_topic" class="contai-label"> 27 <span class="dashicons dashicons-lightbulb"></span> 28 <?php esc_html_e('Topic / Theme', '1platform-content-ai'); ?> 29 29 </label> 30 <input type="url" id="contai_source_url" name="contai_source_url" required 31 class="contai-input" 32 placeholder="https://example.com" 30 <input type="text" id="contai_topic" name="contai_topic" 31 class="contai-input" required 32 placeholder="<?php esc_attr_e('e.g. plantas de interior, salud medioambiental', '1platform-content-ai'); ?>" 33 minlength="3" maxlength="200" 33 34 value="<?php 34 35 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Repopulating form field after submission; value is sanitized and escaped. 35 echo isset($_POST['contai_ source_url']) ? esc_attr( sanitize_text_field( wp_unslash( $_POST['contai_source_url'] ) ) ) : ''; ?>">36 echo isset($_POST['contai_topic']) ? esc_attr( sanitize_text_field( wp_unslash( $_POST['contai_topic'] ) ) ) : ''; ?>"> 36 37 <p class="contai-help-text"> 37 38 <span class="dashicons dashicons-info"></span> 38 <?php esc_html_e('Enter the competitor website URL to analyze', '1platform-content-ai'); ?>39 <?php esc_html_e('Enter a topic or theme to discover keywords from Google (2-4 words work best)', '1platform-content-ai'); ?> 39 40 </p> 40 41 </div> … … 199 200 <thead> 200 201 <tr> 201 <th><?php esc_html_e(' Domain', '1platform-content-ai'); ?></th>202 <th><?php esc_html_e('Topic', '1platform-content-ai'); ?></th> 202 203 <th><?php esc_html_e('Country', '1platform-content-ai'); ?></th> 203 204 <th><?php esc_html_e('Language', '1platform-content-ai'); ?></th> … … 215 216 216 217 private function renderJobRow(array $job): void { 217 $payload = json_decode($job['payload'], true) ;218 $ domain =$payload['domain'] ?? __('Unknown', '1platform-content-ai');218 $payload = json_decode($job['payload'], true) ?? []; 219 $topic = $payload['topic'] ?? $payload['domain'] ?? __('Unknown', '1platform-content-ai'); 219 220 $country = strtoupper($payload['country'] ?? 'N/A'); 220 221 $lang = strtoupper($payload['lang'] ?? 'N/A'); … … 222 223 ?> 223 224 <tr> 224 <td><strong><?php echo esc_html($ domain); ?></strong></td>225 <td><strong><?php echo esc_html($topic); ?></strong></td> 225 226 <td><?php echo esc_html($country); ?></td> 226 227 <td><?php echo esc_html($lang); ?></td> … … 234 235 } 235 236 236 private function calculateElapsedTime(string $processedAt): string { 237 $now = current_time('timestamp'); 237 private function calculateElapsedTime(?string $processedAt): string { 238 if (empty($processedAt)) { 239 return __('Just started', '1platform-content-ai'); 240 } 238 241 $processed = strtotime($processedAt); 239 $diff = $now - $processed; 242 if ($processed === false) { 243 return __('Unknown', '1platform-content-ai'); 244 } 245 $now = time(); 246 $diff = max(0, $now - $processed); 240 247 241 248 $minutes = floor($diff / 60); -
1platform-content-ai/tags/2.9.0/includes/services/api/OnePlatformEndpoints.php
r3483422 r3490375 53 53 // ── Content Generation ────────────────────────────────────── 54 54 const POSTS_KEYWORDS = '/posts/keywords/'; 55 const POSTS_KEYWORDS_TOPIC = '/posts/keywords/topic/'; 55 56 const POSTS_CONTENT = '/posts/content/'; 56 57 const POSTS_CONTENT_JOBS = '/posts/content/jobs/'; -
1platform-content-ai/tags/2.9.0/includes/services/jobs/KeywordExtractionJob.php
r3483422 r3490375 19 19 public function handle(array $payload) 20 20 { 21 $topic = $payload['topic'] ?? ''; 21 22 $domain = $payload['domain'] ?? ''; 22 23 $country = $payload['country'] ?? ''; 23 24 $lang = $payload['lang'] ?? ''; 24 25 25 if (empty($domain) || empty($country) || empty($lang)) { 26 // Support both topic-based (new) and domain-based (legacy) payloads 27 $source = !empty($topic) ? $topic : $domain; 28 29 if (empty($source) || empty($country) || empty($lang)) { 26 30 return [ 27 31 'success' => false, 28 'error' => 'Missing required parameters: domain, country, or lang'32 'error' => 'Missing required parameters: topic/domain, country, or lang' 29 33 ]; 30 34 } 31 35 32 $result = $this->extractor_service->extractAndSaveKeywords($domain, $country, $lang); 36 $result = !empty($topic) 37 ? $this->extractor_service->extractByTopicAndSave($topic, $country, $lang) 38 : $this->extractor_service->extractAndSaveKeywords($domain, $country, $lang); 33 39 34 40 if ($result->isSuccess()) { … … 38 44 'skipped_count' => $result->getSkippedCount(), 39 45 'total_count' => $result->getTotalCount(), 40 ' domain' => $domain46 'source' => $source, 41 47 ]; 42 48 } … … 45 51 'success' => false, 46 52 'error' => $result->getErrorMessage(), 47 ' domain' => $domain53 'source' => $source, 48 54 ]; 49 55 } -
1platform-content-ai/tags/2.9.0/includes/services/jobs/SiteGenerationJob.php
r3483422 r3490375 203 203 $service = ContaiKeywordExtractorService::create(); 204 204 205 $ domain = $extractionConfig['source_url'] ?? '';205 $topic = $extractionConfig['source_topic'] ?? ''; 206 206 $country = $extractionConfig['target_country'] ?? 'us'; 207 207 $lang = $extractionConfig['target_language'] ?? 'en'; 208 208 209 $result = $service->extract AndSaveKeywords($domain, $country, $lang);209 $result = $service->extractByTopicAndSave($topic, $country, $lang); 210 210 211 211 if (!$result->isSuccess()) { -
1platform-content-ai/tags/2.9.0/includes/services/keyword/KeywordExtractorService.php
r3483422 r3490375 57 57 } 58 58 59 public function extractByTopicAndSave( 60 string $topic, 61 string $country, 62 string $lang 63 ): ContaiKeywordExtractionResult { 64 $response = $this->requestKeywordExtractionByTopic($topic, $country, $lang); 65 66 if (!$response->isSuccess()) { 67 return ContaiKeywordExtractionResult::failure( 68 $response->getMessage() ?? self::ERROR_API_REQUEST_FAILED 69 ); 70 } 71 72 return $this->processAndSaveKeywords($response); 73 } 74 59 75 private function requestKeywordExtraction( 60 76 string $domain, … … 69 85 70 86 return $this->client->post(ContaiOnePlatformEndpoints::POSTS_KEYWORDS, $request_data); 87 } 88 89 private function requestKeywordExtractionByTopic( 90 string $topic, 91 string $country, 92 string $lang 93 ): ContaiOnePlatformResponse { 94 $request_data = [ 95 'topic' => $topic, 96 'country' => $country, 97 'lang' => $lang, 98 ]; 99 100 return $this->client->post(ContaiOnePlatformEndpoints::POSTS_KEYWORDS_TOPIC, $request_data); 71 101 } 72 102 -
1platform-content-ai/tags/2.9.0/readme.txt
r3488242 r3490375 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 2. 7.07 Stable tag: 2.9.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html -
1platform-content-ai/trunk/.git/FETCH_HEAD
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1branch 'main' of https://github.com/1platformlabs/1platform-content-ai1 d0f02faf2b07912251edc6729f937622150be15e branch 'main' of https://github.com/1platformlabs/1platform-content-ai -
1platform-content-ai/trunk/.git/ORIG_HEAD
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1 1 d0f02faf2b07912251edc6729f937622150be15e -
1platform-content-ai/trunk/.git/config
r3488242 r3490375 10 10 auto = 0 11 11 [http "https://github.com/"] 12 extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzX zZmZ1hBU01NQ25ORDF3aHA1aE5Rczl2dVpsRzBYMDNNcUZzVA==12 extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzX20yVVRQdDlDdEdZdjVHOXNDZ0ZlelJGTXExV0N0VTNsSHI0Sw== 13 13 [branch "main"] 14 14 remote = origin -
1platform-content-ai/trunk/.git/logs/HEAD
r3488242 r3490375 1 0000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052+0000 checkout: moving from master to main1 0000000000000000000000000000000000000000 d0f02faf2b07912251edc6729f937622150be15e runner <runner@runnervm46oaq.ajpjuzvd0pcu5m1ughqrvmkcxa.bx.internal.cloudapp.net> 1774387066 +0000 checkout: moving from master to main -
1platform-content-ai/trunk/.git/logs/refs/heads/main
r3488242 r3490375 1 0000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052+0000 branch: Created from refs/remotes/origin/main1 0000000000000000000000000000000000000000 d0f02faf2b07912251edc6729f937622150be15e runner <runner@runnervm46oaq.ajpjuzvd0pcu5m1ughqrvmkcxa.bx.internal.cloudapp.net> 1774387066 +0000 branch: Created from refs/remotes/origin/main -
1platform-content-ai/trunk/.git/logs/refs/remotes/origin/main
r3488242 r3490375 1 0000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052+0000 fetch --prune --no-recurse-submodules origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*: storing head1 0000000000000000000000000000000000000000 d0f02faf2b07912251edc6729f937622150be15e runner <runner@runnervm46oaq.ajpjuzvd0pcu5m1ughqrvmkcxa.bx.internal.cloudapp.net> 1774387066 +0000 fetch --prune --no-recurse-submodules origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*: storing head -
1platform-content-ai/trunk/.git/refs/heads/main
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1 1 d0f02faf2b07912251edc6729f937622150be15e -
1platform-content-ai/trunk/.git/refs/remotes/origin/main
r3488242 r3490375 1 0b507e94120943ce7672264963c81dd809d669f1 1 d0f02faf2b07912251edc6729f937622150be15e -
1platform-content-ai/trunk/1platform-content-ai.php
r3488242 r3490375 5 5 * Plugin URI: https://1platform.pro/ 6 6 * Description: SaaS client for AI-powered content generation, SEO optimization, and site management. All AI processing happens on 1Platform external servers. Includes free local tools: Table of Contents and Internal Links. 7 * Version: 2. 7.07 * Version: 2.9.0 8 8 * Author: 1Platform 9 9 * License: GPLv2 or later -
1platform-content-ai/trunk/includes/admin/admin-ai-site-generator.php
r3488242 r3490375 52 52 'page' => 'contai-ai-site-generator', 53 53 'error' => 1, 54 'message' => urlencode( 'Please select a category before starting the site generation process.' ),54 'message' => 'Please select a category before starting the site generation process.', 55 55 ), 56 56 admin_url( 'admin.php' ) … … 69 69 'page' => 'contai-ai-site-generator', 70 70 'error' => 1, 71 'message' => urlencode( 'There is already an active site generation process running.' ),71 'message' => 'There is already an active site generation process running.', 72 72 ), 73 73 admin_url( 'admin.php' ) … … 93 93 ), 94 94 'keyword_extraction' => array( 95 'source_ url' => esc_url_raw( wp_unslash( $_POST['contai_source_url'] ?? '' ) ),95 'source_topic' => sanitize_text_field( wp_unslash( $_POST['contai_source_topic'] ?? '' ) ), 96 96 'target_country' => sanitize_text_field( wp_unslash( $_POST['contai_target_country'] ?? 'us' ) ), 97 97 'target_language' => sanitize_text_field( wp_unslash( $_POST['contai_target_language'] ?? 'en' ) ), … … 129 129 'page' => 'contai-ai-site-generator', 130 130 'error' => 1, 131 'message' => urlencode( 'Failed to start site generation process.' ),131 'message' => 'Failed to start site generation process.', 132 132 ), 133 133 admin_url( 'admin.php' ) … … 141 141 if ( ! empty( $_POST['contai_site_category'] ) ) { 142 142 update_option( 'contai_site_category', sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ) ) ); 143 } 144 145 // Save AdSense publisher ID immediately so it appears in Ads Manager 146 // before the background job completes (fixes #12) 147 $adsense_publisher = sanitize_text_field( wp_unslash( $_POST['contai_adsense_publisher'] ?? '' ) ); 148 if ( ! empty( $adsense_publisher ) && preg_match( '/^pub-\d+$/', $adsense_publisher ) ) { 149 update_option( 'contai_adsense_publishers', $adsense_publisher ); 150 if ( function_exists( 'contai_generate_adsense_ads' ) ) { 151 contai_generate_adsense_ads(); 152 } 143 153 } 144 154 … … 170 180 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 171 181 $msg = isset( $_GET['message'] ) ? sanitize_text_field( wp_unslash( $_GET['message'] ) ) : 'Success'; 172 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( urldecode( $msg )) . '</p></div>';182 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $msg ) . '</p></div>'; 173 183 } 174 184 … … 177 187 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 178 188 $msg = isset( $_GET['message'] ) ? sanitize_text_field( wp_unslash( $_GET['message'] ) ) : 'Error'; 179 echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( urldecode( $msg )) . '</p></div>';189 echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $msg ) . '</p></div>'; 180 190 } 181 191 -
1platform-content-ai/trunk/includes/admin/ai-site-generator/site-generator-form.php
r3488242 r3490375 12 12 $categories = $category_service->getActiveCategories(); 13 13 $saved_category = get_option( 'contai_site_category', '' ); 14 $site_domain = wp_parse_url( home_url(), PHP_URL_HOST ); 15 $default_email = 'info@' . preg_replace( '/^www\./', '', $site_domain ); 14 16 15 17 ?> … … 17 19 <?php wp_nonce_field( 'contai_site_generator_nonce', 'contai_site_generator_nonce' ); ?> 18 20 <input type="hidden" name="contai_start_site_generation" value="1"> 19 20 21 <input type="hidden" id="contai_wordpress_theme" name="contai_wordpress_theme" value="astra"> 21 22 22 23 <!-- Step 1: Website Identity --> 23 <div class="contai-wizard-section" >24 <div class="contai-wizard-section" data-step="1"> 24 25 <div class="contai-section-header"> 25 26 <div class="contai-step-indicator"> 26 27 <span class="contai-step-number">1</span> 28 <span class="contai-step-line"></span> 27 29 </div> 28 30 <div class="contai-section-title-group"> 29 <h2 class="contai-section-title"><?php esc_html_e( 'Website Identity', '1platform-content-ai' ); ?></h2> 31 <h2 class="contai-section-title"> 32 <span class="dashicons dashicons-admin-site-alt3 contai-section-icon"></span> 33 <?php esc_html_e( 'Website Identity', '1platform-content-ai' ); ?> 34 </h2> 30 35 <p class="contai-section-description"><?php esc_html_e( 'Define what your website is about and who it targets.', '1platform-content-ai' ); ?></p> 31 36 </div> 32 37 </div> 33 38 <div class="contai-section-body"> 34 <div class="contai-form-grid contai-grid- 3">35 <div class="contai-form-group ">39 <div class="contai-form-grid contai-grid-2"> 40 <div class="contai-form-group contai-span-full"> 36 41 <label for="contai_site_topic" class="contai-label"> 37 42 <?php esc_html_e( 'Site Topic', '1platform-content-ai' ); ?> 38 43 <span class="contai-required">*</span> 39 44 </label> 40 <input type="text" id="contai_site_topic" name="contai_site_topic" class="contai-input" placeholder="e.g., Technology News" autocomplete="off" required> 45 <div class="contai-input-wrap contai-input-icon"> 46 <span class="dashicons dashicons-edit"></span> 47 <input type="text" id="contai_site_topic" name="contai_site_topic" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., Indoor gardening, Personal finance, Pet care...', '1platform-content-ai' ); ?>" autocomplete="off" required> 48 </div> 41 49 <span class="contai-help-text"><?php esc_html_e( 'The main subject of your website', '1platform-content-ai' ); ?></span> 42 50 </div> … … 91 99 </div> 92 100 93 <div class="contai-form-group contai-span-2">101 <div class="contai-form-group"> 94 102 <label for="contai_adsense_publisher" class="contai-label"> 95 103 <?php esc_html_e( 'AdSense Publisher ID', '1platform-content-ai' ); ?> 96 104 <span class="contai-required">*</span> 97 105 </label> 98 <input type="text" id="contai_adsense_publisher" name="contai_adsense_publisher" class="contai-input" placeholder="pub-1234567890123456" autocomplete="off" spellcheck="false" required> 99 <span class="contai-help-text"><?php esc_html_e( 'Find it in your Google AdSense account under Account > Account information', '1platform-content-ai' ); ?></span> 106 <div class="contai-input-wrap contai-input-icon"> 107 <span class="dashicons dashicons-money-alt"></span> 108 <input type="text" id="contai_adsense_publisher" name="contai_adsense_publisher" class="contai-input" placeholder="pub-1234567890123456" autocomplete="off" spellcheck="false" required> 109 </div> 110 <span class="contai-help-text"><?php esc_html_e( 'Account > Account information in AdSense', '1platform-content-ai' ); ?></span> 100 111 </div> 101 112 </div> … … 104 115 105 116 <!-- Step 2: Legal Information --> 106 <div class="contai-wizard-section" >117 <div class="contai-wizard-section" data-step="2"> 107 118 <div class="contai-section-header"> 108 119 <div class="contai-step-indicator"> 109 120 <span class="contai-step-number">2</span> 121 <span class="contai-step-line"></span> 110 122 </div> 111 123 <div class="contai-section-title-group"> 112 <h2 class="contai-section-title"><?php esc_html_e( 'Legal Information', '1platform-content-ai' ); ?></h2> 124 <h2 class="contai-section-title"> 125 <span class="dashicons dashicons-shield contai-section-icon"></span> 126 <?php esc_html_e( 'Legal Information', '1platform-content-ai' ); ?> 127 </h2> 113 128 <p class="contai-section-description"><?php esc_html_e( 'Used to generate privacy policy, terms of service, and cookie consent.', '1platform-content-ai' ); ?></p> 114 129 </div> 115 130 </div> 116 131 <div class="contai-section-body"> 117 <div class="contai-form-grid contai-grid- 3">132 <div class="contai-form-grid contai-grid-2"> 118 133 <div class="contai-form-group"> 119 134 <label for="contai_legal_owner" class="contai-label"> … … 121 136 <span class="contai-required">*</span> 122 137 </label> 123 <input type="text" id="contai_legal_owner" name="contai_legal_owner" class="contai-input" placeholder="<?php esc_attr_e( 'John Doe', '1platform-content-ai' ); ?>" autocomplete="name" required> 138 <div class="contai-input-wrap contai-input-icon"> 139 <span class="dashicons dashicons-businessperson"></span> 140 <input type="text" id="contai_legal_owner" name="contai_legal_owner" class="contai-input" placeholder="<?php esc_attr_e( 'John Doe', '1platform-content-ai' ); ?>" autocomplete="name" required> 141 </div> 124 142 </div> 125 143 … … 129 147 <span class="contai-required">*</span> 130 148 </label> 131 <input type="email" id="contai_legal_email" name="contai_legal_email" class="contai-input" placeholder="<?php esc_attr_e( 'contact@example.com', '1platform-content-ai' ); ?>" autocomplete="email" spellcheck="false" required> 149 <div class="contai-input-wrap contai-input-icon"> 150 <span class="dashicons dashicons-email"></span> 151 <input type="email" id="contai_legal_email" name="contai_legal_email" class="contai-input" value="<?php echo esc_attr( $default_email ); ?>" placeholder="<?php esc_attr_e( 'info@domain.com', '1platform-content-ai' ); ?>" autocomplete="email" spellcheck="false" required> 152 </div> 132 153 </div> 133 154 … … 137 158 <span class="contai-required">*</span> 138 159 </label> 139 <input type="text" id="contai_legal_activity" name="contai_legal_activity" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., Digital publishing', '1platform-content-ai' ); ?>" autocomplete="organization-title" required> 140 </div> 141 142 <div class="contai-form-group contai-span-full"> 160 <div class="contai-input-wrap contai-input-icon"> 161 <span class="dashicons dashicons-building"></span> 162 <input type="text" id="contai_legal_activity" name="contai_legal_activity" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., Digital publishing', '1platform-content-ai' ); ?>" autocomplete="organization-title" required> 163 </div> 164 </div> 165 166 <div class="contai-form-group"> 143 167 <label for="contai_legal_address" class="contai-label"> 144 168 <?php esc_html_e( 'Business Address', '1platform-content-ai' ); ?> 145 169 <span class="contai-required">*</span> 146 170 </label> 147 <input type="text" id="contai_legal_address" name="contai_legal_address" class="contai-input" placeholder="<?php esc_attr_e( '123 Main St, City, Country', '1platform-content-ai' ); ?>" autocomplete="street-address" required> 171 <div class="contai-input-wrap contai-input-icon"> 172 <span class="dashicons dashicons-location"></span> 173 <input type="text" id="contai_legal_address" name="contai_legal_address" class="contai-input" placeholder="<?php esc_attr_e( '123 Main St, City, Country', '1platform-content-ai' ); ?>" autocomplete="street-address" required> 174 </div> 148 175 </div> 149 176 </div> … … 152 179 153 180 <!-- Step 3: Content Generation Settings --> 154 <div class="contai-wizard-section" >181 <div class="contai-wizard-section" data-step="3"> 155 182 <div class="contai-section-header"> 156 183 <div class="contai-step-indicator"> … … 158 185 </div> 159 186 <div class="contai-section-title-group"> 160 <h2 class="contai-section-title"><?php esc_html_e( 'Content Generation', '1platform-content-ai' ); ?></h2> 187 <h2 class="contai-section-title"> 188 <span class="dashicons dashicons-admin-post contai-section-icon"></span> 189 <?php esc_html_e( 'Content Generation', '1platform-content-ai' ); ?> 190 </h2> 161 191 <p class="contai-section-description"><?php esc_html_e( 'Configure how AI generates your website content, keywords, and images.', '1platform-content-ai' ); ?></p> 162 192 </div> 163 193 </div> 164 194 <div class="contai-section-body"> 165 <div class="contai-form-grid contai-grid- 3">195 <div class="contai-form-grid contai-grid-2"> 166 196 <div class="contai-form-group contai-span-full"> 167 <label for="contai_source_url" class="contai-label"> 168 <?php esc_html_e( 'Competitor Website (for keyword extraction)', '1platform-content-ai' ); ?> 169 <span class="contai-required">*</span> 170 </label> 171 <input type="url" id="contai_source_url" name="contai_source_url" class="contai-input" placeholder="https://example.com" autocomplete="url" spellcheck="false" required> 172 <span class="contai-help-text"><?php esc_html_e( 'We\'ll analyze this site to extract relevant keywords for your content.', '1platform-content-ai' ); ?></span> 197 <label for="contai_source_topic" class="contai-label"> 198 <?php esc_html_e( 'Keyword Topic', '1platform-content-ai' ); ?> 199 <span class="contai-required">*</span> 200 </label> 201 <div class="contai-input-wrap contai-input-icon"> 202 <span class="dashicons dashicons-search"></span> 203 <input type="text" id="contai_source_topic" name="contai_source_topic" class="contai-input" placeholder="<?php esc_attr_e( 'e.g., indoor plants care, home workout routines...', '1platform-content-ai' ); ?>" autocomplete="off" spellcheck="false" required> 204 </div> 205 <span class="contai-help-text"><?php esc_html_e( 'We\'ll research this topic to extract relevant keywords for your content.', '1platform-content-ai' ); ?></span> 173 206 </div> 174 207 … … 191 224 <div class="contai-form-group"> 192 225 <label for="contai_image_provider" class="contai-label"> 193 <?php esc_html_e( 'Image Provider', '1platform-content-ai' ); ?>226 <?php esc_html_e( 'Image Source', '1platform-content-ai' ); ?> 194 227 <span class="contai-required">*</span> 195 228 </label> … … 206 239 <div class="contai-wizard-section contai-wizard-submit"> 207 240 <div class="contai-section-body"> 208 <div class="contai-notice contai-notice-info"> 209 <span class="dashicons dashicons-clock"></span> 210 <div> 211 <strong><?php esc_html_e( 'Background Process', '1platform-content-ai' ); ?></strong> 212 <p><?php esc_html_e( 'This process runs in the background and may take several hours depending on the number of posts. You can safely close this page and check back later.', '1platform-content-ai' ); ?></p> 213 </div> 214 </div> 215 216 <div class="contai-submit-area"> 217 <button type="submit" id="contai_submit_btn" class="contai-btn contai-btn-primary contai-btn-lg"> 218 <span class="dashicons dashicons-controls-play"></span> 219 <?php esc_html_e( 'Start Site Generation', '1platform-content-ai' ); ?> 220 </button> 241 <div class="contai-launch-card"> 242 <div class="contai-launch-info"> 243 <div class="contai-launch-icon"> 244 <span class="dashicons dashicons-clock"></span> 245 </div> 246 <div class="contai-launch-text"> 247 <strong><?php esc_html_e( 'Background Process', '1platform-content-ai' ); ?></strong> 248 <p><?php esc_html_e( 'Generation runs in the background. You can safely close this page and check progress later.', '1platform-content-ai' ); ?></p> 249 </div> 250 </div> 251 <div class="contai-submit-area"> 252 <button type="submit" id="contai_submit_btn" class="contai-btn contai-btn-primary contai-btn-lg"> 253 <span class="dashicons dashicons-controls-play"></span> 254 <?php esc_html_e( 'Launch Site Generation', '1platform-content-ai' ); ?> 255 </button> 256 </div> 221 257 </div> 222 258 </div> -
1platform-content-ai/trunk/includes/admin/assets/css/admin-ai-site-generator.css
r3488242 r3490375 1 1 /* ======================================================== 2 Site Wizard - Modern Admin UI 2 Site Wizard — Refined Admin UI 3 Design: Precision minimalism with connected timeline 3 4 ======================================================== */ 4 5 5 6 /* -- Wizard Wrapper -- */ 6 7 .contai-wizard-wrap { 7 max-width: 960px;8 margin: 2 0px auto 40px;8 max-width: 860px; 9 margin: 24px auto 48px; 9 10 padding: 0; 10 11 background: transparent; … … 16 17 /* -- Hero Header -- */ 17 18 .contai-wizard-header { 18 background: linear-gradient(135deg, # 1e3a5f 0%, var(--contai-primary) 50%, var(--contai-primary-light) 100%);19 background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 40%, var(--contai-primary) 100%); 19 20 border-radius: var(--contai-radius-lg) var(--contai-radius-lg) 0 0; 20 padding: 3 2px 36px;21 padding: 36px 40px; 21 22 margin-bottom: 0; 22 23 position: relative; … … 27 28 content: ''; 28 29 position: absolute; 29 top: -40%; 30 right: -10%; 31 width: 300px; 32 height: 300px; 33 background: radial-gradient(circle, rgba(255,255,255,0.08) 0%, transparent 70%); 34 border-radius: 50%; 30 inset: 0; 31 background: 32 radial-gradient(ellipse 600px 400px at 80% 20%, rgba(59, 130, 246, 0.2) 0%, transparent 70%), 33 radial-gradient(ellipse 300px 300px at 20% 80%, rgba(37, 99, 235, 0.1) 0%, transparent 70%); 35 34 pointer-events: none; 36 35 } … … 39 38 content: ''; 40 39 position: absolute; 41 bottom: -60%; 42 left: 20%; 43 width: 200px; 44 height: 200px; 45 background: radial-gradient(circle, rgba(255,255,255,0.05) 0%, transparent 70%); 46 border-radius: 50%; 40 inset: 0; 41 background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 47 42 pointer-events: none; 48 43 } … … 57 52 58 53 .contai-wizard-icon { 59 width: 5 6px;60 height: 5 6px;61 background: rgba(255, 255, 255, 0.1 5);62 border-radius: 14px;54 width: 52px; 55 height: 52px; 56 background: rgba(255, 255, 255, 0.1); 57 border-radius: var(--contai-radius-lg); 63 58 display: flex; 64 59 align-items: center; 65 60 justify-content: center; 66 61 flex-shrink: 0; 67 backdrop-filter: blur(1 0px);68 border: 1px solid rgba(255, 255, 255, 0. 2);62 backdrop-filter: blur(12px); 63 border: 1px solid rgba(255, 255, 255, 0.15); 69 64 } 70 65 71 66 .contai-wizard-icon .dashicons { 72 font-size: 2 8px;73 width: 2 8px;74 height: 2 8px;67 font-size: 26px; 68 width: 26px; 69 height: 26px; 75 70 color: #fff; 76 71 } 77 72 78 73 .contai-wizard-header-text h1 { 79 margin: 0 0 6px 0;80 font-size: 2 6px;74 margin: 0 0 4px 0; 75 font-size: 22px; 81 76 font-weight: 700; 82 77 color: #fff; 83 letter-spacing: -0. 3px;78 letter-spacing: -0.4px; 84 79 line-height: 1.2; 85 80 padding: 0; … … 88 83 .contai-wizard-header-text p { 89 84 margin: 0; 90 color: rgba(255, 255, 255, 0. 85);91 font-size: 1 4px;85 color: rgba(255, 255, 255, 0.7); 86 font-size: 13.5px; 92 87 line-height: 1.5; 93 max-width: 520px;88 max-width: 480px; 94 89 } 95 90 96 91 /* -- Form Container -- */ 97 92 .contai-site-generator-form { 98 background: var(--contai-neutral- 100);93 background: var(--contai-neutral-50); 99 94 border-radius: 0 0 var(--contai-radius-lg) var(--contai-radius-lg); 100 padding: 28px;95 padding: 32px; 101 96 display: flex; 102 97 flex-direction: column; 103 gap: 24px;98 gap: 0; 104 99 } 105 100 … … 107 102 .contai-wizard-section { 108 103 background: #fff; 109 border-radius: var(--contai-radius- md);104 border-radius: var(--contai-radius-lg); 110 105 border: 1px solid var(--contai-neutral-200); 111 106 overflow: hidden; 112 transition: box-shadow var(--contai-duration-fast) ease; 107 transition: border-color var(--contai-duration-fast) ease, 108 box-shadow var(--contai-duration-fast) ease; 109 margin-bottom: 0; 110 position: relative; 111 } 112 113 .contai-wizard-section:not(.contai-wizard-submit) { 114 margin-bottom: 24px; 113 115 } 114 116 115 117 .contai-wizard-section:hover { 118 border-color: var(--contai-neutral-300); 116 119 box-shadow: var(--contai-shadow-sm); 117 120 } 118 121 119 /* -- Section Header with Step Indicator -- */ 122 .contai-wizard-section:focus-within { 123 border-color: var(--contai-primary-border); 124 box-shadow: 0 0 0 3px var(--contai-primary-glow), var(--contai-shadow-sm); 125 } 126 127 /* -- Section Header with Timeline -- */ 120 128 .contai-section-header { 121 129 display: flex; 122 130 align-items: flex-start; 123 131 gap: 16px; 124 padding: 20px 24px ;125 b order-bottom: 1px solid var(--contai-neutral-200);126 b ackground: var(--contai-neutral-50);132 padding: 20px 24px 16px; 133 background: #fff; 134 border-bottom: none; 127 135 } 128 136 129 137 .contai-step-indicator { 138 display: flex; 139 flex-direction: column; 140 align-items: center; 130 141 flex-shrink: 0; 142 gap: 0; 131 143 } 132 144 … … 135 147 align-items: center; 136 148 justify-content: center; 137 width: 3 6px;138 height: 3 6px;139 background: linear-gradient(135deg, var(--contai-primary), var(--contai-primary-dark));149 width: 32px; 150 height: 32px; 151 background: var(--contai-primary); 140 152 color: #fff; 141 border-radius: var(--contai-radius-md);142 font-size: 1 5px;153 border-radius: 50%; 154 font-size: 13px; 143 155 font-weight: 700; 144 156 line-height: 1; 157 position: relative; 158 z-index: 1; 159 box-shadow: 0 0 0 4px var(--contai-primary-glow); 160 } 161 162 .contai-step-line { 163 display: block; 164 width: 2px; 165 height: 16px; 166 background: var(--contai-neutral-200); 167 margin-top: 4px; 145 168 } 146 169 … … 148 171 flex: 1; 149 172 min-width: 0; 150 padding-top: 2px;173 padding-top: 4px; 151 174 } 152 175 153 176 .contai-section-title { 154 margin: 0 0 4px 0;155 font-size: 1 7px;156 font-weight: 6 00;177 margin: 0 0 2px 0; 178 font-size: 15px; 179 font-weight: 650; 157 180 color: var(--contai-neutral-700); 158 181 line-height: 1.3; 182 letter-spacing: -0.2px; 183 display: flex; 184 align-items: center; 185 gap: 8px; 186 } 187 188 .contai-section-icon { 189 font-size: 17px; 190 width: 17px; 191 height: 17px; 192 color: var(--contai-primary); 193 opacity: 0.85; 159 194 } 160 195 161 196 .contai-section-description { 162 197 margin: 0; 163 color: var(--contai-neutral- 500);164 font-size: 1 3px;198 color: var(--contai-neutral-400); 199 font-size: 12.5px; 165 200 line-height: 1.5; 166 201 } … … 168 203 /* -- Section Body -- */ 169 204 .contai-section-body { 170 padding: 24px;205 padding: 4px 24px 24px; 171 206 } 172 207 … … 174 209 .contai-form-grid { 175 210 display: grid; 176 gap: 20px; 211 gap: 18px; 212 } 213 214 .contai-grid-2 { 215 grid-template-columns: repeat(2, 1fr); 177 216 } 178 217 … … 189 228 } 190 229 191 /* -- Form Divider -- */192 .contai-form-divider {193 height: 1px;194 background: var(--contai-neutral-200);195 margin: 8px 0;196 }197 198 230 /* -- Form Group -- */ 199 231 .contai-form-group { … … 206 238 align-items: center; 207 239 gap: 4px; 208 font-weight: 600;209 font-size: 1 3px;240 font-weight: 550; 241 font-size: 12.5px; 210 242 margin-bottom: 6px; 211 color: var(--contai-neutral- 700);243 color: var(--contai-neutral-600); 212 244 line-height: 1.4; 245 letter-spacing: 0.01em; 246 text-transform: uppercase; 213 247 } 214 248 … … 216 250 color: var(--contai-error); 217 251 font-weight: 700; 218 font-size: 14px; 252 font-size: 13px; 253 } 254 255 /* -- Input Wrapper with Icon -- */ 256 .contai-input-wrap { 257 position: relative; 258 display: flex; 259 align-items: center; 260 } 261 262 .contai-input-icon > .dashicons { 263 position: absolute; 264 left: 12px; 265 top: 50%; 266 transform: translateY(-50%); 267 font-size: 16px; 268 width: 16px; 269 height: 16px; 270 color: var(--contai-neutral-400); 271 pointer-events: none; 272 transition: color var(--contai-duration-fast) ease; 273 z-index: 1; 274 } 275 276 .contai-input-icon > .contai-input { 277 padding-left: 38px; 278 } 279 280 .contai-input-icon:focus-within > .dashicons { 281 color: var(--contai-primary); 219 282 } 220 283 … … 223 286 .contai-select { 224 287 width: 100%; 225 padding: 10px 14px;226 border: 1.5px solid var(--contai-neutral- 300);227 border-radius: var(--contai-radius- lg);228 font-size: 1 4px;288 padding: 9px 13px; 289 border: 1.5px solid var(--contai-neutral-200); 290 border-radius: var(--contai-radius-md); 291 font-size: 13.5px; 229 292 font-family: inherit; 230 293 color: var(--contai-neutral-700); 231 background: #fff; 232 transition: border-color var(--contai-duration-fast) ease, box-shadow var(--contai-duration-fast) ease; 294 background: var(--contai-neutral-50); 295 transition: border-color var(--contai-duration-fast) ease, 296 box-shadow var(--contai-duration-fast) ease, 297 background-color var(--contai-duration-fast) ease; 233 298 -webkit-appearance: none; 234 299 appearance: none; 235 300 box-sizing: border-box; 301 line-height: 1.5; 236 302 } 237 303 238 304 .contai-select { 239 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23 646970' d='M6 8.825L1.175 4 2.238 2.938 6 6.7l3.763-3.763L10.825 4z'/%3E%3C/svg%3E");305 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M6 8.825L1.175 4 2.238 2.938 6 6.7l3.763-3.763L10.825 4z'/%3E%3C/svg%3E"); 240 306 background-repeat: no-repeat; 241 background-position: right 1 4px center;307 background-position: right 12px center; 242 308 background-size: 12px; 243 padding-right: 36px; 309 background-color: var(--contai-neutral-50); 310 padding-right: 34px; 244 311 cursor: pointer; 245 312 } … … 247 314 .contai-input::placeholder { 248 315 color: var(--contai-neutral-400); 316 font-weight: 400; 249 317 } 250 318 251 319 .contai-input:hover, 252 320 .contai-select:hover { 253 border-color: var(--contai-neutral-400); 321 border-color: var(--contai-neutral-300); 322 background: #fff; 254 323 } 255 324 … … 258 327 outline: none; 259 328 border-color: var(--contai-primary); 329 background: #fff; 260 330 box-shadow: 0 0 0 3px var(--contai-primary-glow); 331 } 332 333 /* Number input refinement */ 334 .contai-input[type="number"] { 335 font-variant-numeric: tabular-nums; 336 font-family: var(--contai-font-mono); 337 font-size: 13px; 338 letter-spacing: -0.01em; 261 339 } 262 340 … … 264 342 .contai-input-error { 265 343 border-color: var(--contai-error) !important; 266 box-shadow: 0 0 0 3px rgba(220, 38, 38, 0. 1) !important;344 box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.08) !important; 267 345 } 268 346 … … 270 348 display: block; 271 349 color: var(--contai-error); 272 font-size: 1 2px;350 font-size: 11.5px; 273 351 margin-top: 5px; 274 352 font-weight: 500; … … 279 357 .contai-help-text { 280 358 display: block; 281 color: var(--contai-neutral-500); 359 color: var(--contai-neutral-400); 360 font-size: 11.5px; 361 margin-top: 5px; 362 line-height: 1.5; 363 } 364 365 /* -- Launch Card (Submit Section) -- */ 366 .contai-wizard-submit { 367 border: none; 368 background: transparent; 369 box-shadow: none !important; 370 margin-top: 4px; 371 } 372 373 .contai-wizard-submit:hover { 374 box-shadow: none !important; 375 border-color: transparent !important; 376 } 377 378 .contai-wizard-submit:focus-within { 379 box-shadow: none !important; 380 border-color: transparent !important; 381 } 382 383 .contai-wizard-submit .contai-section-body { 384 padding: 0; 385 } 386 387 .contai-launch-card { 388 display: flex; 389 align-items: center; 390 justify-content: space-between; 391 gap: 24px; 392 padding: 20px 24px; 393 background: linear-gradient(135deg, var(--contai-neutral-700) 0%, #1e3a5f 100%); 394 border-radius: var(--contai-radius-lg); 395 position: relative; 396 overflow: hidden; 397 } 398 399 .contai-launch-card::before { 400 content: ''; 401 position: absolute; 402 inset: 0; 403 background: 404 radial-gradient(ellipse 300px 200px at 90% 50%, rgba(37, 99, 235, 0.15) 0%, transparent 70%); 405 pointer-events: none; 406 } 407 408 .contai-launch-info { 409 display: flex; 410 align-items: center; 411 gap: 14px; 412 position: relative; 413 z-index: 1; 414 flex: 1; 415 min-width: 0; 416 } 417 418 .contai-launch-icon { 419 width: 40px; 420 height: 40px; 421 background: rgba(255, 255, 255, 0.1); 422 border-radius: 50%; 423 display: flex; 424 align-items: center; 425 justify-content: center; 426 flex-shrink: 0; 427 border: 1px solid rgba(255, 255, 255, 0.1); 428 } 429 430 .contai-launch-icon .dashicons { 431 font-size: 18px; 432 width: 18px; 433 height: 18px; 434 color: rgba(255, 255, 255, 0.7); 435 } 436 437 .contai-launch-text { 438 flex: 1; 439 min-width: 0; 440 } 441 442 .contai-launch-text strong { 443 display: block; 444 color: #fff; 445 font-size: 13px; 446 font-weight: 600; 447 margin-bottom: 1px; 448 } 449 450 .contai-launch-text p { 451 margin: 0; 452 color: rgba(255, 255, 255, 0.55); 282 453 font-size: 12px; 283 margin-top: 6px;284 454 line-height: 1.5; 285 455 } 286 456 287 /* -- Info Notice -- */ 457 .contai-launch-card .contai-submit-area { 458 position: relative; 459 z-index: 1; 460 flex-shrink: 0; 461 } 462 463 /* -- Buttons -- */ 464 .contai-btn { 465 display: inline-flex; 466 align-items: center; 467 justify-content: center; 468 gap: 8px; 469 padding: 10px 24px; 470 font-size: 13px; 471 font-weight: 600; 472 font-family: inherit; 473 border: none; 474 border-radius: var(--contai-radius-md); 475 cursor: pointer; 476 transition: all var(--contai-duration-fast) var(--contai-ease); 477 line-height: 1; 478 text-decoration: none; 479 white-space: nowrap; 480 } 481 482 .contai-btn .dashicons { 483 font-size: 16px; 484 width: 16px; 485 height: 16px; 486 } 487 488 .contai-btn-primary { 489 background: #fff; 490 color: var(--contai-neutral-700); 491 box-shadow: var(--contai-shadow-sm); 492 } 493 494 .contai-btn-primary:hover { 495 background: #fff; 496 color: var(--contai-primary); 497 box-shadow: var(--contai-shadow-md), 0 0 0 1px rgba(255, 255, 255, 0.1); 498 transform: translateY(-1px); 499 } 500 501 .contai-btn-primary:active { 502 transform: translateY(0); 503 box-shadow: var(--contai-shadow-xs); 504 } 505 506 .contai-btn-lg { 507 padding: 12px 28px; 508 font-size: 13.5px; 509 border-radius: var(--contai-radius-md); 510 } 511 512 .contai-btn:disabled, 513 .contai-btn-loading { 514 opacity: 0.7; 515 cursor: not-allowed; 516 transform: none !important; 517 } 518 519 /* -- Spinner -- */ 520 .contai-spinning { 521 animation: contai-spin 1s linear infinite; 522 } 523 524 @keyframes contai-spin { 525 from { transform: rotate(0deg); } 526 to { transform: rotate(360deg); } 527 } 528 529 /* -- Legacy Notice (keep for backward compat) -- */ 288 530 .contai-notice { 289 531 display: flex; … … 323 565 } 324 566 325 /* -- Submit Area -- */326 .contai-submit-area {327 display: flex;328 justify-content: flex-end;329 }330 331 /* -- Buttons -- */332 .contai-btn {333 display: inline-flex;334 align-items: center;335 justify-content: center;336 gap: 8px;337 padding: 12px 28px;338 font-size: 14px;339 font-weight: 600;340 font-family: inherit;341 border: none;342 border-radius: var(--contai-radius-lg);343 cursor: pointer;344 transition: all var(--contai-duration-fast) ease;345 line-height: 1;346 text-decoration: none;347 }348 349 .contai-btn .dashicons {350 font-size: 18px;351 width: 18px;352 height: 18px;353 }354 355 .contai-btn-primary {356 background: linear-gradient(135deg, var(--contai-primary), var(--contai-primary-dark));357 color: #fff;358 box-shadow: var(--contai-shadow-md);359 }360 361 .contai-btn-primary:hover {362 background: linear-gradient(135deg, var(--contai-primary-dark), var(--contai-primary-darker));363 box-shadow: var(--contai-shadow-lg);364 color: #fff;365 transform: translateY(-1px);366 }367 368 .contai-btn-primary:active {369 transform: translateY(0);370 box-shadow: var(--contai-shadow-sm);371 }372 373 .contai-btn-lg {374 padding: 14px 36px;375 font-size: 15px;376 }377 378 .contai-btn:disabled,379 .contai-btn-loading {380 opacity: 0.75;381 cursor: not-allowed;382 transform: none !important;383 }384 385 /* -- Spinner -- */386 .contai-spinning {387 animation: contai-spin 1s linear infinite;388 }389 390 @keyframes contai-spin {391 from { transform: rotate(0deg); }392 to { transform: rotate(360deg); }393 }394 395 /* -- Submit Section Override -- */396 .contai-wizard-submit {397 border: none;398 background: transparent;399 box-shadow: none;400 }401 402 .contai-wizard-submit:hover {403 box-shadow: none;404 }405 406 .contai-wizard-submit .contai-section-body {407 padding: 0;408 }409 410 567 /* -- Progress Section (Active Job) -- */ 411 568 .contai-settings-panel { … … 450 607 .contai-progress-bar { 451 608 width: 100%; 452 height: 1 2px;609 height: 10px; 453 610 background-color: var(--contai-neutral-200); 454 border-radius: var(--contai-radius- md);611 border-radius: var(--contai-radius-pill); 455 612 overflow: hidden; 456 613 margin-bottom: 10px; … … 460 617 height: 100%; 461 618 background: linear-gradient(90deg, var(--contai-primary), var(--contai-primary-light)); 462 border-radius: var(--contai-radius- md);463 transition: width 0. 3s ease;619 border-radius: var(--contai-radius-pill); 620 transition: width 0.4s var(--contai-ease); 464 621 } 465 622 … … 467 624 text-align: center; 468 625 font-weight: 600; 469 font-size: 1 4px;626 font-size: 13px; 470 627 color: var(--contai-neutral-700); 628 font-variant-numeric: tabular-nums; 471 629 } 472 630 … … 484 642 display: inline-block; 485 643 padding: 3px 10px; 486 border-radius: 20px;644 border-radius: var(--contai-radius-pill); 487 645 font-weight: 600; 488 646 text-transform: uppercase; 489 font-size: 1 1px;490 letter-spacing: 0. 3px;647 font-size: 10.5px; 648 letter-spacing: 0.4px; 491 649 } 492 650 … … 517 675 .contai-completed-steps h3 { 518 676 margin: 0 0 12px; 519 font-size: 1 4px;677 font-size: 13px; 520 678 font-weight: 600; 521 679 color: var(--contai-neutral-700); 680 text-transform: uppercase; 681 letter-spacing: 0.02em; 522 682 } 523 683 … … 543 703 544 704 .contai-completed-steps li .dashicons { 545 color: #00a32a;705 color: var(--contai-success); 546 706 font-size: 18px; 547 707 width: 18px; … … 562 722 background: linear-gradient(135deg, var(--contai-primary), var(--contai-primary-dark)); 563 723 border: none; 564 border-radius: var(--contai-radius- lg);724 border-radius: var(--contai-radius-md); 565 725 color: #fff; 566 726 font-size: 13px; … … 660 820 } 661 821 822 .contai-grid-2, 662 823 .contai-grid-3 { 663 824 grid-template-columns: repeat(2, 1fr); … … 670 831 .contai-span-2 { 671 832 grid-column: 1 / -1; 833 } 834 835 .contai-launch-card { 836 flex-direction: column; 837 align-items: stretch; 838 text-align: center; 839 } 840 841 .contai-launch-info { 842 flex-direction: column; 843 } 844 845 .contai-submit-area { 846 display: flex; 847 justify-content: center; 672 848 } 673 849 } … … 690 866 691 867 .contai-wizard-header-text h1 { 692 font-size: 2 2px;868 font-size: 20px; 693 869 } 694 870 … … 700 876 border-radius: 0; 701 877 padding: 16px; 702 gap: 16px; 703 } 704 705 .contai-wizard-section { 706 border-radius: var(--contai-radius-lg); 878 } 879 880 .contai-wizard-section:not(.contai-wizard-submit) { 881 margin-bottom: 16px; 707 882 } 708 883 709 884 .contai-section-header { 710 padding: 16px ;885 padding: 16px 16px 12px; 711 886 } 712 887 713 888 .contai-section-body { 714 padding: 16px; 715 } 716 889 padding: 4px 16px 16px; 890 } 891 892 .contai-grid-2, 717 893 .contai-grid-3 { 718 894 grid-template-columns: 1fr; … … 726 902 .contai-select { 727 903 font-size: 16px; 728 padding: 1 2px 14px;729 } 730 731 .contai- submit-area{732 justify-content: stretch;904 padding: 11px 13px; 905 } 906 907 .contai-input-icon > .contai-input { 908 padding-left: 38px; 733 909 } 734 910 735 911 .contai-btn-lg { 736 912 width: 100%; 737 } 738 } 913 justify-content: center; 914 } 915 916 .contai-launch-card { 917 padding: 16px; 918 flex-direction: column; 919 gap: 16px; 920 } 921 922 .contai-launch-info { 923 flex-direction: column; 924 text-align: center; 925 } 926 927 .contai-submit-area { 928 display: flex; 929 } 930 931 .contai-submit-area .contai-btn { 932 width: 100%; 933 } 934 } -
1platform-content-ai/trunk/includes/admin/content-generator/handlers/KeywordExtractionHandler.php
r3483422 r3490375 100 100 101 101 $payload = [ 102 ' domain' => $validation['domain'],102 'topic' => $validation['topic'], 103 103 'country' => $validation['country'], 104 'lang' => $validation['lang'] 104 'lang' => $validation['lang'], 105 105 ]; 106 106 … … 123 123 'success' => true, 124 124 'message' => sprintf( 125 /* translators: %s: domainname for keyword extraction */126 __('Keyword extraction job has been queued . Domain: %s. You can check the Keywords List page for results.', '1platform-content-ai'),127 $validation[' domain']125 /* translators: %s: topic name for keyword extraction */ 126 __('Keyword extraction job has been queued for: %s. You can check the Keywords List page for results.', '1platform-content-ai'), 127 $validation['topic'] 128 128 ) 129 129 ]; … … 132 132 private function validateExtractionRequest(): array { 133 133 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified in handleRequest() via verifyNonce(). 134 $ domain = esc_url_raw(wp_unslash($_POST['contai_source_url'] ?? ''));134 $topic = sanitize_text_field(wp_unslash($_POST['contai_topic'] ?? '')); 135 135 $country = sanitize_text_field(wp_unslash($_POST['contai_country'] ?? '')); 136 136 $lang = sanitize_text_field(wp_unslash($_POST['contai_target_language'] ?? '')); 137 137 // phpcs:enable WordPress.Security.NonceVerification.Missing 138 138 139 if (empty($domain) || empty($country) || empty($lang)) { 140 return [ 141 'valid' => false, 142 'message' => __('Please fill in all required fields.', '1platform-content-ai') 143 ]; 139 if (empty($topic)) { 140 return ['valid' => false, 'message' => __('Please enter a topic for keyword discovery.', '1platform-content-ai')]; 144 141 } 145 146 if (!filter_var($domain, FILTER_VALIDATE_URL)) { 147 return [ 148 'valid' => false, 149 'message' => __('Please enter a valid URL.', '1platform-content-ai') 150 ]; 142 if (mb_strlen($topic) < 3 || mb_strlen($topic) > 200) { 143 return ['valid' => false, 'message' => __('Topic must be between 3 and 200 characters.', '1platform-content-ai')]; 151 144 } 152 145 153 146 $validLanguages = ['en', 'es']; 154 147 if (!in_array($lang, $validLanguages, true)) { 155 return [ 156 'valid' => false, 157 'message' => __('Invalid language selected.', '1platform-content-ai') 158 ]; 148 return ['valid' => false, 'message' => __('Invalid language selected.', '1platform-content-ai')]; 159 149 } 160 150 161 151 $validCountries = ['us', 'es']; 162 152 if (!in_array($country, $validCountries, true)) { 163 return [ 164 'valid' => false, 165 'message' => __('Invalid country selected.', '1platform-content-ai') 166 ]; 153 return ['valid' => false, 'message' => __('Invalid country selected.', '1platform-content-ai')]; 167 154 } 168 155 169 156 return [ 170 157 'valid' => true, 171 ' domain' => $domain,158 'topic' => $topic, 172 159 'country' => $country, 173 'lang' => $lang 160 'lang' => $lang, 174 161 ]; 175 162 } -
1platform-content-ai/trunk/includes/admin/content-generator/panels/keyword-extractor.php
r3483422 r3490375 24 24 <div class="contai-form-grid contai-grid-2"> 25 25 <div class="contai-form-group"> 26 <label for="contai_ source_url" class="contai-label">27 <span class="dashicons dashicons- admin-site-alt3"></span>28 <?php esc_html_e(' Source Website', '1platform-content-ai'); ?>26 <label for="contai_topic" class="contai-label"> 27 <span class="dashicons dashicons-lightbulb"></span> 28 <?php esc_html_e('Topic / Theme', '1platform-content-ai'); ?> 29 29 </label> 30 <input type="url" id="contai_source_url" name="contai_source_url" required 31 class="contai-input" 32 placeholder="https://example.com" 30 <input type="text" id="contai_topic" name="contai_topic" 31 class="contai-input" required 32 placeholder="<?php esc_attr_e('e.g. plantas de interior, salud medioambiental', '1platform-content-ai'); ?>" 33 minlength="3" maxlength="200" 33 34 value="<?php 34 35 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Repopulating form field after submission; value is sanitized and escaped. 35 echo isset($_POST['contai_ source_url']) ? esc_attr( sanitize_text_field( wp_unslash( $_POST['contai_source_url'] ) ) ) : ''; ?>">36 echo isset($_POST['contai_topic']) ? esc_attr( sanitize_text_field( wp_unslash( $_POST['contai_topic'] ) ) ) : ''; ?>"> 36 37 <p class="contai-help-text"> 37 38 <span class="dashicons dashicons-info"></span> 38 <?php esc_html_e('Enter the competitor website URL to analyze', '1platform-content-ai'); ?>39 <?php esc_html_e('Enter a topic or theme to discover keywords from Google (2-4 words work best)', '1platform-content-ai'); ?> 39 40 </p> 40 41 </div> … … 199 200 <thead> 200 201 <tr> 201 <th><?php esc_html_e(' Domain', '1platform-content-ai'); ?></th>202 <th><?php esc_html_e('Topic', '1platform-content-ai'); ?></th> 202 203 <th><?php esc_html_e('Country', '1platform-content-ai'); ?></th> 203 204 <th><?php esc_html_e('Language', '1platform-content-ai'); ?></th> … … 215 216 216 217 private function renderJobRow(array $job): void { 217 $payload = json_decode($job['payload'], true) ;218 $ domain =$payload['domain'] ?? __('Unknown', '1platform-content-ai');218 $payload = json_decode($job['payload'], true) ?? []; 219 $topic = $payload['topic'] ?? $payload['domain'] ?? __('Unknown', '1platform-content-ai'); 219 220 $country = strtoupper($payload['country'] ?? 'N/A'); 220 221 $lang = strtoupper($payload['lang'] ?? 'N/A'); … … 222 223 ?> 223 224 <tr> 224 <td><strong><?php echo esc_html($ domain); ?></strong></td>225 <td><strong><?php echo esc_html($topic); ?></strong></td> 225 226 <td><?php echo esc_html($country); ?></td> 226 227 <td><?php echo esc_html($lang); ?></td> … … 234 235 } 235 236 236 private function calculateElapsedTime(string $processedAt): string { 237 $now = current_time('timestamp'); 237 private function calculateElapsedTime(?string $processedAt): string { 238 if (empty($processedAt)) { 239 return __('Just started', '1platform-content-ai'); 240 } 238 241 $processed = strtotime($processedAt); 239 $diff = $now - $processed; 242 if ($processed === false) { 243 return __('Unknown', '1platform-content-ai'); 244 } 245 $now = time(); 246 $diff = max(0, $now - $processed); 240 247 241 248 $minutes = floor($diff / 60); -
1platform-content-ai/trunk/includes/services/api/OnePlatformEndpoints.php
r3483422 r3490375 53 53 // ── Content Generation ────────────────────────────────────── 54 54 const POSTS_KEYWORDS = '/posts/keywords/'; 55 const POSTS_KEYWORDS_TOPIC = '/posts/keywords/topic/'; 55 56 const POSTS_CONTENT = '/posts/content/'; 56 57 const POSTS_CONTENT_JOBS = '/posts/content/jobs/'; -
1platform-content-ai/trunk/includes/services/jobs/KeywordExtractionJob.php
r3483422 r3490375 19 19 public function handle(array $payload) 20 20 { 21 $topic = $payload['topic'] ?? ''; 21 22 $domain = $payload['domain'] ?? ''; 22 23 $country = $payload['country'] ?? ''; 23 24 $lang = $payload['lang'] ?? ''; 24 25 25 if (empty($domain) || empty($country) || empty($lang)) { 26 // Support both topic-based (new) and domain-based (legacy) payloads 27 $source = !empty($topic) ? $topic : $domain; 28 29 if (empty($source) || empty($country) || empty($lang)) { 26 30 return [ 27 31 'success' => false, 28 'error' => 'Missing required parameters: domain, country, or lang'32 'error' => 'Missing required parameters: topic/domain, country, or lang' 29 33 ]; 30 34 } 31 35 32 $result = $this->extractor_service->extractAndSaveKeywords($domain, $country, $lang); 36 $result = !empty($topic) 37 ? $this->extractor_service->extractByTopicAndSave($topic, $country, $lang) 38 : $this->extractor_service->extractAndSaveKeywords($domain, $country, $lang); 33 39 34 40 if ($result->isSuccess()) { … … 38 44 'skipped_count' => $result->getSkippedCount(), 39 45 'total_count' => $result->getTotalCount(), 40 ' domain' => $domain46 'source' => $source, 41 47 ]; 42 48 } … … 45 51 'success' => false, 46 52 'error' => $result->getErrorMessage(), 47 ' domain' => $domain53 'source' => $source, 48 54 ]; 49 55 } -
1platform-content-ai/trunk/includes/services/jobs/SiteGenerationJob.php
r3483422 r3490375 203 203 $service = ContaiKeywordExtractorService::create(); 204 204 205 $ domain = $extractionConfig['source_url'] ?? '';205 $topic = $extractionConfig['source_topic'] ?? ''; 206 206 $country = $extractionConfig['target_country'] ?? 'us'; 207 207 $lang = $extractionConfig['target_language'] ?? 'en'; 208 208 209 $result = $service->extract AndSaveKeywords($domain, $country, $lang);209 $result = $service->extractByTopicAndSave($topic, $country, $lang); 210 210 211 211 if (!$result->isSuccess()) { -
1platform-content-ai/trunk/includes/services/keyword/KeywordExtractorService.php
r3483422 r3490375 57 57 } 58 58 59 public function extractByTopicAndSave( 60 string $topic, 61 string $country, 62 string $lang 63 ): ContaiKeywordExtractionResult { 64 $response = $this->requestKeywordExtractionByTopic($topic, $country, $lang); 65 66 if (!$response->isSuccess()) { 67 return ContaiKeywordExtractionResult::failure( 68 $response->getMessage() ?? self::ERROR_API_REQUEST_FAILED 69 ); 70 } 71 72 return $this->processAndSaveKeywords($response); 73 } 74 59 75 private function requestKeywordExtraction( 60 76 string $domain, … … 69 85 70 86 return $this->client->post(ContaiOnePlatformEndpoints::POSTS_KEYWORDS, $request_data); 87 } 88 89 private function requestKeywordExtractionByTopic( 90 string $topic, 91 string $country, 92 string $lang 93 ): ContaiOnePlatformResponse { 94 $request_data = [ 95 'topic' => $topic, 96 'country' => $country, 97 'lang' => $lang, 98 ]; 99 100 return $this->client->post(ContaiOnePlatformEndpoints::POSTS_KEYWORDS_TOPIC, $request_data); 71 101 } 72 102 -
1platform-content-ai/trunk/readme.txt
r3488242 r3490375 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 2. 7.07 Stable tag: 2.9.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html
Note: See TracChangeset
for help on using the changeset viewer.