| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| defined( 'ABSPATH' ) || exit;
|
|
|
|
|
|
|
|
|
| function kic_sync_wpcode_snippet( $wpcode_post_id ) {
|
|
|
| if ( 'wpcode' !== get_post_type( $wpcode_post_id ) ) {
|
| return false;
|
| }
|
|
|
|
|
| static $currently_syncing = array();
|
|
|
| if ( isset( $currently_syncing[ $wpcode_post_id ] ) ) {
|
| return false;
|
| }
|
|
|
| $currently_syncing[ $wpcode_post_id ] = true;
|
|
|
|
|
| $wpcode_post = get_post( $wpcode_post_id );
|
| if ( ! $wpcode_post ) {
|
| return false;
|
| }
|
|
|
|
|
| $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;
|
|
|
|
|
| $sync_post_data = array(
|
| 'post_title' => $wpcode_post->post_title,
|
| 'post_type' => 'wpcode_snippets_sync',
|
| 'post_status' => 'publish',
|
| 'post_author' => $wpcode_post->post_author,
|
| );
|
|
|
|
|
| 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;
|
| }
|
|
|
|
|
|
|
|
|
|
|
| $wpcode_code = $wpcode_post->post_content;
|
|
|
|
|
| $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 );
|
|
|
|
|
| $snippet_type = kic_detect_wpcode_snippet_type( $wpcode_code, $wpcode_note );
|
|
|
|
|
| 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 );
|
|
|
|
|
| if ( $wpcode_code ) {
|
| update_field( 'snippet_code', $wpcode_code, $sync_post_id );
|
|
|
|
|
|
|
|
|
| $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 );
|
| }
|
| }
|
|
|
|
|
| if ( $wpcode_note ) {
|
| update_field( 'snippet_description', $wpcode_note, $sync_post_id );
|
| }
|
|
|
|
|
| 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 );
|
| }
|
|
|
|
|
| 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 );
|
| }
|
|
|
|
|
| update_field( 'snippet_auto_insert', (bool) $wpcode_auto_insert, $sync_post_id );
|
|
|
|
|
| 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 );
|
| }
|
| }
|
|
|
|
|
| if ( $wpcode_version ) {
|
| update_field( 'snippet_version', $wpcode_version, $sync_post_id );
|
| }
|
|
|
|
|
| update_field( 'snippet_type', $snippet_type, $sync_post_id );
|
|
|
|
|
| $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 = 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_field( 'last_sync_time', current_time( 'mysql' ), $sync_post_id );
|
|
|
|
|
| unset( $currently_syncing[ $wpcode_post_id ] );
|
|
|
| return $sync_post_id;
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| function kic_create_code_file_attachment( $code, $title, $type, $parent_post_id ) {
|
| if ( empty( $code ) ) {
|
| return false;
|
| }
|
|
|
|
|
| $extensions = array(
|
| 'php' => 'txt',
|
| 'html' => 'txt',
|
| 'css' => 'txt',
|
| 'js' => 'txt',
|
| 'text' => 'txt',
|
| );
|
|
|
| $extension = isset( $extensions[ $type ] ) ? $extensions[ $type ] : 'txt';
|
|
|
|
|
| $filename = sanitize_file_name( $title ) . '.' . $extension;
|
|
|
|
|
| $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'];
|
|
|
|
|
| $upload_dir = wp_upload_dir();
|
| $file_path = get_attached_file( $attachment_id );
|
|
|
| if ( $file_path && file_exists( $file_path ) ) {
|
|
|
| file_put_contents( $file_path, $code );
|
| return $attachment_id;
|
| }
|
| }
|
|
|
|
|
| $upload_dir = wp_upload_dir();
|
| $file_path = $upload_dir['path'] . '/' . $filename;
|
|
|
|
|
| $written = file_put_contents( $file_path, $code );
|
| if ( false === $written ) {
|
| return false;
|
| }
|
|
|
|
|
| $attachment_data = array(
|
| 'post_mime_type' => 'text/plain',
|
| 'post_title' => $title,
|
| 'post_content' => '',
|
| 'post_status' => 'inherit',
|
| 'post_parent' => $parent_post_id,
|
| );
|
|
|
|
|
| $attachment_id = wp_insert_attachment( $attachment_data, $file_path, $parent_post_id );
|
|
|
| if ( is_wp_error( $attachment_id ) ) {
|
| return false;
|
| }
|
|
|
|
|
| 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;
|
| }
|
|
|
|
|
|
|
|
|
| function kic_detect_wpcode_snippet_type( $code, $note ) {
|
| if ( empty( $code ) ) {
|
| return 'text';
|
| }
|
|
|
|
|
| if ( strpos( $code, '<?php' ) !== false || strpos( $code, 'function' ) !== false ) {
|
| return 'php';
|
| }
|
|
|
|
|
| if ( strpos( $code, '<html' ) !== false || strpos( $code, '<div' ) !== false || strpos( $code, '<p>' ) !== false ) {
|
| return 'html';
|
| }
|
|
|
|
|
| if ( preg_match( '/[a-z\-]+\s*:\s*[^;]+;/i', $code ) || strpos( $code, '{' ) !== false ) {
|
| return 'css';
|
| }
|
|
|
|
|
| if ( strpos( $code, 'function(' ) !== false ||
|
| strpos( $code, 'var ' ) !== false ||
|
| strpos( $code, 'const ' ) !== false ||
|
| strpos( $code, 'let ' ) !== false ||
|
| strpos( $code, 'console.' ) !== false ) {
|
| return 'js';
|
| }
|
|
|
|
|
| return 'text';
|
| }
|
|
|
|
|
|
|
|
|
| function kic_sync_all_wpcode_snippets() {
|
|
|
| $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,
|
| );
|
| }
|
|
|
|
|
|
|
|
|
| add_action( 'save_post_wpcode', function( $post_id, $post, $update ) {
|
|
|
| if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
| return;
|
| }
|
|
|
|
|
| kic_sync_wpcode_snippet( $post_id );
|
|
|
| }, 20, 3 );
|
|
|
|
|
|
|
|
|
| add_action( 'updated_post_meta', function( $meta_id, $post_id, $meta_key, $meta_value ) {
|
|
|
| if ( 'wpcode' !== get_post_type( $post_id ) ) {
|
| return;
|
| }
|
|
|
|
|
| if ( strpos( $meta_key, '_wpcode' ) !== 0 ) {
|
| return;
|
| }
|
|
|
|
|
| kic_sync_wpcode_snippet( $post_id );
|
|
|
| }, 10, 4 );
|
|
|
|
|
|
|
|
|
| add_action( 'before_delete_post', function( $post_id ) {
|
| if ( 'wpcode' !== get_post_type( $post_id ) ) {
|
| return;
|
| }
|
|
|
|
|
| $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];
|
|
|
|
|
| $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 );
|
| }
|
|
|
|
|
| wp_delete_post( $sync_post_id, true );
|
| }
|
| } );
|
|
|
|
|
|
|
|
|
| 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'
|
| );
|
| } );
|
|
|
|
|
|
|
|
|
| function kic_wpcode_sync_admin_page() {
|
|
|
| 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>';
|
| }
|
| }
|
|
|
|
|
| $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 source → mirror (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:
|
| border: 1px solid
|
| 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:
|
| padding: 5px 10px;
|
| border-radius: 3px;
|
| display: inline-block;
|
| margin: 5px 0;
|
| }
|
| </style>
|
| <?php
|
| }
|
|
|
|
|
|
|
|
|
| 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