Home / Admin / WPCODE_DIR_AD_SYNC – WPCode Snippets Sync Engine
Duplicate Snippet

Embed Snippet on Your Site

WPCODE_DIR_AD_SYNC – WPCode Snippets Sync Engine

Description: Exposes wpcode_snippets_sync CPT fields via REST API for WhaleSync
* Location: Run Everywhere
* Priority: 15
*
* INSTALL ORDER: #4 - Install last, after sync system is set up
*
* IMPORTANT: This exposes the SHADOW CPT (wpcode_snippets_sync), NOT the actual wpcode CPT
* ✅ UPDATED: Now exposes snippet_code_file attachment field with download URL

ismail daugherty PRO
<10
Code Preview
php
<?php
/**
 * WPCode Snippet: WPCode Snippets Sync Engine
 * Description: Synchronizes WPCode snippets FROM wpcode CPT TO wpcode_snippets_sync CPT
 * Location: Run Everywhere
 * Priority: 20
 * 
 * INSTALL ORDER: #3 - Install after ACF fields are registered
 * 
 * IMPORTANT: This is a ONE-WAY sync from wpcode → wpcode_snippets_sync
 * This does NOT modify the actual WPCode snippets
 * 
 * ✅ FIXED: Now reads code from post_content (where WPCode actually stores it!)
 * ✅ UPDATED: Now creates downloadable text file attachments for each snippet
 */
defined( 'ABSPATH' ) || exit;
/**
 * Sync a single WPCode snippet to the sync CPT
 */
