Plugin Directory

Changeset 3488242


Ignore:
Timestamp:
03/22/2026 02:18:23 PM (2 weeks ago)
Author:
1platform
Message:

Update to version 2.7.0 from GitHub

Location:
1platform-content-ai
Files:
10 added
6 deleted
46 edited
1 copied

Legend:

Unmodified
Added
Removed
  • 1platform-content-ai/tags/2.7.0/.git/FETCH_HEAD

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05        branch 'main' of https://github.com/1platformlabs/1platform-content-ai
     10b507e94120943ce7672264963c81dd809d669f1        branch 'main' of https://github.com/1platformlabs/1platform-content-ai
  • 1platform-content-ai/tags/2.7.0/.git/ORIG_HEAD

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05
     10b507e94120943ce7672264963c81dd809d669f1
  • 1platform-content-ai/tags/2.7.0/.git/config

    r3487968 r3488242  
    1010    auto = 0
    1111[http "https://github.com/"]
    12     extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzX0lyQ1dNZlRNZUNQTTV2V0VIckJrNFY5SDVVSUxFMDJRVW5ycw==
     12    extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzXzZmZ1hBU01NQ25ORDF3aHA1aE5Rczl2dVpsRzBYMDNNcUZzVA==
    1313[branch "main"]
    1414    remote = origin
  • 1platform-content-ai/tags/2.7.0/.git/logs/HEAD

    r3487968 r3488242  
    1 0000000000000000000000000000000000000000 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05 runner <runner@runnervm46oaq.xgcnp5xq0a5uzhbzbke14hj00f.gx.internal.cloudapp.net> 1774128261 +0000    checkout: moving from master to main
     10000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052 +0000    checkout: moving from master to main
  • 1platform-content-ai/tags/2.7.0/.git/logs/refs/heads/main

    r3487968 r3488242  
    1 0000000000000000000000000000000000000000 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05 runner <runner@runnervm46oaq.xgcnp5xq0a5uzhbzbke14hj00f.gx.internal.cloudapp.net> 1774128261 +0000    branch: Created from refs/remotes/origin/main
     10000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052 +0000    branch: Created from refs/remotes/origin/main
  • 1platform-content-ai/tags/2.7.0/.git/logs/refs/remotes/origin/main

    r3487968 r3488242  
    1 0000000000000000000000000000000000000000 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05 runner <runner@runnervm46oaq.xgcnp5xq0a5uzhbzbke14hj00f.gx.internal.cloudapp.net> 1774128261 +0000    fetch --prune --no-recurse-submodules origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*: storing head
     10000000000000000000000000000000000000000 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 head
  • 1platform-content-ai/tags/2.7.0/.git/refs/heads/main

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05
     10b507e94120943ce7672264963c81dd809d669f1
  • 1platform-content-ai/tags/2.7.0/.git/refs/remotes/origin/main

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05
     10b507e94120943ce7672264963c81dd809d669f1
  • 1platform-content-ai/tags/2.7.0/1platform-content-ai.php

    r3487968 r3488242  
    55 * Plugin URI: https://1platform.pro/
    66 * 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.5.0
     7 * Version: 2.7.0
    88 * Author: 1Platform
    99 * License: GPLv2 or later
  • 1platform-content-ai/tags/2.7.0/includes/admin/admin-ai-site-generator.php

    r3483422 r3488242  
    8484                'site_language' => sanitize_text_field( wp_unslash( $_POST['contai_site_language'] ?? 'english' ) ),
    8585                'site_category' => sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ?? '' ) ),
    86                 'wordpress_theme' => sanitize_text_field( wp_unslash( $_POST['contai_wordpress_theme'] ?? 'blogfull' ) ),
     86                'wordpress_theme' => sanitize_text_field( wp_unslash( $_POST['contai_wordpress_theme'] ?? 'astra' ) ),
    8787            ),
    8888            'legal_info' => array(
  • 1platform-content-ai/tags/2.7.0/includes/admin/admin-init-configuration.php

    r3483422 r3488242  
    6666
    6767    if ( empty( $wordpress_theme ) ) {
    68         $wordpress_theme = 'blogfull';
     68        $wordpress_theme = 'astra';
    6969    }
    7070
  • 1platform-content-ai/tags/2.7.0/includes/admin/ai-site-generator/site-generator-form.php

    r3483422 r3488242  
    1818        <input type="hidden" name="contai_start_site_generation" value="1">
    1919
    20         <!-- Step 1: Site & Business Configuration -->
     20        <input type="hidden" id="contai_wordpress_theme" name="contai_wordpress_theme" value="astra">
     21
     22        <!-- Step 1: Website Identity -->
    2123        <div class="contai-wizard-section">
    2224            <div class="contai-section-header">
     
    2527                </div>
    2628                <div class="contai-section-title-group">
    27                     <h2 class="contai-section-title"><?php esc_html_e( 'Site & Business Configuration', '1platform-content-ai' ); ?></h2>
    28                     <p class="contai-section-description"><?php esc_html_e( 'Define your website identity, target audience, and legal information.', '1platform-content-ai' ); ?></p>
     29                    <h2 class="contai-section-title"><?php esc_html_e( 'Website Identity', '1platform-content-ai' ); ?></h2>
     30                    <p class="contai-section-description"><?php esc_html_e( 'Define what your website is about and who it targets.', '1platform-content-ai' ); ?></p>
    2931                </div>
    3032            </div>
     
    3739                        </label>
    3840                        <input type="text" id="contai_site_topic" name="contai_site_topic" class="contai-input" placeholder="e.g., Technology News" autocomplete="off" required>
    39                     </div>
    40 
    41                     <div class="contai-form-group">
    42                         <label for="contai_wordpress_theme" class="contai-label">
    43                             <?php esc_html_e( 'WordPress Theme', '1platform-content-ai' ); ?>
    44                             <span class="contai-required">*</span>
    45                         </label>
    46                         <select id="contai_wordpress_theme" name="contai_wordpress_theme" class="contai-select" autocomplete="off" required>
    47                             <option value="blogfull" selected>Blogfull</option>
    48                             <option value="newsmatic">Newsmatic</option>
    49                         </select>
    50                     </div>
    51 
    52                     <div class="contai-form-group">
    53                         <label for="contai_site_language" class="contai-label">
    54                             <?php esc_html_e( 'Language', '1platform-content-ai' ); ?>
    55                             <span class="contai-required">*</span>
    56                         </label>
    57                         <select id="contai_site_language" name="contai_site_language" class="contai-select" autocomplete="language" required data-category-select="#contai_site_category">
    58                             <option value="english" selected><?php esc_html_e( 'English', '1platform-content-ai' ); ?></option>
    59                             <option value="spanish"><?php esc_html_e( 'Spanish', '1platform-content-ai' ); ?></option>
    60                         </select>
     41                        <span class="contai-help-text"><?php esc_html_e( 'The main subject of your website', '1platform-content-ai' ); ?></span>
    6142                    </div>
    6243
     
    7657                                    $title_en = esc_html( $category['title']['en'] ?? 'Unnamed Category' );
    7758                                    $title_es = esc_html( $category['title']['es'] ?? $title_en );
     59                                    $category_theme = esc_attr( $category['recommended_theme'] ?? 'astra' );
    7860                                    $is_selected = ( $saved_category === $category_id );
    7961                                    ?>
    80                                     <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>">
     62                                    <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>" data-theme="<?php echo esc_attr( $category_theme ); ?>">
    8163                                        <?php echo esc_html( $title_en ); ?>
    8264                                    </option>
     
    8466                            <?php endif; ?>
    8567                        </select>
     68                        <span class="contai-help-text"><?php esc_html_e( 'Determines the theme and content style', '1platform-content-ai' ); ?></span>
     69                    </div>
     70
     71                    <div class="contai-form-group">
     72                        <label for="contai_site_language" class="contai-label">
     73                            <?php esc_html_e( 'Language', '1platform-content-ai' ); ?>
     74                            <span class="contai-required">*</span>
     75                        </label>
     76                        <select id="contai_site_language" name="contai_site_language" class="contai-select" autocomplete="language" required data-category-select="#contai_site_category">
     77                            <option value="english" selected><?php esc_html_e( 'English', '1platform-content-ai' ); ?></option>
     78                            <option value="spanish"><?php esc_html_e( 'Spanish', '1platform-content-ai' ); ?></option>
     79                        </select>
    8680                    </div>
    8781
     
    9791                    </div>
    9892
    99                     <div class="contai-form-group">
     93                    <div class="contai-form-group contai-span-2">
    10094                        <label for="contai_adsense_publisher" class="contai-label">
    10195                            <?php esc_html_e( 'AdSense Publisher ID', '1platform-content-ai' ); ?>
     
    10397                        </label>
    10498                        <input type="text" id="contai_adsense_publisher" name="contai_adsense_publisher" class="contai-input" placeholder="pub-1234567890123456" autocomplete="off" spellcheck="false" required>
    105                     </div>
    106                 </div>
    107 
    108                 <div class="contai-form-divider"></div>
    109 
    110                 <div class="contai-form-grid contai-grid-3">
    111                     <div class="contai-form-group">
    112                         <label for="contai_legal_owner" class="contai-label">
    113                             <?php esc_html_e( 'Business Owner', '1platform-content-ai' ); ?>
    114                             <span class="contai-required">*</span>
    115                         </label>
    116                         <input type="text" id="contai_legal_owner" name="contai_legal_owner" class="contai-input" autocomplete="name" required>
    117                     </div>
    118 
    119                     <div class="contai-form-group">
    120                         <label for="contai_legal_email" class="contai-label">
    121                             <?php esc_html_e( 'Contact Email', '1platform-content-ai' ); ?>
    122                             <span class="contai-required">*</span>
    123                         </label>
    124                         <input type="email" id="contai_legal_email" name="contai_legal_email" class="contai-input" autocomplete="email" spellcheck="false" required>
    125                     </div>
    126 
    127                     <div class="contai-form-group">
    128                         <label for="contai_legal_activity" class="contai-label">
    129                             <?php esc_html_e( 'Business Activity', '1platform-content-ai' ); ?>
    130                             <span class="contai-required">*</span>
    131                         </label>
    132                         <input type="text" id="contai_legal_activity" name="contai_legal_activity" class="contai-input" autocomplete="organization-title" required>
    133                     </div>
    134 
    135                     <div class="contai-form-group contai-span-full">
    136                         <label for="contai_legal_address" class="contai-label">
    137                             <?php esc_html_e( 'Business Address', '1platform-content-ai' ); ?>
    138                             <span class="contai-required">*</span>
    139                         </label>
    140                         <input type="text" id="contai_legal_address" name="contai_legal_address" class="contai-input" autocomplete="street-address" required>
    141                     </div>
    142                 </div>
    143             </div>
    144         </div>
    145 
    146         <!-- Step 2: Content Generation Settings -->
     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>
     100                    </div>
     101                </div>
     102            </div>
     103        </div>
     104
     105        <!-- Step 2: Legal Information -->
    147106        <div class="contai-wizard-section">
    148107            <div class="contai-section-header">
    149108                <div class="contai-step-indicator">
    150109                    <span class="contai-step-number">2</span>
     110                </div>
     111                <div class="contai-section-title-group">
     112                    <h2 class="contai-section-title"><?php esc_html_e( 'Legal Information', '1platform-content-ai' ); ?></h2>
     113                    <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                </div>
     115            </div>
     116            <div class="contai-section-body">
     117                <div class="contai-form-grid contai-grid-3">
     118                    <div class="contai-form-group">
     119                        <label for="contai_legal_owner" class="contai-label">
     120                            <?php esc_html_e( 'Business Owner', '1platform-content-ai' ); ?>
     121                            <span class="contai-required">*</span>
     122                        </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>
     124                    </div>
     125
     126                    <div class="contai-form-group">
     127                        <label for="contai_legal_email" class="contai-label">
     128                            <?php esc_html_e( 'Contact Email', '1platform-content-ai' ); ?>
     129                            <span class="contai-required">*</span>
     130                        </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>
     132                    </div>
     133
     134                    <div class="contai-form-group">
     135                        <label for="contai_legal_activity" class="contai-label">
     136                            <?php esc_html_e( 'Business Activity', '1platform-content-ai' ); ?>
     137                            <span class="contai-required">*</span>
     138                        </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">
     143                        <label for="contai_legal_address" class="contai-label">
     144                            <?php esc_html_e( 'Business Address', '1platform-content-ai' ); ?>
     145                            <span class="contai-required">*</span>
     146                        </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>
     148                    </div>
     149                </div>
     150            </div>
     151        </div>
     152
     153        <!-- Step 3: Content Generation Settings -->
     154        <div class="contai-wizard-section">
     155            <div class="contai-section-header">
     156                <div class="contai-step-indicator">
     157                    <span class="contai-step-number">3</span>
    151158                </div>
    152159                <div class="contai-section-title-group">
  • 1platform-content-ai/tags/2.7.0/includes/admin/assets/css/admin-ai-site-generator.css

    r3483422 r3488242  
    183183.contai-span-full {
    184184    grid-column: 1 / -1;
     185}
     186
     187.contai-span-2 {
     188    grid-column: span 2;
    185189}
    186190
     
    663667        grid-column: 1 / -1;
    664668    }
     669
     670    .contai-span-2 {
     671        grid-column: 1 / -1;
     672    }
    665673}
    666674
     
    711719    }
    712720
     721    .contai-span-2 {
     722        grid-column: 1;
     723    }
     724
    713725    .contai-input,
    714726    .contai-select {
  • 1platform-content-ai/tags/2.7.0/includes/admin/assets/js/tai-category-sync.js

    r3483422 r3488242  
    11/**
    2  * Category language sync for Content AI admin forms.
     2 * Category language sync and theme auto-selection for Content AI admin forms.
    33 *
    4  * Reads data-category-select / data-lang-select attributes from the language
    5  * <select> and updates category option labels when the language changes.
     4 * 1. Language sync: Updates category option labels when language changes.
     5 *    Expects the language select to have data-category-select="#id" pointing at
     6 *    the category select, and each category <option> to carry data-title-en and
     7 *    data-title-es attributes.
    68 *
    7  * Expects the language select to have data-category-select="#id" pointing at
    8  * the category select, and each category <option> to carry data-title-en and
    9  * data-title-es attributes.
     9 * 2. Theme auto-selection: When category changes, reads data-theme from the
     10 *    selected option and updates the hidden contai_wordpress_theme input.
     11 *    Also updates the readonly display field if present (Settings form).
    1012 *
    1113 * @package ContentAI
     
    1416    'use strict';
    1517
     18    // Language sync
    1619    document.querySelectorAll('select[data-category-select]').forEach(function (languageSelect) {
    1720        var categorySelector = languageSelect.getAttribute('data-category-select');
     
    4346        });
    4447    });
     48
     49    // Theme auto-selection based on category
     50    document.querySelectorAll('select[data-lang-select]').forEach(function (categorySelect) {
     51        var themeInput   = document.getElementById('contai_wordpress_theme');
     52        var themeDisplay = document.getElementById('contai_wordpress_theme_display');
     53
     54        if (!themeInput) {
     55            return;
     56        }
     57
     58        function updateTheme() {
     59            var selected = categorySelect.options[categorySelect.selectedIndex];
     60            var theme    = selected ? selected.getAttribute('data-theme') : null;
     61
     62            if (theme) {
     63                themeInput.value = theme;
     64                if (themeDisplay) {
     65                    themeDisplay.value = theme.charAt(0).toUpperCase() + theme.slice(1);
     66                }
     67            }
     68        }
     69
     70        categorySelect.addEventListener('change', updateTheme);
     71
     72        // Set initial theme if a category is already selected
     73        if (categorySelect.value) {
     74            updateTheme();
     75        }
     76    });
    4577})();
  • 1platform-content-ai/tags/2.7.0/includes/admin/init-configuration/site-configuration-form.php

    r3483422 r3488242  
    1010    $site_topic = esc_attr( get_option( 'contai_site_theme', 'blog' ) );
    1111    $site_language = esc_attr( get_option( 'contai_site_language', 'spanish' ) );
    12     $wordpress_theme = esc_attr( get_option( 'contai_wordpress_theme', 'blogfull' ) );
    1312    $languages = array( 'english', 'spanish' );
    14     $themes = array( 'blogfull', 'coral-dark', 'news-portal', 'hyper-news', 'celebnews', 'nova-blog' );
    1513
    1614    // Fetch categories for the select field
     
    7977                                    $title_en = esc_html( $category['title']['en'] ?? 'Unnamed Category' );
    8078                                    $title_es = esc_html( $category['title']['es'] ?? $title_en );
     79                                    $category_theme = esc_attr( $category['recommended_theme'] ?? 'astra' );
    8180                                    $is_selected = ( $saved_category === $category_id );
    8281                                    ?>
    83                                     <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>">
     82                                    <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>" data-theme="<?php echo esc_attr( $category_theme ); ?>">
    8483                                        <?php
    8584                                        $current_lang = ContaiCategoryAPIService::normalizeLanguage( $site_language );
     
    9493
    9594                    <div class="contai-form-group">
    96                         <label for="contai_wordpress_theme" class="contai-label">
     95                        <label for="contai_wordpress_theme_display" class="contai-label">
    9796                            <span class="dashicons dashicons-art"></span>
    9897                            <?php esc_html_e( 'WordPress Theme', '1platform-content-ai' ); ?>
    9998                        </label>
    100                         <select id="contai_wordpress_theme" name="contai_wordpress_theme" class="contai-select">
    101                             <?php foreach ( $themes as $theme ) : ?>
    102                                 <option value="<?php echo esc_attr( $theme ); ?>"
    103                                     <?php selected( $wordpress_theme, $theme ); ?>>
    104                                     <?php echo esc_html( ucfirst( str_replace( '-', ' ', $theme ) ) ); ?>
    105                                 </option>
    106                             <?php endforeach; ?>
    107                         </select>
    108                         <p class="contai-help-text"><?php esc_html_e( 'Select the WordPress theme to be installed', '1platform-content-ai' ); ?></p>
     99                        <input type="text" id="contai_wordpress_theme_display" class="contai-input" readonly
     100                               value="<?php echo esc_attr( ucfirst( get_option( 'contai_wordpress_theme', 'astra' ) ) ); ?>"
     101                               style="background-color: #f0f0f1; cursor: default;">
     102                        <input type="hidden" id="contai_wordpress_theme" name="contai_wordpress_theme"
     103                               value="<?php echo esc_attr( get_option( 'contai_wordpress_theme', 'astra' ) ); ?>">
     104                        <p class="contai-help-text"><?php esc_html_e( 'Automatically assigned based on the selected category', '1platform-content-ai' ); ?></p>
    109105                    </div>
    110106                </div>
  • 1platform-content-ai/tags/2.7.0/includes/admin/licenses/WPContentAILicensePanel.php

    r3483422 r3488242  
    310310        }
    311311
     312        // First attempt failed — force-refresh all tokens and retry once.
     313        // This covers cases where token generation failed transiently
     314        // and the OnePlatformClient retry was also exhausted.
     315        contai_log('Content AI: Profile fetch failed on first attempt, force-refreshing tokens and retrying');
     316        $authService = ContaiOnePlatformAuthService::create();
     317        $refreshResult = $authService->forceRefreshAllTokens();
     318
     319        if (!$refreshResult['success']) {
     320            return false;
     321        }
     322
     323        $retryResponse = $this->service->fetchUserProfile();
     324
     325        if ($retryResponse->isSuccess()) {
     326            $data = $retryResponse->getData();
     327            if ($data) {
     328                $this->service->saveUserProfile($data);
     329            }
     330            return true;
     331        }
     332
    312333        return false;
    313334    }
  • 1platform-content-ai/tags/2.7.0/includes/helpers/crypto.php

    r3483422 r3488242  
    2424
    2525        if ($data === false || strpos($data, '::') === false) {
     26            // Not in encrypted format — return original value (legacy unencrypted key)
    2627            return $encrypted_key;
    2728        }
     
    3031
    3132        if (count($parts) !== 2) {
    32             return $encrypted_key;
     33            contai_log('Content AI Decrypt: invalid encrypted format (unexpected parts)');
     34            return '';
    3335        }
    3436
     
    3638
    3739        if (empty($iv)) {
    38             return $encrypted_key;
     40            contai_log('Content AI Decrypt: invalid encrypted format (empty IV)');
     41            return '';
    3942        }
    4043
    4144        $decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $encryption_key, 0, $iv);
    4245
    43         return $decrypted !== false ? $decrypted : $encrypted_key;
     46        if ($decrypted === false) {
     47            contai_log('Content AI Decrypt: openssl_decrypt failed — possible salt change or corrupted data');
     48            return '';
     49        }
     50
     51        return $decrypted;
    4452    } catch (Exception $e) {
    45         contai_log('Decryption error: ' . $e->getMessage());
    46         return $encrypted_key;
     53        contai_log('Content AI Decrypt error: ' . $e->getMessage());
     54        return '';
    4755    }
    4856}
  • 1platform-content-ai/tags/2.7.0/includes/helpers/site-generation.php

    r3483422 r3488242  
    1919require_once __DIR__ . '/../services/api/OnePlatformEndpoints.php';
    2020require_once __DIR__ . '/../providers/WebsiteProvider.php';
     21
     22/**
     23 * Get the primary sidebar ID for the active theme.
     24 *
     25 * Different themes register sidebars with different IDs. This function
     26 * detects the correct sidebar by checking common naming conventions.
     27 *
     28 * @return string The primary sidebar ID
     29 */
     30function contai_get_primary_sidebar_id(): string {
     31    global $wp_registered_sidebars;
     32
     33    if ( empty( $wp_registered_sidebars ) ) {
     34        return 'sidebar-1';
     35    }
     36
     37    $priority = array( 'sidebar-1', 'sidebar', 'sidebar-primary', 'primary-sidebar', 'primary-widget-area' );
     38    foreach ( $priority as $id ) {
     39        if ( isset( $wp_registered_sidebars[ $id ] ) ) {
     40            return $id;
     41        }
     42    }
     43
     44    // Fallback: first registered sidebar
     45    $keys = array_keys( $wp_registered_sidebars );
     46    return $keys[0] ?? 'sidebar-1';
     47}
     48
     49/**
     50 * Apply theme-specific default settings after installation.
     51 *
     52 * Each theme may need different reading settings, sidebar layouts,
     53 * or other configuration to look good out of the box with generated content.
     54 *
     55 * @param string $theme Theme slug
     56 * @return void
     57 */
     58function contai_apply_theme_defaults( string $theme ): void {
     59    // Common defaults for all themes
     60    update_option( 'show_on_front', 'posts' );
     61    update_option( 'posts_per_page', 10 );
     62
     63    switch ( $theme ) {
     64        case 'newsmatic':
     65            if ( function_exists( 'contai_set_newsmatic_reading_defaults' ) ) {
     66                contai_set_newsmatic_reading_defaults();
     67            }
     68            break;
     69
     70        case 'oceanwp':
     71            set_theme_mod( 'ocean_blog_layout', 'right-sidebar' );
     72            break;
     73
     74        case 'generatepress':
     75            set_theme_mod( 'content_layout_setting', 'content-sidebar' );
     76            break;
     77
     78        case 'colormag':
     79            set_theme_mod( 'colormag_site_layout', 'right-sidebar' );
     80            break;
     81
     82        // astra, neve, blocksy, kadence, sydney: sensible defaults out of the box
     83    }
     84}
    2185
    2286/**
     
    117181    update_option( 'permalink_structure', '/%postname%/' );
    118182    update_option( 'contai_flush_rewrite', true );
    119 
    120     if ( function_exists( 'contai_set_newsmatic_reading_defaults' ) ) {
    121         contai_set_newsmatic_reading_defaults();
    122     }
    123183
    124184    contai_delete_sample_content();
     
    322382
    323383    $sidebars_widgets = get_option( 'sidebars_widgets', array() );
    324     $sidebar_id       = 'sidebar-1';
     384    $sidebar_id       = contai_get_primary_sidebar_id();
    325385    $sidebars_widgets[ $sidebar_id ] = array();
    326386
  • 1platform-content-ai/tags/2.7.0/includes/services/api/OnePlatformClient.php

    r3483441 r3488242  
    9898
    9999        if ($auth_headers === null) {
     100            if ($retry_count < $this->config->getMaxRetries()) {
     101                contai_log('Content AI: Auth token generation failed, force-refreshing and retrying');
     102                $this->auth_service->forceRefreshAllTokens();
     103                return $this->request($method, $url, $data, $retry_count + 1);
     104            }
    100105            return $this->createAuthFailedResponse();
    101106        }
  • 1platform-content-ai/tags/2.7.0/includes/services/setup/SiteConfigService.php

    r3483422 r3488242  
    99        $siteTopic = $config['site_topic'] ?? '';
    1010        $siteLanguage = $config['site_language'] ?? 'english';
    11         $wordpressTheme = $config['wordpress_theme'] ?? 'blogfull';
     11        $wordpressTheme = $config['wordpress_theme'] ?? 'astra';
    1212
    1313        if (empty($siteTopic)) {
     
    4747            'site_topic' => get_option('contai_site_theme', ''),
    4848            'site_language' => get_option('contai_site_language', 'english'),
    49             'wordpress_theme' => get_option('contai_wordpress_theme', 'blogfull'),
     49            'wordpress_theme' => get_option('contai_wordpress_theme', 'astra'),
    5050        ];
    5151    }
  • 1platform-content-ai/tags/2.7.0/includes/services/setup/WebsiteGenerationService.php

    r3483422 r3488242  
    44
    55require_once __DIR__ . '/../../helpers/site-generation.php';
     6require_once __DIR__ . '/../../providers/WebsiteProvider.php';
    67require_once __DIR__ . '/../legal/LegalPagesGenerator.php';
    78
     
    1718
    1819        try {
    19             $theme = get_option('contai_wordpress_theme', 'blogfull');
     20            $theme = get_option('contai_wordpress_theme', 'astra');
    2021
    2122            contai_install_theme($theme);
    22             $results['steps'][] = 'Theme installed';
     23            contai_apply_theme_defaults($theme);
     24            $results['steps'][] = 'Theme installed and configured';
     25
     26            try {
     27                $website_provider = new ContaiWebsiteProvider();
     28                $website_provider->updateWebsite( array( 'theme' => sanitize_text_field( $theme ) ) );
     29                $results['steps'][] = 'Theme tracked in API';
     30            } catch ( Exception $e ) {
     31                $results['errors'][] = 'Theme tracking failed (non-critical): ' . $e->getMessage();
     32            }
    2333
    2434            contai_setup_site_config();
  • 1platform-content-ai/tags/2.7.0/readme.txt

    r3487968 r3488242  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 2.5.0
     7Stable tag: 2.7.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
  • 1platform-content-ai/trunk/.git/FETCH_HEAD

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05        branch 'main' of https://github.com/1platformlabs/1platform-content-ai
     10b507e94120943ce7672264963c81dd809d669f1        branch 'main' of https://github.com/1platformlabs/1platform-content-ai
  • 1platform-content-ai/trunk/.git/ORIG_HEAD

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05
     10b507e94120943ce7672264963c81dd809d669f1
  • 1platform-content-ai/trunk/.git/config

    r3487968 r3488242  
    1010    auto = 0
    1111[http "https://github.com/"]
    12     extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzX0lyQ1dNZlRNZUNQTTV2V0VIckJrNFY5SDVVSUxFMDJRVW5ycw==
     12    extraheader = AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2hzXzZmZ1hBU01NQ25ORDF3aHA1aE5Rczl2dVpsRzBYMDNNcUZzVA==
    1313[branch "main"]
    1414    remote = origin
  • 1platform-content-ai/trunk/.git/logs/HEAD

    r3487968 r3488242  
    1 0000000000000000000000000000000000000000 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05 runner <runner@runnervm46oaq.xgcnp5xq0a5uzhbzbke14hj00f.gx.internal.cloudapp.net> 1774128261 +0000    checkout: moving from master to main
     10000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052 +0000    checkout: moving from master to main
  • 1platform-content-ai/trunk/.git/logs/refs/heads/main

    r3487968 r3488242  
    1 0000000000000000000000000000000000000000 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05 runner <runner@runnervm46oaq.xgcnp5xq0a5uzhbzbke14hj00f.gx.internal.cloudapp.net> 1774128261 +0000    branch: Created from refs/remotes/origin/main
     10000000000000000000000000000000000000000 0b507e94120943ce7672264963c81dd809d669f1 runner <runner@runnervm46oaq.2d4yuw4mzllehnbsihy5bpj2mb.cx.internal.cloudapp.net> 1774189052 +0000    branch: Created from refs/remotes/origin/main
  • 1platform-content-ai/trunk/.git/logs/refs/remotes/origin/main

    r3487968 r3488242  
    1 0000000000000000000000000000000000000000 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05 runner <runner@runnervm46oaq.xgcnp5xq0a5uzhbzbke14hj00f.gx.internal.cloudapp.net> 1774128261 +0000    fetch --prune --no-recurse-submodules origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*: storing head
     10000000000000000000000000000000000000000 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 head
  • 1platform-content-ai/trunk/.git/refs/heads/main

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05
     10b507e94120943ce7672264963c81dd809d669f1
  • 1platform-content-ai/trunk/.git/refs/remotes/origin/main

    r3487968 r3488242  
    1 6afa3c8a66ae5d8ab09b2c8d1fc2f42753b26e05
     10b507e94120943ce7672264963c81dd809d669f1
  • 1platform-content-ai/trunk/1platform-content-ai.php

    r3487968 r3488242  
    55 * Plugin URI: https://1platform.pro/
    66 * 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.5.0
     7 * Version: 2.7.0
    88 * Author: 1Platform
    99 * License: GPLv2 or later
  • 1platform-content-ai/trunk/includes/admin/admin-ai-site-generator.php

    r3483422 r3488242  
    8484                'site_language' => sanitize_text_field( wp_unslash( $_POST['contai_site_language'] ?? 'english' ) ),
    8585                'site_category' => sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ?? '' ) ),
    86                 'wordpress_theme' => sanitize_text_field( wp_unslash( $_POST['contai_wordpress_theme'] ?? 'blogfull' ) ),
     86                'wordpress_theme' => sanitize_text_field( wp_unslash( $_POST['contai_wordpress_theme'] ?? 'astra' ) ),
    8787            ),
    8888            'legal_info' => array(
  • 1platform-content-ai/trunk/includes/admin/admin-init-configuration.php

    r3483422 r3488242  
    6666
    6767    if ( empty( $wordpress_theme ) ) {
    68         $wordpress_theme = 'blogfull';
     68        $wordpress_theme = 'astra';
    6969    }
    7070
  • 1platform-content-ai/trunk/includes/admin/ai-site-generator/site-generator-form.php

    r3483422 r3488242  
    1818        <input type="hidden" name="contai_start_site_generation" value="1">
    1919
    20         <!-- Step 1: Site & Business Configuration -->
     20        <input type="hidden" id="contai_wordpress_theme" name="contai_wordpress_theme" value="astra">
     21
     22        <!-- Step 1: Website Identity -->
    2123        <div class="contai-wizard-section">
    2224            <div class="contai-section-header">
     
    2527                </div>
    2628                <div class="contai-section-title-group">
    27                     <h2 class="contai-section-title"><?php esc_html_e( 'Site & Business Configuration', '1platform-content-ai' ); ?></h2>
    28                     <p class="contai-section-description"><?php esc_html_e( 'Define your website identity, target audience, and legal information.', '1platform-content-ai' ); ?></p>
     29                    <h2 class="contai-section-title"><?php esc_html_e( 'Website Identity', '1platform-content-ai' ); ?></h2>
     30                    <p class="contai-section-description"><?php esc_html_e( 'Define what your website is about and who it targets.', '1platform-content-ai' ); ?></p>
    2931                </div>
    3032            </div>
     
    3739                        </label>
    3840                        <input type="text" id="contai_site_topic" name="contai_site_topic" class="contai-input" placeholder="e.g., Technology News" autocomplete="off" required>
    39                     </div>
    40 
    41                     <div class="contai-form-group">
    42                         <label for="contai_wordpress_theme" class="contai-label">
    43                             <?php esc_html_e( 'WordPress Theme', '1platform-content-ai' ); ?>
    44                             <span class="contai-required">*</span>
    45                         </label>
    46                         <select id="contai_wordpress_theme" name="contai_wordpress_theme" class="contai-select" autocomplete="off" required>
    47                             <option value="blogfull" selected>Blogfull</option>
    48                             <option value="newsmatic">Newsmatic</option>
    49                         </select>
    50                     </div>
    51 
    52                     <div class="contai-form-group">
    53                         <label for="contai_site_language" class="contai-label">
    54                             <?php esc_html_e( 'Language', '1platform-content-ai' ); ?>
    55                             <span class="contai-required">*</span>
    56                         </label>
    57                         <select id="contai_site_language" name="contai_site_language" class="contai-select" autocomplete="language" required data-category-select="#contai_site_category">
    58                             <option value="english" selected><?php esc_html_e( 'English', '1platform-content-ai' ); ?></option>
    59                             <option value="spanish"><?php esc_html_e( 'Spanish', '1platform-content-ai' ); ?></option>
    60                         </select>
     41                        <span class="contai-help-text"><?php esc_html_e( 'The main subject of your website', '1platform-content-ai' ); ?></span>
    6142                    </div>
    6243
     
    7657                                    $title_en = esc_html( $category['title']['en'] ?? 'Unnamed Category' );
    7758                                    $title_es = esc_html( $category['title']['es'] ?? $title_en );
     59                                    $category_theme = esc_attr( $category['recommended_theme'] ?? 'astra' );
    7860                                    $is_selected = ( $saved_category === $category_id );
    7961                                    ?>
    80                                     <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>">
     62                                    <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>" data-theme="<?php echo esc_attr( $category_theme ); ?>">
    8163                                        <?php echo esc_html( $title_en ); ?>
    8264                                    </option>
     
    8466                            <?php endif; ?>
    8567                        </select>
     68                        <span class="contai-help-text"><?php esc_html_e( 'Determines the theme and content style', '1platform-content-ai' ); ?></span>
     69                    </div>
     70
     71                    <div class="contai-form-group">
     72                        <label for="contai_site_language" class="contai-label">
     73                            <?php esc_html_e( 'Language', '1platform-content-ai' ); ?>
     74                            <span class="contai-required">*</span>
     75                        </label>
     76                        <select id="contai_site_language" name="contai_site_language" class="contai-select" autocomplete="language" required data-category-select="#contai_site_category">
     77                            <option value="english" selected><?php esc_html_e( 'English', '1platform-content-ai' ); ?></option>
     78                            <option value="spanish"><?php esc_html_e( 'Spanish', '1platform-content-ai' ); ?></option>
     79                        </select>
    8680                    </div>
    8781
     
    9791                    </div>
    9892
    99                     <div class="contai-form-group">
     93                    <div class="contai-form-group contai-span-2">
    10094                        <label for="contai_adsense_publisher" class="contai-label">
    10195                            <?php esc_html_e( 'AdSense Publisher ID', '1platform-content-ai' ); ?>
     
    10397                        </label>
    10498                        <input type="text" id="contai_adsense_publisher" name="contai_adsense_publisher" class="contai-input" placeholder="pub-1234567890123456" autocomplete="off" spellcheck="false" required>
    105                     </div>
    106                 </div>
    107 
    108                 <div class="contai-form-divider"></div>
    109 
    110                 <div class="contai-form-grid contai-grid-3">
    111                     <div class="contai-form-group">
    112                         <label for="contai_legal_owner" class="contai-label">
    113                             <?php esc_html_e( 'Business Owner', '1platform-content-ai' ); ?>
    114                             <span class="contai-required">*</span>
    115                         </label>
    116                         <input type="text" id="contai_legal_owner" name="contai_legal_owner" class="contai-input" autocomplete="name" required>
    117                     </div>
    118 
    119                     <div class="contai-form-group">
    120                         <label for="contai_legal_email" class="contai-label">
    121                             <?php esc_html_e( 'Contact Email', '1platform-content-ai' ); ?>
    122                             <span class="contai-required">*</span>
    123                         </label>
    124                         <input type="email" id="contai_legal_email" name="contai_legal_email" class="contai-input" autocomplete="email" spellcheck="false" required>
    125                     </div>
    126 
    127                     <div class="contai-form-group">
    128                         <label for="contai_legal_activity" class="contai-label">
    129                             <?php esc_html_e( 'Business Activity', '1platform-content-ai' ); ?>
    130                             <span class="contai-required">*</span>
    131                         </label>
    132                         <input type="text" id="contai_legal_activity" name="contai_legal_activity" class="contai-input" autocomplete="organization-title" required>
    133                     </div>
    134 
    135                     <div class="contai-form-group contai-span-full">
    136                         <label for="contai_legal_address" class="contai-label">
    137                             <?php esc_html_e( 'Business Address', '1platform-content-ai' ); ?>
    138                             <span class="contai-required">*</span>
    139                         </label>
    140                         <input type="text" id="contai_legal_address" name="contai_legal_address" class="contai-input" autocomplete="street-address" required>
    141                     </div>
    142                 </div>
    143             </div>
    144         </div>
    145 
    146         <!-- Step 2: Content Generation Settings -->
     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>
     100                    </div>
     101                </div>
     102            </div>
     103        </div>
     104
     105        <!-- Step 2: Legal Information -->
    147106        <div class="contai-wizard-section">
    148107            <div class="contai-section-header">
    149108                <div class="contai-step-indicator">
    150109                    <span class="contai-step-number">2</span>
     110                </div>
     111                <div class="contai-section-title-group">
     112                    <h2 class="contai-section-title"><?php esc_html_e( 'Legal Information', '1platform-content-ai' ); ?></h2>
     113                    <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                </div>
     115            </div>
     116            <div class="contai-section-body">
     117                <div class="contai-form-grid contai-grid-3">
     118                    <div class="contai-form-group">
     119                        <label for="contai_legal_owner" class="contai-label">
     120                            <?php esc_html_e( 'Business Owner', '1platform-content-ai' ); ?>
     121                            <span class="contai-required">*</span>
     122                        </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>
     124                    </div>
     125
     126                    <div class="contai-form-group">
     127                        <label for="contai_legal_email" class="contai-label">
     128                            <?php esc_html_e( 'Contact Email', '1platform-content-ai' ); ?>
     129                            <span class="contai-required">*</span>
     130                        </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>
     132                    </div>
     133
     134                    <div class="contai-form-group">
     135                        <label for="contai_legal_activity" class="contai-label">
     136                            <?php esc_html_e( 'Business Activity', '1platform-content-ai' ); ?>
     137                            <span class="contai-required">*</span>
     138                        </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">
     143                        <label for="contai_legal_address" class="contai-label">
     144                            <?php esc_html_e( 'Business Address', '1platform-content-ai' ); ?>
     145                            <span class="contai-required">*</span>
     146                        </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>
     148                    </div>
     149                </div>
     150            </div>
     151        </div>
     152
     153        <!-- Step 3: Content Generation Settings -->
     154        <div class="contai-wizard-section">
     155            <div class="contai-section-header">
     156                <div class="contai-step-indicator">
     157                    <span class="contai-step-number">3</span>
    151158                </div>
    152159                <div class="contai-section-title-group">
  • 1platform-content-ai/trunk/includes/admin/assets/css/admin-ai-site-generator.css

    r3483422 r3488242  
    183183.contai-span-full {
    184184    grid-column: 1 / -1;
     185}
     186
     187.contai-span-2 {
     188    grid-column: span 2;
    185189}
    186190
     
    663667        grid-column: 1 / -1;
    664668    }
     669
     670    .contai-span-2 {
     671        grid-column: 1 / -1;
     672    }
    665673}
    666674
     
    711719    }
    712720
     721    .contai-span-2 {
     722        grid-column: 1;
     723    }
     724
    713725    .contai-input,
    714726    .contai-select {
  • 1platform-content-ai/trunk/includes/admin/assets/js/tai-category-sync.js

    r3483422 r3488242  
    11/**
    2  * Category language sync for Content AI admin forms.
     2 * Category language sync and theme auto-selection for Content AI admin forms.
    33 *
    4  * Reads data-category-select / data-lang-select attributes from the language
    5  * <select> and updates category option labels when the language changes.
     4 * 1. Language sync: Updates category option labels when language changes.
     5 *    Expects the language select to have data-category-select="#id" pointing at
     6 *    the category select, and each category <option> to carry data-title-en and
     7 *    data-title-es attributes.
    68 *
    7  * Expects the language select to have data-category-select="#id" pointing at
    8  * the category select, and each category <option> to carry data-title-en and
    9  * data-title-es attributes.
     9 * 2. Theme auto-selection: When category changes, reads data-theme from the
     10 *    selected option and updates the hidden contai_wordpress_theme input.
     11 *    Also updates the readonly display field if present (Settings form).
    1012 *
    1113 * @package ContentAI
     
    1416    'use strict';
    1517
     18    // Language sync
    1619    document.querySelectorAll('select[data-category-select]').forEach(function (languageSelect) {
    1720        var categorySelector = languageSelect.getAttribute('data-category-select');
     
    4346        });
    4447    });
     48
     49    // Theme auto-selection based on category
     50    document.querySelectorAll('select[data-lang-select]').forEach(function (categorySelect) {
     51        var themeInput   = document.getElementById('contai_wordpress_theme');
     52        var themeDisplay = document.getElementById('contai_wordpress_theme_display');
     53
     54        if (!themeInput) {
     55            return;
     56        }
     57
     58        function updateTheme() {
     59            var selected = categorySelect.options[categorySelect.selectedIndex];
     60            var theme    = selected ? selected.getAttribute('data-theme') : null;
     61
     62            if (theme) {
     63                themeInput.value = theme;
     64                if (themeDisplay) {
     65                    themeDisplay.value = theme.charAt(0).toUpperCase() + theme.slice(1);
     66                }
     67            }
     68        }
     69
     70        categorySelect.addEventListener('change', updateTheme);
     71
     72        // Set initial theme if a category is already selected
     73        if (categorySelect.value) {
     74            updateTheme();
     75        }
     76    });
    4577})();
  • 1platform-content-ai/trunk/includes/admin/init-configuration/site-configuration-form.php

    r3483422 r3488242  
    1010    $site_topic = esc_attr( get_option( 'contai_site_theme', 'blog' ) );
    1111    $site_language = esc_attr( get_option( 'contai_site_language', 'spanish' ) );
    12     $wordpress_theme = esc_attr( get_option( 'contai_wordpress_theme', 'blogfull' ) );
    1312    $languages = array( 'english', 'spanish' );
    14     $themes = array( 'blogfull', 'coral-dark', 'news-portal', 'hyper-news', 'celebnews', 'nova-blog' );
    1513
    1614    // Fetch categories for the select field
     
    7977                                    $title_en = esc_html( $category['title']['en'] ?? 'Unnamed Category' );
    8078                                    $title_es = esc_html( $category['title']['es'] ?? $title_en );
     79                                    $category_theme = esc_attr( $category['recommended_theme'] ?? 'astra' );
    8180                                    $is_selected = ( $saved_category === $category_id );
    8281                                    ?>
    83                                     <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>">
     82                                    <option value="<?php echo esc_attr( $category_id ); ?>"<?php selected( $is_selected ); ?> data-title-en="<?php echo esc_attr( $title_en ); ?>" data-title-es="<?php echo esc_attr( $title_es ); ?>" data-theme="<?php echo esc_attr( $category_theme ); ?>">
    8483                                        <?php
    8584                                        $current_lang = ContaiCategoryAPIService::normalizeLanguage( $site_language );
     
    9493
    9594                    <div class="contai-form-group">
    96                         <label for="contai_wordpress_theme" class="contai-label">
     95                        <label for="contai_wordpress_theme_display" class="contai-label">
    9796                            <span class="dashicons dashicons-art"></span>
    9897                            <?php esc_html_e( 'WordPress Theme', '1platform-content-ai' ); ?>
    9998                        </label>
    100                         <select id="contai_wordpress_theme" name="contai_wordpress_theme" class="contai-select">
    101                             <?php foreach ( $themes as $theme ) : ?>
    102                                 <option value="<?php echo esc_attr( $theme ); ?>"
    103                                     <?php selected( $wordpress_theme, $theme ); ?>>
    104                                     <?php echo esc_html( ucfirst( str_replace( '-', ' ', $theme ) ) ); ?>
    105                                 </option>
    106                             <?php endforeach; ?>
    107                         </select>
    108                         <p class="contai-help-text"><?php esc_html_e( 'Select the WordPress theme to be installed', '1platform-content-ai' ); ?></p>
     99                        <input type="text" id="contai_wordpress_theme_display" class="contai-input" readonly
     100                               value="<?php echo esc_attr( ucfirst( get_option( 'contai_wordpress_theme', 'astra' ) ) ); ?>"
     101                               style="background-color: #f0f0f1; cursor: default;">
     102                        <input type="hidden" id="contai_wordpress_theme" name="contai_wordpress_theme"
     103                               value="<?php echo esc_attr( get_option( 'contai_wordpress_theme', 'astra' ) ); ?>">
     104                        <p class="contai-help-text"><?php esc_html_e( 'Automatically assigned based on the selected category', '1platform-content-ai' ); ?></p>
    109105                    </div>
    110106                </div>
  • 1platform-content-ai/trunk/includes/admin/licenses/WPContentAILicensePanel.php

    r3483422 r3488242  
    310310        }
    311311
     312        // First attempt failed — force-refresh all tokens and retry once.
     313        // This covers cases where token generation failed transiently
     314        // and the OnePlatformClient retry was also exhausted.
     315        contai_log('Content AI: Profile fetch failed on first attempt, force-refreshing tokens and retrying');
     316        $authService = ContaiOnePlatformAuthService::create();
     317        $refreshResult = $authService->forceRefreshAllTokens();
     318
     319        if (!$refreshResult['success']) {
     320            return false;
     321        }
     322
     323        $retryResponse = $this->service->fetchUserProfile();
     324
     325        if ($retryResponse->isSuccess()) {
     326            $data = $retryResponse->getData();
     327            if ($data) {
     328                $this->service->saveUserProfile($data);
     329            }
     330            return true;
     331        }
     332
    312333        return false;
    313334    }
  • 1platform-content-ai/trunk/includes/helpers/crypto.php

    r3483422 r3488242  
    2424
    2525        if ($data === false || strpos($data, '::') === false) {
     26            // Not in encrypted format — return original value (legacy unencrypted key)
    2627            return $encrypted_key;
    2728        }
     
    3031
    3132        if (count($parts) !== 2) {
    32             return $encrypted_key;
     33            contai_log('Content AI Decrypt: invalid encrypted format (unexpected parts)');
     34            return '';
    3335        }
    3436
     
    3638
    3739        if (empty($iv)) {
    38             return $encrypted_key;
     40            contai_log('Content AI Decrypt: invalid encrypted format (empty IV)');
     41            return '';
    3942        }
    4043
    4144        $decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $encryption_key, 0, $iv);
    4245
    43         return $decrypted !== false ? $decrypted : $encrypted_key;
     46        if ($decrypted === false) {
     47            contai_log('Content AI Decrypt: openssl_decrypt failed — possible salt change or corrupted data');
     48            return '';
     49        }
     50
     51        return $decrypted;
    4452    } catch (Exception $e) {
    45         contai_log('Decryption error: ' . $e->getMessage());
    46         return $encrypted_key;
     53        contai_log('Content AI Decrypt error: ' . $e->getMessage());
     54        return '';
    4755    }
    4856}
  • 1platform-content-ai/trunk/includes/helpers/site-generation.php

    r3483422 r3488242  
    1919require_once __DIR__ . '/../services/api/OnePlatformEndpoints.php';
    2020require_once __DIR__ . '/../providers/WebsiteProvider.php';
     21
     22/**
     23 * Get the primary sidebar ID for the active theme.
     24 *
     25 * Different themes register sidebars with different IDs. This function
     26 * detects the correct sidebar by checking common naming conventions.
     27 *
     28 * @return string The primary sidebar ID
     29 */
     30function contai_get_primary_sidebar_id(): string {
     31    global $wp_registered_sidebars;
     32
     33    if ( empty( $wp_registered_sidebars ) ) {
     34        return 'sidebar-1';
     35    }
     36
     37    $priority = array( 'sidebar-1', 'sidebar', 'sidebar-primary', 'primary-sidebar', 'primary-widget-area' );
     38    foreach ( $priority as $id ) {
     39        if ( isset( $wp_registered_sidebars[ $id ] ) ) {
     40            return $id;
     41        }
     42    }
     43
     44    // Fallback: first registered sidebar
     45    $keys = array_keys( $wp_registered_sidebars );
     46    return $keys[0] ?? 'sidebar-1';
     47}
     48
     49/**
     50 * Apply theme-specific default settings after installation.
     51 *
     52 * Each theme may need different reading settings, sidebar layouts,
     53 * or other configuration to look good out of the box with generated content.
     54 *
     55 * @param string $theme Theme slug
     56 * @return void
     57 */
     58function contai_apply_theme_defaults( string $theme ): void {
     59    // Common defaults for all themes
     60    update_option( 'show_on_front', 'posts' );
     61    update_option( 'posts_per_page', 10 );
     62
     63    switch ( $theme ) {
     64        case 'newsmatic':
     65            if ( function_exists( 'contai_set_newsmatic_reading_defaults' ) ) {
     66                contai_set_newsmatic_reading_defaults();
     67            }
     68            break;
     69
     70        case 'oceanwp':
     71            set_theme_mod( 'ocean_blog_layout', 'right-sidebar' );
     72            break;
     73
     74        case 'generatepress':
     75            set_theme_mod( 'content_layout_setting', 'content-sidebar' );
     76            break;
     77
     78        case 'colormag':
     79            set_theme_mod( 'colormag_site_layout', 'right-sidebar' );
     80            break;
     81
     82        // astra, neve, blocksy, kadence, sydney: sensible defaults out of the box
     83    }
     84}
    2185
    2286/**
     
    117181    update_option( 'permalink_structure', '/%postname%/' );
    118182    update_option( 'contai_flush_rewrite', true );
    119 
    120     if ( function_exists( 'contai_set_newsmatic_reading_defaults' ) ) {
    121         contai_set_newsmatic_reading_defaults();
    122     }
    123183
    124184    contai_delete_sample_content();
     
    322382
    323383    $sidebars_widgets = get_option( 'sidebars_widgets', array() );
    324     $sidebar_id       = 'sidebar-1';
     384    $sidebar_id       = contai_get_primary_sidebar_id();
    325385    $sidebars_widgets[ $sidebar_id ] = array();
    326386
  • 1platform-content-ai/trunk/includes/services/api/OnePlatformClient.php

    r3483441 r3488242  
    9898
    9999        if ($auth_headers === null) {
     100            if ($retry_count < $this->config->getMaxRetries()) {
     101                contai_log('Content AI: Auth token generation failed, force-refreshing and retrying');
     102                $this->auth_service->forceRefreshAllTokens();
     103                return $this->request($method, $url, $data, $retry_count + 1);
     104            }
    100105            return $this->createAuthFailedResponse();
    101106        }
  • 1platform-content-ai/trunk/includes/services/setup/SiteConfigService.php

    r3483422 r3488242  
    99        $siteTopic = $config['site_topic'] ?? '';
    1010        $siteLanguage = $config['site_language'] ?? 'english';
    11         $wordpressTheme = $config['wordpress_theme'] ?? 'blogfull';
     11        $wordpressTheme = $config['wordpress_theme'] ?? 'astra';
    1212
    1313        if (empty($siteTopic)) {
     
    4747            'site_topic' => get_option('contai_site_theme', ''),
    4848            'site_language' => get_option('contai_site_language', 'english'),
    49             'wordpress_theme' => get_option('contai_wordpress_theme', 'blogfull'),
     49            'wordpress_theme' => get_option('contai_wordpress_theme', 'astra'),
    5050        ];
    5151    }
  • 1platform-content-ai/trunk/includes/services/setup/WebsiteGenerationService.php

    r3483422 r3488242  
    44
    55require_once __DIR__ . '/../../helpers/site-generation.php';
     6require_once __DIR__ . '/../../providers/WebsiteProvider.php';
    67require_once __DIR__ . '/../legal/LegalPagesGenerator.php';
    78
     
    1718
    1819        try {
    19             $theme = get_option('contai_wordpress_theme', 'blogfull');
     20            $theme = get_option('contai_wordpress_theme', 'astra');
    2021
    2122            contai_install_theme($theme);
    22             $results['steps'][] = 'Theme installed';
     23            contai_apply_theme_defaults($theme);
     24            $results['steps'][] = 'Theme installed and configured';
     25
     26            try {
     27                $website_provider = new ContaiWebsiteProvider();
     28                $website_provider->updateWebsite( array( 'theme' => sanitize_text_field( $theme ) ) );
     29                $results['steps'][] = 'Theme tracked in API';
     30            } catch ( Exception $e ) {
     31                $results['errors'][] = 'Theme tracking failed (non-critical): ' . $e->getMessage();
     32            }
    2333
    2434            contai_setup_site_config();
  • 1platform-content-ai/trunk/readme.txt

    r3487968 r3488242  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 2.5.0
     7Stable tag: 2.7.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
Note: See TracChangeset for help on using the changeset viewer.