| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| defined( 'ABSPATH' ) || exit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if ( ! function_exists( 'kic_scan_mu_subfolders' ) ) {
|
| function kic_scan_mu_subfolders() {
|
| $mu_plugins_dir = WPMU_PLUGIN_DIR;
|
| $subfolders = array();
|
|
|
| if ( ! is_dir( $mu_plugins_dir ) ) {
|
| return $subfolders;
|
| }
|
|
|
|
|
| $directories = glob( trailingslashit( $mu_plugins_dir ) . '*', GLOB_ONLYDIR );
|
|
|
| if ( empty( $directories ) ) {
|
| return $subfolders;
|
| }
|
|
|
| foreach ( $directories as $dir_path ) {
|
| $folder_name = basename( $dir_path );
|
|
|
|
|
| $php_files = glob( trailingslashit( $dir_path ) . '*.php' );
|
|
|
| if ( empty( $php_files ) ) {
|
| continue;
|
| }
|
|
|
| $files_data = array();
|
| foreach ( $php_files as $file_path ) {
|
| $files_data[] = array(
|
| 'path' => $file_path,
|
| 'filename' => basename( $file_path ),
|
| );
|
| }
|
|
|
| $subfolders[] = array(
|
| 'folder_name' => $folder_name,
|
| 'folder_path' => $dir_path,
|
| 'files' => $files_data,
|
| 'file_count' => count( $files_data ),
|
| );
|
| }
|
|
|
| return $subfolders;
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| add_action( 'admin_notices', function() {
|
| $screen = get_current_screen();
|
|
|
| if ( ! $screen || 'edit-wpcode_snippets_sync' !== $screen->id ) {
|
| return;
|
| }
|
|
|
|
|
| $count = wp_count_posts( 'wpcode_snippets_sync' );
|
| $total = isset( $count->publish ) ? $count->publish : 0;
|
|
|
| if ( $total < 1 ) {
|
| return;
|
| }
|
|
|
|
|
| $wpcode_count = count( get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'fields' => 'ids',
|
| 'no_found_rows' => true,
|
| 'meta_query' => array(
|
| 'relation' => 'OR',
|
| array(
|
| 'key' => 'source_type',
|
| 'value' => 'wpcode',
|
| ),
|
| array(
|
| 'key' => 'source_type',
|
| 'compare' => 'NOT EXISTS',
|
| ),
|
| ),
|
| ) ) );
|
|
|
| $mu_plugin_count = count( get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'fields' => 'ids',
|
| 'no_found_rows' => true,
|
| 'meta_query' => array(
|
| array(
|
| 'key' => 'source_type',
|
| 'value' => 'mu-plugin',
|
| ),
|
| ),
|
| ) ) );
|
|
|
|
|
| $active_count = count( get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'fields' => 'ids',
|
| 'no_found_rows' => true,
|
| 'meta_query' => array(
|
| 'relation' => 'AND',
|
| array(
|
| 'key' => 'snippet_active',
|
| 'value' => '1',
|
| ),
|
| array(
|
| 'relation' => 'OR',
|
| array(
|
| 'key' => 'source_type',
|
| 'value' => 'wpcode',
|
| ),
|
| array(
|
| 'key' => 'source_type',
|
| 'compare' => 'NOT EXISTS',
|
| ),
|
| ),
|
| ),
|
| ) ) );
|
|
|
| $inactive_count = $wpcode_count - $active_count;
|
|
|
|
|
| $mu_subfolders = kic_scan_mu_subfolders();
|
| $subfolder_count = count( $mu_subfolders );
|
| $subfolder_file_count = 0;
|
| foreach ( $mu_subfolders as $folder ) {
|
| $subfolder_file_count += $folder['file_count'];
|
| }
|
|
|
|
|
| $download_url = wp_nonce_url(
|
| admin_url( 'admin-ajax.php?action=download_all_snippets' ),
|
| 'download_all_snippets_action',
|
| '_wpnonce'
|
| );
|
|
|
| $directory_url = wp_nonce_url(
|
| admin_url( 'admin-ajax.php?action=download_snippets_directory' ),
|
| 'download_snippets_directory_action',
|
| '_wpnonce'
|
| );
|
|
|
| $ai_directory_url = wp_nonce_url(
|
| admin_url( 'admin-ajax.php?action=download_ai_directory' ),
|
| 'download_ai_directory_action',
|
| '_wpnonce'
|
| );
|
|
|
| $full_analysis_url = wp_nonce_url(
|
| admin_url( 'admin-ajax.php?action=download_full_ai_analysis' ),
|
| 'download_full_ai_analysis_action',
|
| '_wpnonce'
|
| );
|
|
|
|
|
| $has_openai_key = ! empty( get_option( 'kic_openai_api_key' ) );
|
|
|
| ?>
|
| <div class="notice notice-info" style="display: flex; align-items: center; justify-content: space-between; padding: 12px 15px; flex-wrap: wrap; gap: 10px;">
|
| <p style="margin: 0;">
|
| <strong>📦 Bulk Export:</strong>
|
| Download all synced snippets as a ZIP archive.
|
| <span style="color: #666; font-size: 12px;">
|
| (<?php echo esc_html( $wpcode_count ); ?> WPCode: <span style="color: #00a32a;"><?php echo esc_html( $active_count ); ?> active</span>, <span style="color: #d63638;"><?php echo esc_html( $inactive_count ); ?> inactive</span> | <?php echo esc_html( $mu_plugin_count ); ?> MU-plugins<?php if ( $subfolder_file_count > 0 ) : ?> | <span style="color: #2271b1;"><?php echo esc_html( $subfolder_file_count ); ?> subfolder files</span><?php endif; ?>)
|
| </span>
|
| </p>
|
| <div style="display: flex; gap: 8px; flex-wrap: wrap;">
|
| <a href="<?php echo esc_url( $directory_url ); ?>"
|
| class="button button-secondary"
|
| id="download-directory-btn"
|
| title="Download text catalog with descriptions parsed from code comments (FREE - no API)">
|
| <span class="dashicons dashicons-list-view" style="margin-top: 3px; margin-right: 3px;"></span>
|
| Directory
|
| </a>
|
| <?php if ( $has_openai_key ) : ?>
|
| <a href="<?php echo esc_url( $ai_directory_url ); ?>"
|
| class="button button-secondary"
|
| id="download-ai-directory-btn"
|
| style="background: linear-gradient(135deg, #10a37f 0%, #1a7f64 100%); border-color: #10a37f; color: #fff;"
|
| title="AI-generated 1-2 sentence summaries (~$0.05 for 50 snippets)">
|
| <span class="dashicons dashicons-superhero" style="margin-top: 3px; margin-right: 3px;"></span>
|
| AI Summary
|
| </a>
|
| <a href="<?php echo esc_url( $full_analysis_url ); ?>"
|
| class="button button-secondary"
|
| id="download-full-analysis-btn"
|
| style="background: linear-gradient(135deg, #7c3aed 0%, #5b21b6 100%); border-color: #7c3aed; color: #fff;"
|
| title="Full AI analysis explaining every part of each snippet (~$0.50 for 50 snippets) - TAKES LONGER"
|
| onclick="return confirm('Full AI Analysis sends all code to OpenAI and takes several minutes.\n\nEstimated cost: ~$0.01 per snippet\n\nContinue?');">
|
| <span class="dashicons dashicons-welcome-learn-more" style="margin-top: 3px; margin-right: 3px;"></span>
|
| Full Analysis
|
| </a>
|
| <?php else : ?>
|
| <span class="button button-disabled"
|
| style="opacity: 0.6; cursor: not-allowed;"
|
| title="Configure OpenAI API key in Settings → Code Snippets AI to enable">
|
| <span class="dashicons dashicons-superhero" style="margin-top: 3px; margin-right: 3px;"></span>
|
| AI Summary
|
| </span>
|
| <span class="button button-disabled"
|
| style="opacity: 0.6; cursor: not-allowed;"
|
| title="Configure OpenAI API key in Settings → Code Snippets AI to enable">
|
| <span class="dashicons dashicons-welcome-learn-more" style="margin-top: 3px; margin-right: 3px;"></span>
|
| Full Analysis
|
| </span>
|
| <?php endif; ?>
|
| <a href="<?php echo esc_url( $download_url ); ?>"
|
| class="button button-primary"
|
| id="download-all-snippets-btn">
|
| <span class="dashicons dashicons-download" style="margin-top: 3px; margin-right: 3px;"></span>
|
| Download All
|
| </a>
|
| </div>
|
| </div>
|
| <?php
|
| }, 10 ); // Priority 10 to show after MU-plugins control panel
|
|
|
| /**
|
| * AJAX handler for downloading all snippets as ZIP
|
| *
|
| * Security: Uses check_ajax_referer() which automatically dies on failure
|
| * and properly handles nonce verification per WordPress Coding Standards.
|
| *
|
| * v1.4.0: Adds shortcode subfolders from mu-plugins
|
| * v1.3.0: Adds -active/-inactive suffix to filenames
|
| * v1.2.0: Now includes MU-plugins by generating files from snippet_code field
|
| */
|
| add_action( 'wp_ajax_download_all_snippets', function() {
|
|
|
|
|
| if ( ! current_user_can( 'manage_options' ) ) {
|
| wp_send_json_error( array( 'message' => 'Unauthorized access.' ), 403 );
|
| }
|
|
|
|
|
| check_ajax_referer( 'download_all_snippets_action', '_wpnonce' );
|
|
|
|
|
| if ( ! class_exists( 'ZipArchive' ) ) {
|
| wp_send_json_error( array( 'message' => 'ZipArchive PHP extension is required but not available.' ), 500 );
|
| }
|
|
|
|
|
| $snippets = get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'no_found_rows' => true,
|
| ) );
|
|
|
|
|
| $mu_subfolders = kic_scan_mu_subfolders();
|
|
|
| if ( empty( $snippets ) && empty( $mu_subfolders ) ) {
|
| wp_send_json_error( array( 'message' => 'No snippets or subfolders found to download.' ), 404 );
|
| }
|
|
|
|
|
| $temp_dir = get_temp_dir();
|
| $zip_filename = 'wpcode-snippets-export-' . gmdate( 'Y-m-d-His' ) . '.zip';
|
| $zip_path = trailingslashit( $temp_dir ) . $zip_filename;
|
|
|
|
|
| $zip = new ZipArchive();
|
| $zip_result = $zip->open( $zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE );
|
|
|
| if ( true !== $zip_result ) {
|
| wp_send_json_error( array(
|
| 'message' => 'Could not create ZIP file.',
|
| 'error_code' => $zip_result
|
| ), 500 );
|
| }
|
|
|
|
|
| $upload_dir = wp_upload_dir();
|
|
|
|
|
| $manifest = array(
|
| 'exported_at' => gmdate( 'Y-m-d H:i:s' ) . ' UTC',
|
| 'exported_by' => wp_get_current_user()->user_login,
|
| 'site_url' => home_url(),
|
| 'wordpress_ver' => get_bloginfo( 'version' ),
|
| 'total_files' => 0,
|
| 'wpcode_count' => 0,
|
| 'wpcode_active' => 0,
|
| 'wpcode_inactive' => 0,
|
| 'mu_plugin_count' => 0,
|
| 'subfolder_count' => 0,
|
| 'subfolder_file_count'=> 0,
|
| 'snippets' => array(),
|
| 'subfolders' => array(),
|
| );
|
|
|
| $files_added = 0;
|
| $wpcode_added = 0;
|
| $wpcode_active = 0;
|
| $wpcode_inactive = 0;
|
| $mu_plugin_added = 0;
|
| $subfolder_files_added = 0;
|
| $errors = array();
|
|
|
|
|
|
|
|
|
| foreach ( $snippets as $snippet ) {
|
| $post_id = $snippet->ID;
|
|
|
|
|
| $kic_id = get_field( 'kic_snippet_id', $post_id );
|
| $snippet_type = get_field( 'snippet_type', $post_id );
|
| $snippet_title = get_field( 'snippet_title', $post_id );
|
| $snippet_file = get_field( 'snippet_code_file', $post_id );
|
| $snippet_code = get_field( 'snippet_code', $post_id );
|
| $original_wpcode_id = get_field( 'original_wpcode_id', $post_id );
|
| $snippet_active = get_field( 'snippet_active', $post_id );
|
| $snippet_priority = get_field( 'snippet_priority', $post_id );
|
| $snippet_location = get_field( 'snippet_location', $post_id );
|
| $source_type = get_field( 'source_type', $post_id );
|
| $file_path_meta = get_field( 'file_path', $post_id );
|
|
|
|
|
| $is_mu_plugin = ( 'mu-plugin' === $source_type );
|
|
|
|
|
| if ( $is_mu_plugin ) {
|
| $is_active = true;
|
| $status_suffix = '-active';
|
| } else {
|
| $is_active = ! empty( $snippet_active );
|
| $status_suffix = $is_active ? '-active' : '-inactive';
|
| }
|
|
|
|
|
| if ( $is_mu_plugin ) {
|
| if ( ! empty( $file_path_meta ) ) {
|
| $original_filename = basename( $file_path_meta );
|
| $original_filename = preg_replace( '/\.php$/i', $status_suffix . '.php', $original_filename );
|
| } else {
|
| $original_filename = sanitize_file_name( $snippet_title );
|
| if ( empty( $original_filename ) ) {
|
| $original_filename = 'mu-plugin-' . $post_id;
|
| }
|
| $original_filename .= $status_suffix . '.php';
|
| }
|
| $zip_entry_name = 'mu-plugins/' . $original_filename;
|
| } else {
|
|
|
| $safe_name = sanitize_file_name( $snippet_title );
|
| if ( empty( $safe_name ) ) {
|
| $safe_name = 'snippet-' . $post_id;
|
| }
|
| $safe_name .= $status_suffix;
|
|
|
|
|
| if ( ! empty( $original_wpcode_id ) ) {
|
| $safe_name .= '-ID' . intval( $original_wpcode_id );
|
| }
|
|
|
| $extension = '.txt';
|
| if ( ! empty( $snippet_type ) ) {
|
| switch ( strtolower( $snippet_type ) ) {
|
| case 'php':
|
| $extension = '.php';
|
| break;
|
| case 'css':
|
| $extension = '.css';
|
| break;
|
| case 'js':
|
| case 'javascript':
|
| $extension = '.js';
|
| break;
|
| case 'html':
|
| $extension = '.html';
|
| break;
|
| }
|
| }
|
|
|
| $type_folder = ! empty( $snippet_type ) ? strtolower( $snippet_type ) : 'misc';
|
| $zip_entry_name = 'wpcode/' . $type_folder . '/' . $safe_name . $extension;
|
| }
|
|
|
| $file_content = null;
|
| $content_source = '';
|
|
|
|
|
| if ( ! empty( $snippet_file ) ) {
|
| $file_url = is_array( $snippet_file ) ? $snippet_file['url'] : $snippet_file;
|
|
|
| if ( ! empty( $file_url ) ) {
|
| $local_file_path = str_replace(
|
| $upload_dir['baseurl'],
|
| $upload_dir['basedir'],
|
| esc_url_raw( $file_url )
|
| );
|
| $local_file_path = preg_replace( '/\?.*$/', '', $local_file_path );
|
| $local_file_path = realpath( $local_file_path );
|
|
|
| if ( $local_file_path && strpos( $local_file_path, realpath( $upload_dir['basedir'] ) ) === 0 ) {
|
| if ( file_exists( $local_file_path ) ) {
|
| $file_content = file_get_contents( $local_file_path );
|
| $content_source = 'file';
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| if ( null === $file_content && ! empty( $snippet_code ) ) {
|
| $file_content = $snippet_code;
|
| $content_source = 'code_field';
|
| }
|
|
|
| if ( empty( $file_content ) ) {
|
| $errors[] = "Skipped '{$snippet_title}' - no file or code content";
|
| continue;
|
| }
|
|
|
| if ( $zip->addFromString( $zip_entry_name, $file_content ) ) {
|
| $files_added++;
|
|
|
| if ( $is_mu_plugin ) {
|
| $mu_plugin_added++;
|
| } else {
|
| $wpcode_added++;
|
| if ( $is_active ) {
|
| $wpcode_active++;
|
| } else {
|
| $wpcode_inactive++;
|
| }
|
| }
|
|
|
| $manifest['snippets'][] = array(
|
| 'file' => $zip_entry_name,
|
| 'kic_id' => $kic_id,
|
| 'title' => $snippet_title,
|
| 'type' => $snippet_type,
|
| 'source_type' => $is_mu_plugin ? 'mu-plugin' : 'wpcode',
|
| 'original_wpcode_id' => $original_wpcode_id,
|
| 'original_file_path' => $file_path_meta,
|
| 'active' => $is_active,
|
| 'priority' => $snippet_priority,
|
| 'location' => $snippet_location,
|
| 'content_source' => $content_source,
|
| );
|
| } else {
|
| $errors[] = "Failed to add '{$snippet_title}' to ZIP";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $mu_plugins_dir = WPMU_PLUGIN_DIR;
|
|
|
| foreach ( $mu_subfolders as $folder ) {
|
| $folder_name = $folder['folder_name'];
|
| $folder_manifest = array(
|
| 'folder_name' => $folder_name,
|
| 'files' => array(),
|
| );
|
|
|
| foreach ( $folder['files'] as $file_info ) {
|
| $file_path = $file_info['path'];
|
| $filename = $file_info['filename'];
|
|
|
|
|
| $real_path = realpath( $file_path );
|
| $real_mu_dir = realpath( $mu_plugins_dir );
|
|
|
| if ( ! $real_path || strpos( $real_path, $real_mu_dir ) !== 0 ) {
|
| $errors[] = "Skipped '{$filename}' - outside mu-plugins directory";
|
| continue;
|
| }
|
|
|
| if ( ! file_exists( $file_path ) || ! is_readable( $file_path ) ) {
|
| $errors[] = "Skipped '{$filename}' - file not readable";
|
| continue;
|
| }
|
|
|
| $file_content = file_get_contents( $file_path );
|
|
|
| if ( false === $file_content ) {
|
| $errors[] = "Skipped '{$filename}' - could not read file";
|
| continue;
|
| }
|
|
|
|
|
| $zip_entry_name = 'mu-plugins-subfolders/' . $folder_name . '/' . $filename;
|
|
|
| if ( $zip->addFromString( $zip_entry_name, $file_content ) ) {
|
| $subfolder_files_added++;
|
| $files_added++;
|
|
|
| $folder_manifest['files'][] = array(
|
| 'file' => $zip_entry_name,
|
| 'original_path' => $file_path,
|
| 'filename' => $filename,
|
| );
|
| } else {
|
| $errors[] = "Failed to add '{$filename}' from {$folder_name} to ZIP";
|
| }
|
| }
|
|
|
| if ( ! empty( $folder_manifest['files'] ) ) {
|
| $manifest['subfolders'][] = $folder_manifest;
|
| }
|
| }
|
|
|
|
|
| $manifest['total_files'] = $files_added;
|
| $manifest['wpcode_count'] = $wpcode_added;
|
| $manifest['wpcode_active'] = $wpcode_active;
|
| $manifest['wpcode_inactive'] = $wpcode_inactive;
|
| $manifest['mu_plugin_count'] = $mu_plugin_added;
|
| $manifest['subfolder_count'] = count( $mu_subfolders );
|
| $manifest['subfolder_file_count'] = $subfolder_files_added;
|
|
|
| if ( ! empty( $errors ) ) {
|
| $manifest['warnings'] = $errors;
|
| }
|
|
|
|
|
| $zip->addFromString( 'manifest.json', wp_json_encode( $manifest, JSON_PRETTY_PRINT ) );
|
|
|
|
|
| $readme = "# WPCode Snippets Export\n\n";
|
| $readme .= "Exported: " . $manifest['exported_at'] . "\n";
|
| $readme .= "From: " . $manifest['site_url'] . "\n";
|
| $readme .= "Total Files: " . $files_added . "\n\n";
|
| $readme .= "## Status Summary\n\n";
|
| $readme .= "| Type | Active | Inactive | Total |\n";
|
| $readme .= "|------|--------|----------|-------|\n";
|
| $readme .= "| WPCode Snippets | " . $wpcode_active . " | " . $wpcode_inactive . " | " . $wpcode_added . " |\n";
|
| $readme .= "| MU-Plugins (root) | " . $mu_plugin_added . " | 0 | " . $mu_plugin_added . " |\n";
|
| $readme .= "| MU-Plugins (subfolders) | " . $subfolder_files_added . " | 0 | " . $subfolder_files_added . " |\n";
|
| $readme .= "| **Total** | **" . ( $wpcode_active + $mu_plugin_added + $subfolder_files_added ) . "** | **" . $wpcode_inactive . "** | **" . $files_added . "** |\n\n";
|
| $readme .= "## Filename Convention\n\n";
|
| $readme .= "**WPCode snippets** include status AND WPCode ID:\n";
|
| $readme .= "- `snippet-name-active-ID42.php` - Active snippet (WPCode ID 42)\n";
|
| $readme .= "- `snippet-name-inactive-ID99.php` - Disabled snippet (WPCode ID 99)\n\n";
|
| $readme .= "**MU-Plugins (root)** include status only:\n";
|
| $readme .= "- `plugin-name-active.php` - Always active\n\n";
|
| $readme .= "**MU-Plugins (subfolders)** keep original names (always active).\n\n";
|
| $readme .= "## Folder Structure\n\n";
|
| $readme .= "```\n";
|
| $readme .= "export.zip\n";
|
| $readme .= "├── wpcode/ # WPCode snippets by type\n";
|
| $readme .= "│ ├── php/\n";
|
| $readme .= "│ ├── css/\n";
|
| $readme .= "│ ├── js/\n";
|
| $readme .= "│ └── html/\n";
|
| $readme .= "├── mu-plugins/ # Root-level MU-Plugins\n";
|
| $readme .= "├── mu-plugins-subfolders/ # All MU-Plugin subfolders\n";
|
| foreach ( $mu_subfolders as $folder ) {
|
| $readme .= "│ └── " . $folder['folder_name'] . "/\n";
|
| }
|
| $readme .= "├── manifest.json\n";
|
| $readme .= "└── README.md\n";
|
| $readme .= "```\n\n";
|
| $readme .= "## Deployment\n\n";
|
| $readme .= "Copy `mu-plugins-subfolders/*` folders to `/wp-content/mu-plugins/` on target site.\n";
|
|
|
| $zip->addFromString( 'README.md', $readme );
|
|
|
|
|
| $zip->close();
|
|
|
| if ( ! file_exists( $zip_path ) ) {
|
| wp_die( 'ZIP file was not created.', 'Error', array( 'response' => 500 ) );
|
| }
|
|
|
|
|
| header( 'Content-Type: application/zip' );
|
| header( 'Content-Disposition: attachment; filename="' . $zip_filename . '"' );
|
| header( 'Content-Length: ' . filesize( $zip_path ) );
|
| header( 'Pragma: no-cache' );
|
| header( 'Expires: 0' );
|
|
|
| readfile( $zip_path );
|
|
|
|
|
| if ( file_exists( $zip_path ) ) {
|
| wp_delete_file( $zip_path );
|
| }
|
|
|
| exit;
|
| } );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| add_action( 'wp_ajax_download_snippets_directory', function() {
|
|
|
|
|
| if ( ! current_user_can( 'manage_options' ) ) {
|
| wp_send_json_error( array( 'message' => 'Unauthorized access.' ), 403 );
|
| }
|
|
|
|
|
| check_ajax_referer( 'download_snippets_directory_action', '_wpnonce' );
|
|
|
|
|
| $snippets = get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'no_found_rows' => true,
|
| 'orderby' => 'title',
|
| 'order' => 'ASC',
|
| ) );
|
|
|
|
|
| $mu_subfolders = kic_scan_mu_subfolders();
|
|
|
| if ( empty( $snippets ) && empty( $mu_subfolders ) ) {
|
| wp_send_json_error( array( 'message' => 'No snippets found.' ), 404 );
|
| }
|
|
|
|
|
| $directory = "================================================================================\n";
|
| $directory .= " CODE SNIPPETS DIRECTORY\n";
|
| $directory .= "================================================================================\n";
|
| $directory .= "Generated: " . gmdate( 'Y-m-d H:i:s' ) . " UTC\n";
|
| $directory .= "Site: " . home_url() . "\n";
|
| $directory .= "================================================================================\n\n";
|
|
|
|
|
| $wpcode_entries = array();
|
| $mu_plugin_entries = array();
|
| $mu_subfolder_entries = array();
|
|
|
|
|
| foreach ( $snippets as $snippet ) {
|
| $post_id = $snippet->ID;
|
|
|
|
|
| $kic_id = get_field( 'kic_snippet_id', $post_id );
|
| $snippet_type = get_field( 'snippet_type', $post_id );
|
| $snippet_title = get_field( 'snippet_title', $post_id );
|
| $snippet_code = get_field( 'snippet_code', $post_id );
|
| $original_wpcode_id = get_field( 'original_wpcode_id', $post_id );
|
| $snippet_active = get_field( 'snippet_active', $post_id );
|
| $snippet_priority = get_field( 'snippet_priority', $post_id );
|
| $snippet_location = get_field( 'snippet_location', $post_id );
|
| $source_type = get_field( 'source_type', $post_id );
|
| $file_path_meta = get_field( 'file_path', $post_id );
|
| $snippet_description = get_field( 'snippet_description', $post_id );
|
|
|
|
|
| $parsed_description = kic_parse_code_description( $snippet_code );
|
| $final_description = ! empty( $parsed_description ) ? $parsed_description : $snippet_description;
|
|
|
|
|
| $entry = array(
|
| 'title' => $snippet_title ? $snippet_title : $snippet->post_title,
|
| 'id' => $original_wpcode_id ? $original_wpcode_id : $post_id,
|
| 'kic_id' => $kic_id,
|
| 'type' => $snippet_type ? strtoupper( $snippet_type ) : 'UNKNOWN',
|
| 'status' => $snippet_active ? 'ACTIVE' : 'INACTIVE',
|
| 'priority' => $snippet_priority ? $snippet_priority : 10,
|
| 'location' => $snippet_location ? $snippet_location : 'N/A',
|
| 'description' => $final_description,
|
| 'file_path' => $file_path_meta,
|
| );
|
|
|
|
|
| if ( 'mu-plugin' === $source_type ) {
|
| $mu_plugin_entries[] = $entry;
|
| } elseif ( 'mu-plugin-subfolder' === $source_type ) {
|
| $mu_subfolder_entries[] = $entry;
|
| } else {
|
| $wpcode_entries[] = $entry;
|
| }
|
| }
|
|
|
|
|
| $mu_plugins_dir = WPMU_PLUGIN_DIR;
|
| foreach ( $mu_subfolders as $folder ) {
|
| foreach ( $folder['files'] as $file_info ) {
|
| $file_path = $file_info['path'];
|
| $filename = $file_info['filename'];
|
|
|
|
|
| $already_synced = false;
|
| foreach ( $mu_subfolder_entries as $entry ) {
|
| if ( isset( $entry['file_path'] ) && basename( $entry['file_path'] ) === $filename ) {
|
| $already_synced = true;
|
| break;
|
| }
|
| }
|
|
|
| if ( ! $already_synced ) {
|
|
|
| $real_path = realpath( $file_path );
|
| $real_mu_dir = realpath( $mu_plugins_dir );
|
|
|
| if ( $real_path && strpos( $real_path, $real_mu_dir ) === 0 && file_exists( $file_path ) ) {
|
| $code_content = file_get_contents( $file_path );
|
| $parsed_description = kic_parse_code_description( $code_content );
|
|
|
| $mu_subfolder_entries[] = array(
|
| 'title' => $filename,
|
| 'id' => 'N/A (not synced)',
|
| 'kic_id' => 'mu_subfolder_' . $folder['folder_name'] . '_' . pathinfo( $filename, PATHINFO_FILENAME ),
|
| 'type' => 'PHP',
|
| 'status' => 'ACTIVE',
|
| 'priority' => 'N/A',
|
| 'location' => 'mu-plugins/' . $folder['folder_name'] . '/',
|
| 'description' => $parsed_description,
|
| 'file_path' => $file_path,
|
| );
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "################################################################################\n";
|
| $directory .= "# SECTION 1: WPCODE SNIPPETS (" . count( $wpcode_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $wpcode_entries ) ) {
|
| $directory .= "(No WPCode snippets found)\n\n";
|
| } else {
|
| foreach ( $wpcode_entries as $index => $entry ) {
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( " WPCode ID: %s\n", $entry['id'] );
|
| $directory .= sprintf( " Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( " Status: %s\n", $entry['status'] );
|
| $directory .= sprintf( " Priority: %s\n", $entry['priority'] );
|
| $directory .= sprintf( " Location: %s\n", $entry['location'] );
|
| $directory .= "\n";
|
| $directory .= " DESCRIPTION:\n";
|
| if ( ! empty( $entry['description'] ) ) {
|
|
|
| $desc_lines = explode( "\n", wordwrap( $entry['description'], 74 ) );
|
| foreach ( $desc_lines as $line ) {
|
| $directory .= " " . $line . "\n";
|
| }
|
| } else {
|
| $directory .= " (No description found in code)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SECTION 2: MU-PLUGINS - ROOT (" . count( $mu_plugin_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $mu_plugin_entries ) ) {
|
| $directory .= "(No root MU-plugins found)\n\n";
|
| } else {
|
| foreach ( $mu_plugin_entries as $index => $entry ) {
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( " Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( " Status: %s (always active)\n", $entry['status'] );
|
| $directory .= sprintf( " File: %s\n", $entry['file_path'] ? basename( $entry['file_path'] ) : 'N/A' );
|
| $directory .= "\n";
|
| $directory .= " DESCRIPTION:\n";
|
| if ( ! empty( $entry['description'] ) ) {
|
| $desc_lines = explode( "\n", wordwrap( $entry['description'], 74 ) );
|
| foreach ( $desc_lines as $line ) {
|
| $directory .= " " . $line . "\n";
|
| }
|
| } else {
|
| $directory .= " (No description found in code)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SECTION 3: MU-PLUGINS - SUBFOLDERS (" . count( $mu_subfolder_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $mu_subfolder_entries ) ) {
|
| $directory .= "(No subfolder MU-plugins found)\n\n";
|
| } else {
|
|
|
| $by_folder = array();
|
| foreach ( $mu_subfolder_entries as $entry ) {
|
| $folder = 'unknown';
|
| if ( ! empty( $entry['location'] ) ) {
|
| preg_match( '/mu-plugins\/([^\/]+)\//', $entry['location'], $matches );
|
| if ( ! empty( $matches[1] ) ) {
|
| $folder = $matches[1];
|
| }
|
| } elseif ( ! empty( $entry['file_path'] ) ) {
|
| $parts = explode( '/', str_replace( '\\', '/', $entry['file_path'] ) );
|
| $mu_index = array_search( 'mu-plugins', $parts );
|
| if ( $mu_index !== false && isset( $parts[ $mu_index + 1 ] ) ) {
|
| $folder = $parts[ $mu_index + 1 ];
|
| }
|
| }
|
| $by_folder[ $folder ][] = $entry;
|
| }
|
|
|
| foreach ( $by_folder as $folder_name => $entries ) {
|
| $directory .= "=== FOLDER: " . $folder_name . "/ (" . count( $entries ) . " files) ===\n\n";
|
|
|
| foreach ( $entries as $index => $entry ) {
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( " Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( " Status: ACTIVE (always active)\n" );
|
| $directory .= sprintf( " Folder: %s/\n", $folder_name );
|
| $directory .= "\n";
|
| $directory .= " DESCRIPTION:\n";
|
| if ( ! empty( $entry['description'] ) ) {
|
| $desc_lines = explode( "\n", wordwrap( $entry['description'], 74 ) );
|
| foreach ( $desc_lines as $line ) {
|
| $directory .= " " . $line . "\n";
|
| }
|
| } else {
|
| $directory .= " (No description found in code)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SUMMARY\n";
|
| $directory .= "################################################################################\n\n";
|
| $directory .= sprintf( " WPCode Snippets: %d\n", count( $wpcode_entries ) );
|
| $directory .= sprintf( " MU-Plugins (root): %d\n", count( $mu_plugin_entries ) );
|
| $directory .= sprintf( " MU-Plugins (subfolders):%d\n", count( $mu_subfolder_entries ) );
|
| $directory .= sprintf( " --------------------------------\n" );
|
| $directory .= sprintf( " TOTAL: %d\n", count( $wpcode_entries ) + count( $mu_plugin_entries ) + count( $mu_subfolder_entries ) );
|
| $directory .= "\n================================================================================\n";
|
| $directory .= " END OF DIRECTORY\n";
|
| $directory .= "================================================================================\n";
|
|
|
|
|
| $filename = 'code-snippets-directory-' . gmdate( 'Y-m-d-His' ) . '.txt';
|
|
|
|
|
| header( 'Content-Type: text/plain; charset=utf-8' );
|
| header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
|
| header( 'Content-Length: ' . strlen( $directory ) );
|
| header( 'Pragma: no-cache' );
|
| header( 'Expires: 0' );
|
|
|
| echo $directory;
|
| exit;
|
| } );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| function kic_parse_code_description( $code ) {
|
| if ( empty( $code ) ) {
|
| return '';
|
| }
|
|
|
| $description = '';
|
|
|
|
|
| if ( preg_match( '/^\s*\*?\s*Description:\s*(.+?)$/mi', $code, $matches ) ) {
|
| $description = trim( $matches[1] );
|
| }
|
|
|
|
|
| if ( empty( $description ) && preg_match( '/@description\s+(.+?)(?:\n\s*\*\s*@|\n\s*\*\/)/si', $code, $matches ) ) {
|
| $description = trim( preg_replace( '/\s*\*\s*/', ' ', $matches[1] ) );
|
| }
|
|
|
|
|
| if ( empty( $description ) && preg_match( '/\/\*\*\s*\n\s*\*\s*([^@\n][^\n]*(?:\n\s*\*\s*[^@\n][^\n]*)*)/s', $code, $matches ) ) {
|
| $raw = $matches[1];
|
|
|
| $lines = preg_split( '/\n\s*\*\s*/', $raw );
|
| $cleaned = array();
|
| foreach ( $lines as $line ) {
|
| $line = trim( $line );
|
| if ( ! empty( $line ) && strpos( $line, '@' ) !== 0 ) {
|
| $cleaned[] = $line;
|
| }
|
| }
|
| if ( ! empty( $cleaned ) ) {
|
| $description = implode( ' ', $cleaned );
|
| }
|
| }
|
|
|
|
|
| if ( empty( $description ) && preg_match( '/\/\*[^*](.+?)\*\//s', $code, $matches ) ) {
|
| $raw = trim( $matches[1] );
|
|
|
| $raw = preg_replace( '/\s+/', ' ', $raw );
|
| if ( strlen( $raw ) > 20 && strlen( $raw ) < 500 ) {
|
| $description = $raw;
|
| }
|
| }
|
|
|
|
|
| if ( empty( $description ) && preg_match( '/^(?:<\?php\s*)?\s*\/\/\s*(.{20,200})$/m', $code, $matches ) ) {
|
| $description = trim( $matches[1] );
|
| }
|
|
|
|
|
| $description = trim( $description );
|
| $description = preg_replace( '/\s+/', ' ', $description );
|
|
|
|
|
| if ( strlen( $description ) > 500 ) {
|
| $description = substr( $description, 0, 497 ) . '...';
|
| }
|
|
|
| return $description;
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| function kic_openai_analyze_code( $code, $title = '', $mode = 'summary' ) {
|
| $api_key = get_option( 'kic_openai_api_key' );
|
|
|
| if ( empty( $api_key ) || empty( $code ) ) {
|
| return '';
|
| }
|
|
|
|
|
| $code_sample = $code;
|
| if ( 'full' === $mode ) {
|
|
|
| if ( strlen( $code ) > 6000 ) {
|
| $code_sample = substr( $code, 0, 4000 ) . "\n\n... [code truncated for length] ...\n\n" . substr( $code, -1500 );
|
| }
|
| } else {
|
|
|
| if ( strlen( $code ) > 3000 ) {
|
| $code_sample = substr( $code, 0, 1500 ) . "\n\n... [code truncated] ...\n\n" . substr( $code, -500 );
|
| }
|
| }
|
|
|
|
|
| if ( 'full' === $mode ) {
|
| $system_message = 'You are a senior WordPress developer assistant. Provide detailed code analysis that explains what each major section does. Use clear headings and bullet points. Be thorough but organized.';
|
|
|
| $prompt = "Analyze this WordPress/PHP code snippet in detail. Provide:\n\n";
|
| $prompt .= "1. **PURPOSE**: What is the overall goal of this code?\n";
|
| $prompt .= "2. **KEY FUNCTIONS**: List and explain each function/hook\n";
|
| $prompt .= "3. **HOW IT WORKS**: Step-by-step explanation of the flow\n";
|
| $prompt .= "4. **DEPENDENCIES**: What plugins/features does it require?\n";
|
| $prompt .= "5. **SECURITY**: Any security measures implemented\n\n";
|
|
|
| $max_tokens = 800;
|
| } else {
|
| $system_message = 'You are a WordPress developer assistant. Summarize code snippets concisely in 1-2 sentences. Focus on what the code does, not how it does it. Do not include phrases like "This code" - just state what it does directly.';
|
|
|
| $prompt = "Analyze this WordPress/PHP code snippet and provide a concise 1-2 sentence summary of what it does. Focus on the main functionality and purpose. Be specific but brief.\n\n";
|
|
|
| $max_tokens = 150;
|
| }
|
|
|
| if ( ! empty( $title ) ) {
|
| $prompt .= "Snippet Title: {$title}\n\n";
|
| }
|
| $prompt .= "Code:\n```php\n{$code_sample}\n```";
|
|
|
|
|
| $request_body = array(
|
| 'model' => 'gpt-4o-mini',
|
| 'messages' => array(
|
| array(
|
| 'role' => 'system',
|
| 'content' => $system_message,
|
| ),
|
| array(
|
| 'role' => 'user',
|
| 'content' => $prompt,
|
| ),
|
| ),
|
| 'max_tokens' => $max_tokens,
|
| 'temperature' => 0.3,
|
| );
|
|
|
| $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', array(
|
| 'timeout' => 60,
|
| 'headers' => array(
|
| 'Authorization' => 'Bearer ' . $api_key,
|
| 'Content-Type' => 'application/json',
|
| ),
|
| 'body' => wp_json_encode( $request_body ),
|
| ) );
|
|
|
| if ( is_wp_error( $response ) ) {
|
| return '';
|
| }
|
|
|
| $response_code = wp_remote_retrieve_response_code( $response );
|
| if ( 200 !== $response_code ) {
|
| return '';
|
| }
|
|
|
| $body = wp_remote_retrieve_body( $response );
|
| $data = json_decode( $body, true );
|
|
|
| if ( ! empty( $data['choices'][0]['message']['content'] ) ) {
|
| return trim( $data['choices'][0]['message']['content'] );
|
| }
|
|
|
| return '';
|
| }
|
|
|
|
|
|
|
|
|
| function kic_openai_summarize_code( $code, $title = '' ) {
|
| return kic_openai_analyze_code( $code, $title, 'summary' );
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| add_action( 'wp_ajax_download_ai_directory', function() {
|
|
|
|
|
| if ( ! current_user_can( 'manage_options' ) ) {
|
| wp_send_json_error( array( 'message' => 'Unauthorized access.' ), 403 );
|
| }
|
|
|
|
|
| check_ajax_referer( 'download_ai_directory_action', '_wpnonce' );
|
|
|
|
|
| $api_key = get_option( 'kic_openai_api_key' );
|
| if ( empty( $api_key ) ) {
|
| wp_die( 'OpenAI API key not configured. Go to Settings → Code Snippets AI to add your key.', 'Configuration Error', array( 'response' => 400 ) );
|
| }
|
|
|
|
|
| $snippets = get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'no_found_rows' => true,
|
| 'orderby' => 'title',
|
| 'order' => 'ASC',
|
| ) );
|
|
|
|
|
| $mu_subfolders = kic_scan_mu_subfolders();
|
|
|
| if ( empty( $snippets ) && empty( $mu_subfolders ) ) {
|
| wp_send_json_error( array( 'message' => 'No snippets found.' ), 404 );
|
| }
|
|
|
|
|
| $directory = "================================================================================\n";
|
| $directory .= " CODE SNIPPETS DIRECTORY (AI-ENHANCED)\n";
|
| $directory .= "================================================================================\n";
|
| $directory .= "Generated: " . gmdate( 'Y-m-d H:i:s' ) . " UTC\n";
|
| $directory .= "Site: " . home_url() . "\n";
|
| $directory .= "AI Model: GPT-4o-mini (OpenAI)\n";
|
| $directory .= "================================================================================\n\n";
|
|
|
|
|
| $wpcode_entries = array();
|
| $mu_plugin_entries = array();
|
| $mu_subfolder_entries = array();
|
| $ai_summaries_generated = 0;
|
| $ai_failures = 0;
|
|
|
|
|
| foreach ( $snippets as $snippet ) {
|
| $post_id = $snippet->ID;
|
|
|
|
|
| $kic_id = get_field( 'kic_snippet_id', $post_id );
|
| $snippet_type = get_field( 'snippet_type', $post_id );
|
| $snippet_title = get_field( 'snippet_title', $post_id );
|
| $snippet_code = get_field( 'snippet_code', $post_id );
|
| $original_wpcode_id = get_field( 'original_wpcode_id', $post_id );
|
| $snippet_active = get_field( 'snippet_active', $post_id );
|
| $snippet_priority = get_field( 'snippet_priority', $post_id );
|
| $snippet_location = get_field( 'snippet_location', $post_id );
|
| $source_type = get_field( 'source_type', $post_id );
|
| $file_path_meta = get_field( 'file_path', $post_id );
|
|
|
|
|
| $ai_summary = '';
|
| if ( ! empty( $snippet_code ) ) {
|
| $ai_summary = kic_openai_summarize_code( $snippet_code, $snippet_title );
|
| if ( ! empty( $ai_summary ) ) {
|
| $ai_summaries_generated++;
|
| } else {
|
| $ai_failures++;
|
|
|
| $ai_summary = kic_parse_code_description( $snippet_code );
|
| if ( ! empty( $ai_summary ) ) {
|
| $ai_summary = '[Parsed] ' . $ai_summary;
|
| }
|
| }
|
| }
|
|
|
|
|
| $entry = array(
|
| 'title' => $snippet_title ? $snippet_title : $snippet->post_title,
|
| 'id' => $original_wpcode_id ? $original_wpcode_id : $post_id,
|
| 'kic_id' => $kic_id,
|
| 'type' => $snippet_type ? strtoupper( $snippet_type ) : 'UNKNOWN',
|
| 'status' => $snippet_active ? 'ACTIVE' : 'INACTIVE',
|
| 'priority' => $snippet_priority ? $snippet_priority : 10,
|
| 'location' => $snippet_location ? $snippet_location : 'N/A',
|
| 'description' => $ai_summary,
|
| 'file_path' => $file_path_meta,
|
| );
|
|
|
|
|
| if ( 'mu-plugin' === $source_type ) {
|
| $mu_plugin_entries[] = $entry;
|
| } elseif ( 'mu-plugin-subfolder' === $source_type ) {
|
| $mu_subfolder_entries[] = $entry;
|
| } else {
|
| $wpcode_entries[] = $entry;
|
| }
|
|
|
|
|
| usleep( 100000 );
|
| }
|
|
|
|
|
| $mu_plugins_dir = WPMU_PLUGIN_DIR;
|
| foreach ( $mu_subfolders as $folder ) {
|
| foreach ( $folder['files'] as $file_info ) {
|
| $file_path = $file_info['path'];
|
| $filename = $file_info['filename'];
|
|
|
|
|
| $already_synced = false;
|
| foreach ( $mu_subfolder_entries as $entry ) {
|
| if ( isset( $entry['file_path'] ) && basename( $entry['file_path'] ) === $filename ) {
|
| $already_synced = true;
|
| break;
|
| }
|
| }
|
|
|
| if ( ! $already_synced ) {
|
| $real_path = realpath( $file_path );
|
| $real_mu_dir = realpath( $mu_plugins_dir );
|
|
|
| if ( $real_path && strpos( $real_path, $real_mu_dir ) === 0 && file_exists( $file_path ) ) {
|
| $code_content = file_get_contents( $file_path );
|
|
|
|
|
| $ai_summary = kic_openai_summarize_code( $code_content, $filename );
|
| if ( ! empty( $ai_summary ) ) {
|
| $ai_summaries_generated++;
|
| } else {
|
| $ai_failures++;
|
| $ai_summary = kic_parse_code_description( $code_content );
|
| if ( ! empty( $ai_summary ) ) {
|
| $ai_summary = '[Parsed] ' . $ai_summary;
|
| }
|
| }
|
|
|
| $mu_subfolder_entries[] = array(
|
| 'title' => $filename,
|
| 'id' => 'N/A',
|
| 'kic_id' => 'mu_subfolder_' . $folder['folder_name'] . '_' . pathinfo( $filename, PATHINFO_FILENAME ),
|
| 'type' => 'PHP',
|
| 'status' => 'ACTIVE',
|
| 'priority' => 'N/A',
|
| 'location' => 'mu-plugins/' . $folder['folder_name'] . '/',
|
| 'description' => $ai_summary,
|
| 'file_path' => $file_path,
|
| );
|
|
|
| usleep( 100000 );
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "################################################################################\n";
|
| $directory .= "# SECTION 1: WPCODE SNIPPETS (" . count( $wpcode_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $wpcode_entries ) ) {
|
| $directory .= "(No WPCode snippets found)\n\n";
|
| } else {
|
| foreach ( $wpcode_entries as $index => $entry ) {
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( " WPCode ID: %s\n", $entry['id'] );
|
| $directory .= sprintf( " Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( " Status: %s\n", $entry['status'] );
|
| $directory .= sprintf( " Priority: %s\n", $entry['priority'] );
|
| $directory .= sprintf( " Location: %s\n", $entry['location'] );
|
| $directory .= "\n";
|
| $directory .= " AI SUMMARY:\n";
|
| if ( ! empty( $entry['description'] ) ) {
|
| $desc_lines = explode( "\n", wordwrap( $entry['description'], 74 ) );
|
| foreach ( $desc_lines as $line ) {
|
| $directory .= " " . $line . "\n";
|
| }
|
| } else {
|
| $directory .= " (Could not generate summary)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SECTION 2: MU-PLUGINS - ROOT (" . count( $mu_plugin_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $mu_plugin_entries ) ) {
|
| $directory .= "(No root MU-plugins found)\n\n";
|
| } else {
|
| foreach ( $mu_plugin_entries as $index => $entry ) {
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( " Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( " Status: %s (always active)\n", $entry['status'] );
|
| $directory .= sprintf( " File: %s\n", $entry['file_path'] ? basename( $entry['file_path'] ) : 'N/A' );
|
| $directory .= "\n";
|
| $directory .= " AI SUMMARY:\n";
|
| if ( ! empty( $entry['description'] ) ) {
|
| $desc_lines = explode( "\n", wordwrap( $entry['description'], 74 ) );
|
| foreach ( $desc_lines as $line ) {
|
| $directory .= " " . $line . "\n";
|
| }
|
| } else {
|
| $directory .= " (Could not generate summary)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SECTION 3: MU-PLUGINS - SUBFOLDERS (" . count( $mu_subfolder_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $mu_subfolder_entries ) ) {
|
| $directory .= "(No subfolder MU-plugins found)\n\n";
|
| } else {
|
| $by_folder = array();
|
| foreach ( $mu_subfolder_entries as $entry ) {
|
| $folder = 'unknown';
|
| if ( ! empty( $entry['location'] ) ) {
|
| preg_match( '/mu-plugins\/([^\/]+)\//', $entry['location'], $matches );
|
| if ( ! empty( $matches[1] ) ) {
|
| $folder = $matches[1];
|
| }
|
| } elseif ( ! empty( $entry['file_path'] ) ) {
|
| $parts = explode( '/', str_replace( '\\', '/', $entry['file_path'] ) );
|
| $mu_index = array_search( 'mu-plugins', $parts );
|
| if ( $mu_index !== false && isset( $parts[ $mu_index + 1 ] ) ) {
|
| $folder = $parts[ $mu_index + 1 ];
|
| }
|
| }
|
| $by_folder[ $folder ][] = $entry;
|
| }
|
|
|
| foreach ( $by_folder as $folder_name => $entries ) {
|
| $directory .= "=== FOLDER: " . $folder_name . "/ (" . count( $entries ) . " files) ===\n\n";
|
|
|
| foreach ( $entries as $index => $entry ) {
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "--------------------------------------------------------------------------------\n";
|
| $directory .= sprintf( " Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( " Status: ACTIVE (always active)\n" );
|
| $directory .= sprintf( " Folder: %s/\n", $folder_name );
|
| $directory .= "\n";
|
| $directory .= " AI SUMMARY:\n";
|
| if ( ! empty( $entry['description'] ) ) {
|
| $desc_lines = explode( "\n", wordwrap( $entry['description'], 74 ) );
|
| foreach ( $desc_lines as $line ) {
|
| $directory .= " " . $line . "\n";
|
| }
|
| } else {
|
| $directory .= " (Could not generate summary)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $total_snippets = count( $wpcode_entries ) + count( $mu_plugin_entries ) + count( $mu_subfolder_entries );
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SUMMARY\n";
|
| $directory .= "################################################################################\n\n";
|
| $directory .= sprintf( " WPCode Snippets: %d\n", count( $wpcode_entries ) );
|
| $directory .= sprintf( " MU-Plugins (root): %d\n", count( $mu_plugin_entries ) );
|
| $directory .= sprintf( " MU-Plugins (subfolders): %d\n", count( $mu_subfolder_entries ) );
|
| $directory .= sprintf( " --------------------------------\n" );
|
| $directory .= sprintf( " TOTAL SNIPPETS: %d\n", $total_snippets );
|
| $directory .= "\n";
|
| $directory .= sprintf( " AI Summaries Generated: %d\n", $ai_summaries_generated );
|
| $directory .= sprintf( " Fallback (Parsed): %d\n", $ai_failures );
|
| $directory .= "\n================================================================================\n";
|
| $directory .= " END OF AI-ENHANCED DIRECTORY\n";
|
| $directory .= "================================================================================\n";
|
|
|
|
|
| $filename = 'code-snippets-ai-directory-' . gmdate( 'Y-m-d-His' ) . '.txt';
|
|
|
|
|
| header( 'Content-Type: text/plain; charset=utf-8' );
|
| header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
|
| header( 'Content-Length: ' . strlen( $directory ) );
|
| header( 'Pragma: no-cache' );
|
| header( 'Expires: 0' );
|
|
|
| echo $directory;
|
| exit;
|
| } );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| add_action( 'wp_ajax_download_full_ai_analysis', function() {
|
|
|
|
|
| if ( ! current_user_can( 'manage_options' ) ) {
|
| wp_send_json_error( array( 'message' => 'Unauthorized access.' ), 403 );
|
| }
|
|
|
|
|
| check_ajax_referer( 'download_full_ai_analysis_action', '_wpnonce' );
|
|
|
|
|
| $api_key = get_option( 'kic_openai_api_key' );
|
| if ( empty( $api_key ) ) {
|
| wp_die( 'OpenAI API key not configured. Go to Settings → Code Snippets AI to add your key.', 'Configuration Error', array( 'response' => 400 ) );
|
| }
|
|
|
|
|
| $snippets = get_posts( array(
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'publish',
|
| 'no_found_rows' => true,
|
| 'orderby' => 'title',
|
| 'order' => 'ASC',
|
| ) );
|
|
|
| $mu_subfolders = kic_scan_mu_subfolders();
|
|
|
| if ( empty( $snippets ) && empty( $mu_subfolders ) ) {
|
| wp_send_json_error( array( 'message' => 'No snippets found.' ), 404 );
|
| }
|
|
|
|
|
| $directory = "================================================================================\n";
|
| $directory .= " FULL CODE ANALYSIS REPORT (AI-POWERED)\n";
|
| $directory .= "================================================================================\n";
|
| $directory .= "Generated: " . gmdate( 'Y-m-d H:i:s' ) . " UTC\n";
|
| $directory .= "Site: " . home_url() . "\n";
|
| $directory .= "AI Model: GPT-4o-mini (OpenAI)\n";
|
| $directory .= "Analysis Type: FULL (detailed breakdown of each snippet)\n";
|
| $directory .= "================================================================================\n\n";
|
| $directory .= "NOTE: This report provides comprehensive analysis of each code snippet,\n";
|
| $directory .= "including purpose, functions, flow, dependencies, and security measures.\n";
|
| $directory .= "\n================================================================================\n\n";
|
|
|
|
|
| $wpcode_entries = array();
|
| $mu_plugin_entries = array();
|
| $mu_subfolder_entries = array();
|
| $ai_analyses_generated = 0;
|
| $ai_failures = 0;
|
|
|
|
|
| foreach ( $snippets as $snippet ) {
|
| $post_id = $snippet->ID;
|
|
|
| $kic_id = get_field( 'kic_snippet_id', $post_id );
|
| $snippet_type = get_field( 'snippet_type', $post_id );
|
| $snippet_title = get_field( 'snippet_title', $post_id );
|
| $snippet_code = get_field( 'snippet_code', $post_id );
|
| $original_wpcode_id = get_field( 'original_wpcode_id', $post_id );
|
| $snippet_active = get_field( 'snippet_active', $post_id );
|
| $snippet_priority = get_field( 'snippet_priority', $post_id );
|
| $snippet_location = get_field( 'snippet_location', $post_id );
|
| $source_type = get_field( 'source_type', $post_id );
|
| $file_path_meta = get_field( 'file_path', $post_id );
|
|
|
|
|
| $ai_analysis = '';
|
| if ( ! empty( $snippet_code ) ) {
|
| $ai_analysis = kic_openai_analyze_code( $snippet_code, $snippet_title, 'full' );
|
| if ( ! empty( $ai_analysis ) ) {
|
| $ai_analyses_generated++;
|
| } else {
|
| $ai_failures++;
|
| $ai_analysis = '[Analysis failed - API error or timeout]';
|
| }
|
| }
|
|
|
| $entry = array(
|
| 'title' => $snippet_title ? $snippet_title : $snippet->post_title,
|
| 'id' => $original_wpcode_id ? $original_wpcode_id : $post_id,
|
| 'kic_id' => $kic_id,
|
| 'type' => $snippet_type ? strtoupper( $snippet_type ) : 'UNKNOWN',
|
| 'status' => $snippet_active ? 'ACTIVE' : 'INACTIVE',
|
| 'priority' => $snippet_priority ? $snippet_priority : 10,
|
| 'location' => $snippet_location ? $snippet_location : 'N/A',
|
| 'analysis' => $ai_analysis,
|
| 'file_path' => $file_path_meta,
|
| 'code_length' => strlen( $snippet_code ),
|
| );
|
|
|
| if ( 'mu-plugin' === $source_type ) {
|
| $mu_plugin_entries[] = $entry;
|
| } elseif ( 'mu-plugin-subfolder' === $source_type ) {
|
| $mu_subfolder_entries[] = $entry;
|
| } else {
|
| $wpcode_entries[] = $entry;
|
| }
|
|
|
|
|
| usleep( 200000 );
|
| }
|
|
|
|
|
| $mu_plugins_dir = WPMU_PLUGIN_DIR;
|
| foreach ( $mu_subfolders as $folder ) {
|
| foreach ( $folder['files'] as $file_info ) {
|
| $file_path = $file_info['path'];
|
| $filename = $file_info['filename'];
|
|
|
| $already_synced = false;
|
| foreach ( $mu_subfolder_entries as $entry ) {
|
| if ( isset( $entry['file_path'] ) && basename( $entry['file_path'] ) === $filename ) {
|
| $already_synced = true;
|
| break;
|
| }
|
| }
|
|
|
| if ( ! $already_synced ) {
|
| $real_path = realpath( $file_path );
|
| $real_mu_dir = realpath( $mu_plugins_dir );
|
|
|
| if ( $real_path && strpos( $real_path, $real_mu_dir ) === 0 && file_exists( $file_path ) ) {
|
| $code_content = file_get_contents( $file_path );
|
|
|
| $ai_analysis = kic_openai_analyze_code( $code_content, $filename, 'full' );
|
| if ( ! empty( $ai_analysis ) ) {
|
| $ai_analyses_generated++;
|
| } else {
|
| $ai_failures++;
|
| $ai_analysis = '[Analysis failed - API error or timeout]';
|
| }
|
|
|
| $mu_subfolder_entries[] = array(
|
| 'title' => $filename,
|
| 'id' => 'N/A',
|
| 'kic_id' => 'mu_subfolder_' . $folder['folder_name'] . '_' . pathinfo( $filename, PATHINFO_FILENAME ),
|
| 'type' => 'PHP',
|
| 'status' => 'ACTIVE',
|
| 'priority' => 'N/A',
|
| 'location' => 'mu-plugins/' . $folder['folder_name'] . '/',
|
| 'analysis' => $ai_analysis,
|
| 'file_path' => $file_path,
|
| 'code_length' => strlen( $code_content ),
|
| );
|
|
|
| usleep( 200000 );
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "################################################################################\n";
|
| $directory .= "# SECTION 1: WPCODE SNIPPETS (" . count( $wpcode_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $wpcode_entries ) ) {
|
| $directory .= "(No WPCode snippets found)\n\n";
|
| } else {
|
| foreach ( $wpcode_entries as $index => $entry ) {
|
| $directory .= "================================================================================\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "================================================================================\n";
|
| $directory .= sprintf( "WPCode ID: %s\n", $entry['id'] );
|
| $directory .= sprintf( "Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( "Status: %s\n", $entry['status'] );
|
| $directory .= sprintf( "Priority: %s\n", $entry['priority'] );
|
| $directory .= sprintf( "Location: %s\n", $entry['location'] );
|
| $directory .= sprintf( "Code Length: %s chars\n", number_format( $entry['code_length'] ) );
|
| $directory .= "\n--- FULL AI ANALYSIS ---\n\n";
|
| if ( ! empty( $entry['analysis'] ) ) {
|
| $directory .= $entry['analysis'] . "\n";
|
| } else {
|
| $directory .= "(Could not generate analysis)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SECTION 2: MU-PLUGINS - ROOT (" . count( $mu_plugin_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $mu_plugin_entries ) ) {
|
| $directory .= "(No root MU-plugins found)\n\n";
|
| } else {
|
| foreach ( $mu_plugin_entries as $index => $entry ) {
|
| $directory .= "================================================================================\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "================================================================================\n";
|
| $directory .= sprintf( "Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( "Status: %s (always active)\n", $entry['status'] );
|
| $directory .= sprintf( "File: %s\n", $entry['file_path'] ? basename( $entry['file_path'] ) : 'N/A' );
|
| $directory .= sprintf( "Code Length: %s chars\n", number_format( $entry['code_length'] ) );
|
| $directory .= "\n--- FULL AI ANALYSIS ---\n\n";
|
| if ( ! empty( $entry['analysis'] ) ) {
|
| $directory .= $entry['analysis'] . "\n";
|
| } else {
|
| $directory .= "(Could not generate analysis)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# SECTION 3: MU-PLUGINS - SUBFOLDERS (" . count( $mu_subfolder_entries ) . " total)\n";
|
| $directory .= "################################################################################\n\n";
|
|
|
| if ( empty( $mu_subfolder_entries ) ) {
|
| $directory .= "(No subfolder MU-plugins found)\n\n";
|
| } else {
|
| $by_folder = array();
|
| foreach ( $mu_subfolder_entries as $entry ) {
|
| $folder = 'unknown';
|
| if ( ! empty( $entry['location'] ) ) {
|
| preg_match( '/mu-plugins\/([^\/]+)\//', $entry['location'], $matches );
|
| if ( ! empty( $matches[1] ) ) {
|
| $folder = $matches[1];
|
| }
|
| } elseif ( ! empty( $entry['file_path'] ) ) {
|
| $parts = explode( '/', str_replace( '\\', '/', $entry['file_path'] ) );
|
| $mu_index = array_search( 'mu-plugins', $parts );
|
| if ( $mu_index !== false && isset( $parts[ $mu_index + 1 ] ) ) {
|
| $folder = $parts[ $mu_index + 1 ];
|
| }
|
| }
|
| $by_folder[ $folder ][] = $entry;
|
| }
|
|
|
| foreach ( $by_folder as $folder_name => $entries ) {
|
| $directory .= "=== FOLDER: " . $folder_name . "/ (" . count( $entries ) . " files) ===\n\n";
|
|
|
| foreach ( $entries as $index => $entry ) {
|
| $directory .= "================================================================================\n";
|
| $directory .= sprintf( "[%d] %s\n", $index + 1, $entry['title'] );
|
| $directory .= "================================================================================\n";
|
| $directory .= sprintf( "Type: %s\n", $entry['type'] );
|
| $directory .= sprintf( "Status: ACTIVE (always active)\n" );
|
| $directory .= sprintf( "Folder: %s/\n", $folder_name );
|
| $directory .= sprintf( "Code Length: %s chars\n", isset( $entry['code_length'] ) ? number_format( $entry['code_length'] ) : 'N/A' );
|
| $directory .= "\n--- FULL AI ANALYSIS ---\n\n";
|
| if ( ! empty( $entry['analysis'] ) ) {
|
| $directory .= $entry['analysis'] . "\n";
|
| } else {
|
| $directory .= "(Could not generate analysis)\n";
|
| }
|
| $directory .= "\n";
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| $total_snippets = count( $wpcode_entries ) + count( $mu_plugin_entries ) + count( $mu_subfolder_entries );
|
|
|
| $directory .= "\n################################################################################\n";
|
| $directory .= "# ANALYSIS SUMMARY\n";
|
| $directory .= "################################################################################\n\n";
|
| $directory .= sprintf( " WPCode Snippets: %d\n", count( $wpcode_entries ) );
|
| $directory .= sprintf( " MU-Plugins (root): %d\n", count( $mu_plugin_entries ) );
|
| $directory .= sprintf( " MU-Plugins (subfolders): %d\n", count( $mu_subfolder_entries ) );
|
| $directory .= sprintf( " --------------------------------\n" );
|
| $directory .= sprintf( " TOTAL ANALYZED: %d\n", $total_snippets );
|
| $directory .= "\n";
|
| $directory .= sprintf( " Successful Analyses: %d\n", $ai_analyses_generated );
|
| $directory .= sprintf( " Failed Analyses: %d\n", $ai_failures );
|
| $directory .= "\n";
|
| $directory .= "================================================================================\n";
|
| $directory .= " END OF FULL ANALYSIS REPORT\n";
|
| $directory .= "================================================================================\n";
|
|
|
|
|
| $filename = 'code-full-ai-analysis-' . gmdate( 'Y-m-d-His' ) . '.txt';
|
|
|
|
|
| header( 'Content-Type: text/plain; charset=utf-8' );
|
| header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
|
| header( 'Content-Length: ' . strlen( $directory ) );
|
| header( 'Pragma: no-cache' );
|
| header( 'Expires: 0' );
|
|
|
| echo $directory;
|
| exit;
|
| } );
|
|
|
|
|
|
|
|
|
| add_action( 'admin_menu', function() {
|
| add_options_page(
|
| 'Code Snippets AI Settings',
|
| 'Code Snippets AI',
|
| 'manage_options',
|
| 'kic-snippets-ai-settings',
|
| 'kic_snippets_ai_settings_page'
|
| );
|
| } );
|
|
|
|
|
|
|
|
|
| function kic_snippets_ai_settings_page() {
|
|
|
| if ( isset( $_POST['kic_save_openai_key'] ) ) {
|
| if ( ! current_user_can( 'manage_options' ) ) {
|
| wp_die( 'Unauthorized' );
|
| }
|
|
|
| check_admin_referer( 'kic_openai_settings_nonce' );
|
|
|
| $api_key = isset( $_POST['kic_openai_api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['kic_openai_api_key'] ) ) : '';
|
| update_option( 'kic_openai_api_key', $api_key );
|
|
|
| echo '<div class="notice notice-success"><p>OpenAI API key saved!</p></div>';
|
| }
|
|
|
| $current_key = get_option( 'kic_openai_api_key', '' );
|
| $masked_key = ! empty( $current_key ) ? substr( $current_key, 0, 7 ) . '...' . substr( $current_key, -4 ) : '';
|
|
|
| ?>
|
| <div class="wrap">
|
| <h1>🤖 Code Snippets AI Settings</h1>
|
| <p>Configure OpenAI API integration for AI-powered code summaries.</p>
|
|
|
| <div class="card" style="max-width: 600px; padding: 20px; margin: 20px 0;">
|
| <h2>OpenAI API Key</h2>
|
| <form method="post" action="">
|
| <?php wp_nonce_field( 'kic_openai_settings_nonce' ); ?>
|
|
|
| <table class="form-table">
|
| <tr>
|
| <th scope="row"><label for="kic_openai_api_key">API Key</label></th>
|
| <td>
|
| <input type="password"
|
| name="kic_openai_api_key"
|
| id="kic_openai_api_key"
|
| class="regular-text"
|
| value="<?php echo esc_attr( $current_key ); ?>"
|
| placeholder="sk-...">
|
| <?php if ( ! empty( $masked_key ) ) : ?>
|
| <p class="description">Current: <code><?php echo esc_html( $masked_key ); ?></code></p>
|
| <?php endif; ?>
|
| <p class="description">
|
| Get your API key from <a href="https://platform.openai.com/api-keys" target="_blank">OpenAI Platform</a>
|
| </p>
|
| </td>
|
| </tr>
|
| </table>
|
|
|
| <p class="submit">
|
| <button type="submit" name="kic_save_openai_key" class="button button-primary">
|
| Save API Key
|
| </button>
|
| </p>
|
| </form>
|
| </div>
|
|
|
| <div class="card" style="max-width: 600px; padding: 20px; margin: 20px 0;">
|
| <h2>💡 How It Works</h2>
|
| <ol>
|
| <li>Enter your OpenAI API key above</li>
|
| <li>Go to <strong>Code Snippets (Sync)</strong> in the admin menu</li>
|
| <li>Click the <strong style="color: #10a37f;">AI Directory</strong> button</li>
|
| <li>Each snippet's code is sent to GPT-4o-mini for summarization</li>
|
| <li>Download includes AI-generated descriptions for all code</li>
|
| </ol>
|
|
|
| <h3>Cost Estimate</h3>
|
| <p>
|
| Using <strong>GPT-4o-mini</strong> (most cost-effective):<br>
|
| ~$0.001 - $0.005 per snippet depending on code length<br>
|
| <strong>50 snippets ≈ $0.05 - $0.25</strong>
|
| </p>
|
| </div>
|
| </div>
|
| <?php
|
| }
|
|
|
| /**
|
| * Add download link to individual row actions
|
| */
|
| add_filter( 'post_row_actions', function( $actions, $post ) {
|
|
|
| if ( 'wpcode_snippets_sync' !== $post->post_type ) {
|
| return $actions;
|
| }
|
|
|
| $snippet_file = get_field( 'snippet_code_file', $post->ID );
|
|
|
| if ( ! empty( $snippet_file ) ) {
|
| $file_url = is_array( $snippet_file ) ? $snippet_file['url'] : $snippet_file;
|
|
|
| if ( ! empty( $file_url ) ) {
|
| $download_url = add_query_arg( 'download', '1', esc_url_raw( $file_url ) );
|
| $actions['download'] = sprintf(
|
| '<a href="%s" title="%s">%s</a>',
|
| esc_url( $download_url ),
|
| esc_attr__( 'Download snippet file', 'wpcode-snippets-sync' ),
|
| esc_html__( 'Download', 'wpcode-snippets-sync' )
|
| );
|
| }
|
| }
|
|
|
| return $actions;
|
| }, 10, 2 );
|
|
|
|
|
|
|
|
|
| add_action( 'admin_footer', function() {
|
| $screen = get_current_screen();
|
|
|
| if ( ! $screen || 'edit-wpcode_snippets_sync' !== $screen->id ) {
|
| return;
|
| }
|
| ?>
|
| <script>
|
| jQuery(document).ready(function($) {
|
| $('#download-all-snippets-btn').on('click', function() {
|
| var $btn = $(this);
|
| var originalText = $btn.html();
|
|
|
| $btn.html('<span class="dashicons dashicons-update" style="margin-top: 3px; margin-right: 3px; animation: rotation 1s infinite linear;"></span> Preparing ZIP...');
|
|
|
| setTimeout(function() {
|
| $btn.html(originalText);
|
| }, 3000);
|
| });
|
| });
|
| </script>
|
| <style>
|
| @keyframes rotation {
|
| from { transform: rotate(0deg); }
|
| to { transform: rotate(360deg); }
|
| }
|
| </style>
|
| <?php
|
| } );
|
| |
| |
Comments