function kic_sync_wpcode_snippet( $wpcode_post_id ) {
    // Verify this is a wpcode post type
    if ( 'wpcode' !== get_post_type( $wpcode_post_id ) ) {
        return false;
    }
    
    // Prevent infinite loops - use a static variable instead of a constant
    static $currently_syncing = array();
    
    if ( isset( $currently_syncing[ $wpcode_post_id ] ) ) {
        return false; // Already syncing this specific snippet
    }
    
    $currently_syncing[ $wpcode_post_id ] = true;
    
    // Get the WPCode post
    $wpcode_post = get_post( $wpcode_post_id );
    if ( ! $wpcode_post ) {
        return false;
    }
    
    // Check if sync post already exists for this WPCode snippet
    $existing_sync_post = get_posts( array(
        'post_type'   => 'wpcode_snippets_sync',
        'meta_key'    => 'original_wpcode_id',
        'meta_value'  => $wpcode_post_id,
        'numberposts' => 1,
        'fields'      => 'ids',
    ) );
    
    $sync_post_id = ! empty( $existing_sync_post ) ? $existing_sync_post[0] : 0;
    
    // Prepare sync post data
    $sync_post_data = array(
        'post_title'   => $wpcode_post->post_title,
        'post_type'    => 'wpcode_snippets_sync',
        'post_status'  => 'publish', // Always publish in sync CPT
        'post_author'  => $wpcode_post->post_author,
    );
    
    // Update or insert sync post
    if ( $sync_post_id ) {
        $sync_post_data['ID'] = $sync_post_id;
        wp_update_post( $sync_post_data );
    } else {
        $sync_post_id = wp_insert_post( $sync_post_data );
    }
    
    if ( ! $sync_post_id || is_wp_error( $sync_post_id ) ) {
        return false;
    }
    
    // ==========================================
    // ✅ FIXED: Read code from post_content!
    // ==========================================
    // WPCode stores the actual code in post_content field, NOT in postmeta!
    $wpcode_code = $wpcode_post->post_content;
    
    // Get WPCode metadata using ACTUAL meta keys discovered
    $wpcode_note = get_post_meta( $wpcode_post_id, '_wpcode_note', true );
    $wpcode_priority = get_post_meta( $wpcode_post_id, '_wpcode_priority', true );
    $wpcode_device_type = get_post_meta( $wpcode_post_id, '_wpcode_device_type', true );
    $wpcode_auto_insert = get_post_meta( $wpcode_post_id, '_wpcode_auto_insert', true );
    $wpcode_schedule = get_post_meta( $wpcode_post_id, '_wpcode_schedule', true );
    $wpcode_version = get_post_meta( $wpcode_post_id, '_wpcode_snippet_version', true );
    
    // Detect snippet type
    $snippet_type = kic_detect_wpcode_snippet_type( $wpcode_code, $wpcode_note );
    
    // Update ACF fields with WPCode data
    update_field( 'original_wpcode_id', $wpcode_post_id, $sync_post_id );
    update_field( 'kic_snippet_id', 'wpcode_' . $wpcode_post_id, $sync_post_id );
    update_field( 'snippet_active', ( 'publish' === $wpcode_post->post_status ), $sync_post_id );
    update_field( 'snippet_title', $wpcode_post->post_title, $sync_post_id );
    update_field( 'snippet_created_date', $wpcode_post->post_date, $sync_post_id );
    update_field( 'snippet_modified_date', $wpcode_post->post_modified, $sync_post_id );
    update_field( 'snippet_author', get_the_author_meta( 'display_name', $wpcode_post->post_author ), $sync_post_id );
    
    // Snippet code (the actual code content from post_content!)
    if ( $wpcode_code ) {
        update_field( 'snippet_code', $wpcode_code, $sync_post_id );
        
        // ==========================================
        // ✅ NEW: Create downloadable code file
        // ==========================================
        $attachment_id = kic_create_code_file_attachment( $wpcode_code, $wpcode_post->post_title, $snippet_type, $sync_post_id );
        if ( $attachment_id ) {
            update_field( 'snippet_code_file', $attachment_id, $sync_post_id );
        }
    }
    
    // Description (stored in _wpcode_note)
    if ( $wpcode_note ) {
        update_field( 'snippet_description', $wpcode_note, $sync_post_id );
    }
    
    // Priority
    if ( $wpcode_priority !== '' && $wpcode_priority !== false ) {
        update_field( 'snippet_priority', intval( $wpcode_priority ), $sync_post_id );
    } else {
        update_field( 'snippet_priority', 10, $sync_post_id ); // default
    }
    
    // Device type (any, mobile, desktop)
    if ( $wpcode_device_type ) {
        update_field( 'snippet_device_type', $wpcode_device_type, $sync_post_id );
    } else {
        update_field( 'snippet_device_type', 'all', $sync_post_id ); // default
    }
    
    // Auto insert enabled
    update_field( 'snippet_auto_insert', (bool) $wpcode_auto_insert, $sync_post_id );
    
    // Schedule (start and end dates)
    if ( is_array( $wpcode_schedule ) ) {
        if ( ! empty( $wpcode_schedule['start'] ) ) {
            update_field( 'snippet_schedule_start', $wpcode_schedule['start'], $sync_post_id );
        }
        if ( ! empty( $wpcode_schedule['end'] ) ) {
            update_field( 'snippet_schedule_end', $wpcode_schedule['end'], $sync_post_id );
        }
    }
    
    // Snippet version
    if ( $wpcode_version ) {
        update_field( 'snippet_version', $wpcode_version, $sync_post_id );
    }
    
    // Snippet type
    update_field( 'snippet_type', $snippet_type, $sync_post_id );
    
    // Location - WPCode uses auto_insert settings
    $wpcode_auto_insert_number = get_post_meta( $wpcode_post_id, '_wpcode_auto_insert_number', true );
    if ( $wpcode_auto_insert_number ) {
        update_field( 'snippet_location', 'auto_insert_' . $wpcode_auto_insert_number, $sync_post_id );
    }
    
    // Tags - combine version and other metadata as tags
    $tags = array();
    if ( $wpcode_version ) {
        $tags[] = 'v' . $wpcode_version;
    }
    if ( $wpcode_device_type && $wpcode_device_type !== 'any' ) {
        $tags[] = $wpcode_device_type;
    }
    if ( ! empty( $tags ) ) {
        update_field( 'snippet_tags', implode( ', ', $tags ), $sync_post_id );
    }
    
    // Update last sync time
    update_field( 'last_sync_time', current_time( 'mysql' ), $sync_post_id );
    
    // Clean up - mark this snippet as no longer syncing
    unset( $currently_syncing[ $wpcode_post_id ] );
    
    return $sync_post_id;
}
/**
 * ==========================================
 * ✅ NEW: Create downloadable code file attachment
 * ==========================================
 * Creates a text file attachment with the snippet code
 * Returns attachment ID on success, false on failure
 */
