# ai-builder/2.3.11/includes/class-generations-storage.php

AI Builder – Generate pages, blocks, images &amp; translate with AI, version 2.3.11. 404 lines.

- Page: https://pluginprobe.com/plugins/ai-builder/2.3.11/code/includes/class-generations-storage.php
- Raw: https://pluginprobe.com/plugins/ai-builder/2.3.11/raw/includes/class-generations-storage.php
- Modified: 2025-12-08T10:33:22+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ai-builder/2.3.11/code/includes/class-generations-storage.php#L10-L20`.

```php
<?php
/**
 * Class to handle Multi-Page Generator storage using JSON files
 * Stores generations in wp-content/uploads/ai-builder-generations/
 */

if (!defined('ABSPATH'))
    exit;

class AIBUI_Generations_Storage
{
    private $base_dir;
    
    public function __construct()
    {
        $upload_dir = wp_upload_dir();
        $this->base_dir = $upload_dir['basedir'] . '/ai-builder-generations';
        $this->ensure_directories_exist();
    }
    
    /**
     * Ensure base directory and .htaccess exist
     */
    private function ensure_directories_exist()
    {
        if (!file_exists($this->base_dir)) {
            wp_mkdir_p($this->base_dir);
            
            // Create .htaccess to protect files
            $htaccess_content = "deny from all\n";
            file_put_contents($this->base_dir . '/.htaccess', $htaccess_content);
        }
    }
    
    /**
     * Get user-specific directory for generations
     */
    private function get_user_dir($user_id = null)
    {
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        
        $user_dir = $this->base_dir . '/user-' . intval($user_id);
        
        if (!file_exists($user_dir)) {
            wp_mkdir_p($user_dir);
        }
        
        return $user_dir;
    }
    
    /**
     * Generate filename for a generation
     */
    private function get_filename($id)
    {
        $sanitized_id = sanitize_file_name($id);
        return 'gen-' . date('Ymd-His') . '-' . $sanitized_id . '.json';
    }
    
    /**
     * Find file by generation ID
     */
    private function find_file_by_id($id, $user_id = null)
    {
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        
        $user_dir = $this->get_user_dir($user_id);
        $pattern = $user_dir . '/gen-*-' . sanitize_file_name($id) . '.json';
        $files = glob($pattern);
        
        return !empty($files) ? $files[0] : null;
    }
    
    /**
     * Save a generation to file
     */
    public function save($payload)
    {
        $user_id = get_current_user_id();
        $user_dir = $this->get_user_dir($user_id);
        
        $id = isset($payload['id']) && is_string($payload['id']) ? $payload['id'] : wp_generate_uuid4();
        $filename = $this->get_filename($id);
        $filepath = $user_dir . '/' . $filename;
        
        // Prepare data structure
        $data = array(
            'id' => $id,
            'title' => sanitize_text_field($payload['title'] ?? ''),
            'metaDesc' => sanitize_textarea_field($payload['metaDesc'] ?? ''),
            'cssContent' => wp_kses_post($payload['cssContent'] ?? ''),
            'blocksJson' => isset($payload['blocksJson']) && is_array($payload['blocksJson']) ? $payload['blocksJson'] : array(),
            'status' => 'Pending review',
            'createdAt' => current_time('mysql'),
            'applied' => false,
            'pageId' => 0,
            'userId' => $user_id,
        );
        
        // Write JSON file
        $json_content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        
        if (file_put_contents($filepath, $json_content) === false) {
            return new WP_Error('file_write_error', 'Failed to save generation file');
        }
        
        // Update index for quick listing
        $this->update_index($user_id, $id, array(
            'filename' => $filename,
            'title' => $data['title'],
            'status' => $data['status'],
            'createdAt' => $data['createdAt'],
        ));
        
        return $data;
    }
    
    /**
     * Get a generation by ID
     */
    public function get($id, $user_id = null)
    {
        $filepath = $this->find_file_by_id($id, $user_id);
        
        if (!$filepath || !file_exists($filepath)) {
            return new WP_Error('not_found', 'Generation not found');
        }
        
        $json_content = file_get_contents($filepath);
        
        if ($json_content === false) {
            return new WP_Error('file_read_error', 'Failed to read generation file');
        }
        
        $data = json_decode($json_content, true);
        
        if (!$data || !is_array($data)) {
            return new WP_Error('invalid_json', 'Invalid JSON in generation file');
        }
        
        return $data;
    }
    
    /**
     * Get all generations for a user
     */
    public function get_all($user_id = null)
    {
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        
        $user_dir = $this->get_user_dir($user_id);
        $files = glob($user_dir . '/gen-*.json');
        
        $items = array();
        
        foreach ($files as $filepath) {
            $json_content = file_get_contents($filepath);
            if ($json_content === false) continue;
            
            $data = json_decode($json_content, true);
            if (!$data || !is_array($data)) continue;
            
            // Return only essential info (not full blocks JSON)
            $items[] = array(
                'id' => $data['id'] ?? '',
                'title' => $data['title'] ?? '',
                'status' => $data['status'] ?? 'Pending review',
                'createdAt' => $data['createdAt'] ?? '',
                'applied' => $data['applied'] ?? false,
                'pageId' => $data['pageId'] ?? 0,
            );
        }
        
        // Sort by date (newest first)
        usort($items, function($a, $b) {
            return strcmp($b['createdAt'] ?? '', $a['createdAt'] ?? '');
        });
        
        return $items;
    }
    
    /**
     * Mark a generation as applied
     */
    public function mark_applied($id, $page_id = 0, $user_id = null)
    {
        $filepath = $this->find_file_by_id($id, $user_id);
        
        if (!$filepath || !file_exists($filepath)) {
            return new WP_Error('not_found', 'Generation not found');
        }
        
        $json_content = file_get_contents($filepath);
        $data = json_decode($json_content, true);
        
        if (!$data || !is_array($data)) {
            return new WP_Error('invalid_json', 'Invalid JSON in generation file');
        }
        
        $data['status'] = 'Applied';
        $data['applied'] = true;
        if ($page_id > 0) {
            $data['pageId'] = intval($page_id);
        }
        
        // Rewrite file
        $updated_json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        
        if (file_put_contents($filepath, $updated_json) === false) {
            return new WP_Error('file_write_error', 'Failed to update generation file');
        }
        
        // Update index
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        $this->update_index($user_id, $id, array(
            'filename' => basename($filepath),
            'title' => $data['title'],
            'status' => 'Applied',
            'createdAt' => $data['createdAt'],
        ));
        
        return $data;
    }
    
    /**
     * Delete a generation file
     */
    public function delete($id, $user_id = null)
    {
        $filepath = $this->find_file_by_id($id, $user_id);
        
        if (!$filepath || !file_exists($filepath)) {
            return new WP_Error('not_found', 'Generation not found');
        }
        
        if (unlink($filepath) === false) {
            return new WP_Error('file_delete_error', 'Failed to delete generation file');
        }
        
        // Update index
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        $this->remove_from_index($user_id, $id);
        
        return true;
    }
    
    /**
     * Update index for quick listing
     */
    private function update_index($user_id, $id, $info)
    {
        $index_key = 'aibui_gen_index_' . intval($user_id);
        $index = get_option($index_key, array());
        
        if (!is_array($index)) {
            $index = array();
        }
        
        $index[$id] = $info;
        update_option($index_key, $index, false);
    }
    
    /**
     * Remove from index
     */
    private function remove_from_index($user_id, $id)
    {
        $index_key = 'aibui_gen_index_' . intval($user_id);
        $index = get_option($index_key, array());
        
        if (is_array($index) && isset($index[$id])) {
            unset($index[$id]);
            update_option($index_key, $index, false);
        }
    }
    
    /**
     * Cleanup old applied generations (older than X days)
     */
    public function cleanup_old($days = 30)
    {
        if (!file_exists($this->base_dir)) {
            return 0;
        }
        
        $deleted_count = 0;
        $user_dirs = glob($this->base_dir . '/user-*', GLOB_ONLYDIR);
        
        foreach ($user_dirs as $user_dir) {
            $files = glob($user_dir . '/gen-*.json');
            
            foreach ($files as $filepath) {
                $json_content = file_get_contents($filepath);
                if ($json_content === false) continue;
                
                $data = json_decode($json_content, true);
                if (!$data || !is_array($data)) continue;
                
                // Delete if applied and older than X days
                if (($data['applied'] ?? false) && isset($data['createdAt'])) {
                    $created = strtotime($data['createdAt']);
                    if ($created === false) continue;
                    
                    $age_days = (time() - $created) / DAY_IN_SECONDS;
                    
                    if ($age_days > $days) {
                        if (unlink($filepath)) {
                            $deleted_count++;
                            
                            // Update index
                            $user_id = $data['userId'] ?? 0;
                            if ($user_id) {
                                $this->remove_from_index($user_id, $data['id'] ?? '');
                            }
                        }
                    }
                }
            }
        }
        
        return $deleted_count;
    }
    
    /**
     * Migrate old wp_options data to files (one-time migration)
     */
    public function migrate_from_options()
    {
        $old_data = get_option('aibui_multi_page_generations', array());
        
        if (empty($old_data) || !is_array($old_data)) {
            return 0;
        }
        
        $migrated_count = 0;
        
        foreach ($old_data as $id => $generation) {
            if (!is_array($generation)) continue;
            
            // Try to determine user ID from generation data or use current user
            $user_id = isset($generation['userId']) ? intval($generation['userId']) : get_current_user_id();
            
            // Temporarily set user context for migration
            $original_user = get_current_user_id();
            if ($user_id !== $original_user) {
                // Note: This is a limitation - we can't easily switch user context
                // So we'll use the current user's directory
                $user_id = $original_user;
            }
            
            $user_dir = $this->get_user_dir($user_id);
            $filename = 'gen-' . date('Ymd-His', strtotime($generation['createdAt'] ?? 'now')) . '-' . sanitize_file_name($id) . '.json';
            $filepath = $user_dir . '/' . $filename;
            
            // Check if already migrated
            if (file_exists($filepath)) {
                continue;
            }
            
            // Prepare data
            $data = array(
                'id' => $id,
                'title' => sanitize_text_field($generation['title'] ?? ''),
                'metaDesc' => sanitize_textarea_field($generation['metaDesc'] ?? ''),
                'cssContent' => wp_kses_post($generation['cssContent'] ?? ''),
                'blocksJson' => isset($generation['blocksJson']) && is_array($generation['blocksJson']) ? $generation['blocksJson'] : array(),
                'status' => $generation['status'] ?? 'Pending review',
                'createdAt' => $generation['createdAt'] ?? current_time('mysql'),
                'applied' => $generation['applied'] ?? false,
                'pageId' => isset($generation['pageId']) ? intval($generation['pageId']) : 0,
                'userId' => $user_id,
            );
            
            // Write file
            $json_content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            
            if (file_put_contents($filepath, $json_content) !== false) {
                $migrated_count++;
                
                // Update index
                $this->update_index($user_id, $id, array(
                    'filename' => $filename,
                    'title' => $data['title'],
                    'status' => $data['status'],
                    'createdAt' => $data['createdAt'],
                ));
            }
        }
        
        return $migrated_count;
    }
}


```