function kic_create_code_file_attachment( $code, $title, $type, $parent_post_id ) {
    if ( empty( $code ) ) {
        return false;
    }
    
    // Determine file extension based on snippet type
    $extensions = array(
        'php'  => 'txt', // Use .txt for safety (PHP files can be security risk)
        'html' => 'txt',
        'css'  => 'txt',
        'js'   => 'txt',
        'text' => 'txt',
    );
    
    $extension = isset( $extensions[ $type ] ) ? $extensions[ $type ] : 'txt';
    
    // Sanitize filename
    $filename = sanitize_file_name( $title ) . '.' . $extension;
    
    // Check if attachment already exists for this sync post
    $existing_attachment = get_field( 'snippet_code_file', $parent_post_id );
    if ( $existing_attachment && is_array( $existing_attachment ) && ! empty( $existing_attachment['ID'] ) ) {
        $attachment_id = $existing_attachment['ID'];
        
        // Update existing file content
        $upload_dir = wp_upload_dir();
        $file_path = get_attached_file( $attachment_id );
        
        if ( $file_path && file_exists( $file_path ) ) {
            // Update the file content
            file_put_contents( $file_path, $code );
            return $attachment_id;
        }
    }
    
    // Create new attachment
    $upload_dir = wp_upload_dir();
    $file_path = $upload_dir['path'] . '/' . $filename;
    
    // Write code to file
    $written = file_put_contents( $file_path, $code );
    if ( false === $written ) {
        return false;
    }
    
    // Prepare attachment data
    $attachment_data = array(
        'post_mime_type' => 'text/plain',
        'post_title'     => $title,
        'post_content'   => '',
        'post_status'    => 'inherit',
        'post_parent'    => $parent_post_id,
    );
    
    // Insert attachment
    $attachment_id = wp_insert_attachment( $attachment_data, $file_path, $parent_post_id );
    
    if ( is_wp_error( $attachment_id ) ) {
        return false;
    }
    
    // Generate attachment metadata
    require_once( ABSPATH . 'wp-admin/includes/image.php' );
    $attach_data = wp_generate_attachment_metadata( $attachment_id, $file_path );
    wp_update_attachment_metadata( $attachment_id, $attach_data );
    
    return $attachment_id;
}
/**
 * Helper function to detect snippet type from code content
 */
function kic_detect_wpcode_snippet_type( $code, $note ) {
    if ( empty( $code ) ) {
        return 'text';
    }
    
    // Check for PHP
    if ( strpos( $code, '<?php' ) !== false || strpos( $code, 'function' ) !== false ) {
        return 'php';
    }
    
    // Check for HTML
    if ( strpos( $code, '<html' ) !== false || strpos( $code, '<div' ) !== false || strpos( $code, '<p>' ) !== false ) {
        return 'html';
    }
    
    // Check for CSS
    if ( preg_match( '/[a-z\-]+\s*:\s*[^;]+;/i', $code ) || strpos( $code, '{' ) !== false ) {
        return 'css';
    }
    
    // Check for JavaScript
    if ( strpos( $code, 'function(' ) !== false || 
         strpos( $code, 'var ' ) !== false || 
         strpos( $code, 'const ' ) !== false || 
         strpos( $code, 'let ' ) !== false ||
         strpos( $code, 'console.' ) !== false ) {
        return 'js';
    }
    
    // Default to text
    return 'text';
}
/**
 * Sync all WPCode snippets
 */
function kic_sync_all_wpcode_snippets() {
    // Get all wpcode posts
    $wpcode_posts = get_posts( array(
        'post_type'      => 'wpcode',
        'post_status'    => 'any',
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'orderby'        => 'ID',
        'order'          => 'ASC',
    ) );
    
    if ( empty( $wpcode_posts ) ) {
        return array(
            'success' => false,
            'message' => 'No WPCode snippets found to sync',
            'synced'  => 0,
        );
    }
    
    $synced_count = 0;
    $errors = array();
    
    foreach ( $wpcode_posts as $wpcode_id ) {
        $result = kic_sync_wpcode_snippet( $wpcode_id );
        if ( $result ) {
            $synced_count++;
        } else {
            $errors[] = $wpcode_id;
        }
    }
    
    return array(
        'success' => true,
        'message' => sprintf( 'Successfully synced %d of %d WPCode snippets', $synced_count, count( $wpcode_posts ) ),
        'synced'  => $synced_count,
        'total'   => count( $wpcode_posts ),
        'errors'  => $errors,
    );
}
/**
 * Hook: Auto-sync when WPCode snippet is saved/updated
 */
add_action( 'save_post_wpcode', function( $post_id, $post, $update ) {
    // Skip autosaves and revisions
    if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
        return;
    }
    
    // Sync this snippet to the shadow CPT
    kic_sync_wpcode_snippet( $post_id );
    
}, 20, 3 );
/**
 * Hook: Sync when WPCode snippet metadata is updated
 */
add_action( 'updated_post_meta', function( $meta_id, $post_id, $meta_key, $meta_value ) {
    // Only process wpcode post type
    if ( 'wpcode' !== get_post_type( $post_id ) ) {
        return;
    }
    
    // Only process wpcode-related meta keys
    if ( strpos( $meta_key, '_wpcode' ) !== 0 ) {
        return;
    }
    
    // Sync this snippet
    kic_sync_wpcode_snippet( $post_id );
    
}, 10, 4 );
/**
 * Hook: Delete sync post AND attachment when WPCode snippet is deleted
 */
add_action( 'before_delete_post', function( $post_id ) {
    if ( 'wpcode' !== get_post_type( $post_id ) ) {
        return;
    }
    
    // Find and delete the corresponding sync post
    $sync_posts = get_posts( array(
        'post_type'   => 'wpcode_snippets_sync',
        'meta_key'    => 'original_wpcode_id',
        'meta_value'  => $post_id,
        'numberposts' => 1,
        'fields'      => 'ids',
    ) );
    
    if ( ! empty( $sync_posts ) ) {
        $sync_post_id = $sync_posts[0];
        
        // Delete the code file attachment first
        $code_file = get_field( 'snippet_code_file', $sync_post_id );
        if ( $code_file && is_array( $code_file ) && ! empty( $code_file['ID'] ) ) {
            wp_delete_attachment( $code_file['ID'], true );
        }
        
        // Delete the sync post
        wp_delete_post( $sync_post_id, true );
    }
} );
/**
 * Admin: Add manual sync button
 */
add_action( 'admin_menu', function() {
    add_submenu_page(
        'edit.php?post_type=wpcode_snippets_sync',
        'Sync WPCode Snippets',
        'Sync Now',
        'manage_options',
        'kic-wpcode-sync',
        'kic_wpcode_sync_admin_page'
    );
} );
/**
 * Admin page for manual sync
 */
function kic_wpcode_sync_admin_page() {
    // Handle manual sync
    if ( isset( $_POST['kic_sync_wpcode'] ) && check_admin_referer( 'kic_sync_wpcode_action' ) ) {
        $result = kic_sync_all_wpcode_snippets();
        
        if ( $result['success'] ) {
            echo '<div class="notice notice-success"><p>' . esc_html( $result['message'] ) . '</p></div>';
        } else {
            echo '<div class="notice notice-error"><p>' . esc_html( $result['message'] ) . '</p></div>';
        }
    }
    
    // Get counts
    $wpcode_count = wp_count_posts( 'wpcode' );
    $sync_count = wp_count_posts( 'wpcode_snippets_sync' );
    
    $total_wpcode = $wpcode_count->publish + $wpcode_count->draft + $wpcode_count->private;
    $total_sync = $sync_count->publish;
    
    ?>
    <div class="wrap">
        <h1>WPCode Snippets Sync</h1>
        <p>Synchronize WPCode snippets to the sync CPT for REST API access via WhaleSync.</p>
        
        <div class="card">
            <h2>📊 Current Status</h2>
            <table class="widefat">
                <tr>
                    <td><strong>WPCode Snippets (Source):</strong></td>
                    <td><?php echo esc_html( $total_wpcode ); ?></td>
                </tr>
                <tr>
                    <td><strong>Synced Snippets (Mirror):</strong></td>
                    <td><?php echo esc_html( $total_sync ); ?></td>
                </tr>
                <tr>
                    <td><strong>Active WPCode Snippets:</strong></td>
                    <td><?php echo esc_html( $wpcode_count->publish ); ?></td>
                </tr>
                <tr>
                    <td><strong>Inactive/Draft:</strong></td>
                    <td><?php echo esc_html( $wpcode_count->draft ); ?></td>
                </tr>
            </table>
            
            <?php
            // Get last sync time
            $last_sync = get_posts( array(
                'post_type'      => 'wpcode_snippets_sync',
                'posts_per_page' => 1,
                'orderby'        => 'meta_value',
                'meta_key'       => 'last_sync_time',
                'order'          => 'DESC',
            ) );
            
            if ( ! empty( $last_sync ) ) {
                $last_sync_time = get_field( 'last_sync_time', $last_sync[0]->ID );
                echo '<p><strong>Last Sync:</strong> ' . esc_html( $last_sync_time ) . '</p>';
            }
            ?>
        </div>
        
        <div class="card">
            <h2>🔄 Manual Sync</h2>
            <p>Click the button below to manually sync all WPCode snippets to the sync CPT.</p>
            <form method="post" action="">
                <?php wp_nonce_field( 'kic_sync_wpcode_action' ); ?>
                <p>
                    <button type="submit" name="kic_sync_wpcode" class="button button-primary button-hero">
                        Sync All WPCode Snippets Now
                    </button>
                </p>
            </form>
            <p><em>This creates/updates mirror posts in wpcode_snippets_sync CPT. Original WPCode snippets are never modified.</em></p>
            <p><strong>✅ NEW:</strong> Each snippet now includes a downloadable code file attachment!</p>
        </div>
        
        <div class="card">
            <h2>🌐 REST API Endpoint</h2>
            <p>Your synced WPCode snippets are available at:</p>
            <code><?php echo esc_url( rest_url( 'wp/v2/wpcode-snippets-sync' ) ); ?></code>
            
            <p style="margin-top: 15px;">To test with 100 snippets:</p>
            <code>GET <?php echo esc_url( rest_url( 'wp/v2/wpcode-snippets-sync?per_page=100' ) ); ?></code>
        </div>
        
        <div class="card">
            <h2>⚙️ How It Works</h2>
            <ol>
                <li><strong>Source:</strong> Actual WPCode snippets in the <code>wpcode</code> custom post type</li>
                <li><strong>Mirror:</strong> Read-only copies in <code>wpcode_snippets_sync</code> custom post type</li>
                <li><strong>Sync:</strong> One-way sync from sourcemirror (automatic + manual)</li>
                <li><strong>Files:</strong> Each snippet gets a downloadable .txt file attachment</li>
                <li><strong>WhaleSync:</strong> Connects to mirror CPT REST API (safe, read-only)</li>
            </ol>
            <p><strong>Performance:</strong> WhaleSync never touches your actual WPCode snippets!</p>
        </div>
        
        <div class="card">
            <h2>✅ Automatic Sync</h2>
            <p>Snippets are automatically synced when:</p>
            <ul style="list-style: disc; margin-left: 20px;">
                <li>A WPCode snippet is created or updated</li>
                <li>Snippet metadata is modified in WPCode</li>
                <li>You manually trigger a sync using the button above</li>
            </ul>
            <p><strong>Note:</strong> When you delete a WPCode snippet, the mirror post AND its code file attachment are also deleted automatically.</p>
        </div>
    </div>
    
    <style>
        .card { 
            max-width: 900px; 
            padding: 20px; 
            margin: 20px 0;
            background: #fff;
            border: 1px solid #ccd0d4;
            box-shadow: 0 1px 1px rgba(0,0,0,0.04);
        }
        .card h2 { margin-top: 0; }
        .card table { margin: 15px 0; }
        .card table td { padding: 8px; }
        code {
            background: #f0f0f1;
            padding: 5px 10px;
            border-radius: 3px;
            display: inline-block;
            margin: 5px 0;
        }
    </style>
    <?php
}
/**
 * WP-CLI command for syncing
 */
if ( defined( 'WP_CLI' ) && WP_CLI ) {
    WP_CLI::add_command( 'kic sync-wpcode', function( $args, $assoc_args ) {
        WP_CLI::log( 'Starting WPCode snippets sync...' );
        
        $result = kic_sync_all_wpcode_snippets();
        
        if ( $result['success'] ) {
            WP_CLI::success( $result['message'] );
            if ( ! empty( $result['errors'] ) ) {
                WP_CLI::warning( 'Some snippets failed to sync: ' . implode( ', ', $result['errors'] ) );
            }
        } else {
            WP_CLI::error( $result['message'] );
        }
    } );
}

Comments

Add a Comment