Plugin Directory

Changeset 3436764


Ignore:
Timestamp:
01/10/2026 05:56:30 PM (3 months ago)
Author:
davidfcarr
Message:

improved image and metadata handling

Location:
quick-playground
Files:
66 added
12 edited

Legend:

Unmodified
Added
Removed
  • quick-playground/trunk/api.php

    r3432395 r3436764  
    147147    $clone = qckply_posts_related($clone);
    148148    $clone = qckply_get_menu_data($clone);
    149     unset($clone['ids']);
     149    //unset($clone['ids']);
    150150    $response = new WP_REST_Response( $clone, 200 );
    151151    $response->header( "Access-Control-Allow-Origin", "*" );
  • quick-playground/trunk/client-save-images.php

    r3432091 r3436764  
    9191}   
    9292$qckply_top_ids = qckply_top_ids();
    93 $images = $wpdb->get_results($wpdb->prepare("SELECT * FROM %i WHERE post_type='attachment' AND post_status='inherit' AND ID > %d ORDER BY ID DESC",$wpdb->posts,$qckply_top_ids['posts']));
     93$sql = $wpdb->prepare("SELECT * FROM %i posts JOIN %i meta ON posts.ID=meta.post_id WHERE meta_key='attachment_updated'",$wpdb->posts,$wpdb->postmeta);
     94printf('<p>%s</p>',$sql);
     95$images = $wpdb->get_results($sql);
    9496if(!empty($images)) {
    9597    echo '<h2>Save Images</h2>';
  • quick-playground/trunk/client-save-playground.php

    r3432206 r3436764  
    8787    $clone['settings']['cache_created'] = time();
    8888    $updated_options = get_option('qckply_updated_options',[]);
     89    if(!in_array('stylesheet',$updated_options))
     90        $updated_options[] = 'stylesheet';//always include stylesheet
    8991    foreach($updated_options as $option) {
    9092        $v = get_option($option);
     
    203205    $search_path = $qckply_mysite_url.'/wp-content/uploads';
    204206    $replace_path = $sync_origin.$site_dir;
    205     $sql = $wpdb->prepare("SELECT * FROM %i WHERE post_status='publish' AND post_type != 'attachment' AND post_modified > %s ORDER BY post_modified DESC",$wpdb->posts, $top['post_modified']);
     207    //block theme assets first
     208    $sql = $wpdb->prepare("SELECT * FROM %i WHERE post_status='publish' AND (post_type = 'wp_template' OR post_type = 'wp_template_part' OR post_type = 'wp_global_styles' OR post_type='wp_navigation' ) AND post_modified > %s ORDER BY post_modified DESC",$wpdb->posts, $top['post_modified']);
     209    $templates = $wpdb->get_results($sql);
     210    //then other posts
     211    $sql = $wpdb->prepare("SELECT * FROM %i WHERE post_status='publish' AND post_type != 'attachment' AND post_type != 'wp_template' AND post_type != 'wp_template_part' AND post_type != 'wp_global_styles' AND  post_type!='wp_navigation' AND post_modified > %s ORDER BY post_modified DESC",$wpdb->posts, $top['post_modified']);
    206212    $posts = $wpdb->get_results($sql);
     213    if(empty($posts))
     214        $posts = [];
     215    if(!empty($templates))
     216        $posts = array_merge($templates,$posts); // templates first, then any regular content
    207217    printf('<p>Found %d posts modified since last sync with %s</p>',esc_html(count($posts)),esc_html($sql));
    208218    $ids = [];
     
    217227    global $wpdb;   
    218228    printf('<h1>%s</h1><p>%s</p>',esc_html__('Save and Sync Playground','quick-playground'),esc_html__('You can save the current state of the Playground for future sessions or to sync to your live website.','quick-playground'));
     229    $sync_origin = $qckply_baseurl = get_option('qckply_sync_origin');
     230    $qckply_profile = get_option('qckply_profile','default');
     231    printf('<p><a href="%s" target="_blank">Save to Live Website</a> - administrator approval required on %s.</p>',esc_attr($sync_origin.'/wp-admin/admin.php?page=qckply_sync&profile='.$qckply_profile),esc_html($sync_origin));
    219232    if(!empty($_POST) && !wp_verify_nonce( sanitize_text_field( wp_unslash ( $_POST['playground'])), 'quickplayground' ) )
    220233    {
     
    226239        return;
    227240    $origin_stylesheet = get_option('origin_stylesheet');
    228     $sync_origin = $qckply_baseurl = get_option('qckply_sync_origin');
    229241    $no_cache = get_option('qckply_no_cache',false);
    230242    $qckply_profile = get_option('qckply_profile','default');
     
    238250    $qckply_sync_code = get_option('qckply_sync_code');
    239251    $action = admin_url('admin.php?page=qckply_save');
    240     printf('<p><a href="%s" target="_blank">Save to Live Website</a> - administrator approval required on %s.</p>',esc_attr($sync_origin.'/wp-admin/admin.php?page=qckply_sync'),esc_html($sync_origin));
    241     $play_posts = qckply_posts();//new, updated, clone, all, ids
     252    $play_posts = qckply_posts();
    242253    error_log('play_posts '.sizeof($play_posts));
    243254    qckply_clone_save_playground($play_posts);
  • quick-playground/trunk/expro-api.php

    r3432091 r3436764  
    7373      if($json && $cache = json_decode($json,true)) {
    7474        $post_ids = [];
     75        $taxonomy_tracking = [];
    7576        foreach($data['posts'] as $post) {
    7677          $post = (object) $post;
    7778          $post_ids[] = $post->ID;
     79          $track = qckply_theme_template_tracking_key($post->ID, $data);
     80          if($track)
     81            $taxonomy_tracking[] = $track;
    7882        }
    7983        $sync_response['cached_posts_included'] = 0;
     84        $include = true;
    8085        foreach($cache['posts'] as $post) {
    8186          $post = (object) $post;
     87          $track = qckply_theme_template_tracking_key($post->ID, $cache);
     88          if($track && in_array($track,$taxonomy_tracking)) {
     89            $include = false;
     90            continue; //if there is a more recent version of a document like a theme header, don't include the cached one regardless of ID
     91          }
    8292          if(!in_array($post->ID,$post_ids)) {
    8393            //if the post is not already in the data being sent, include it
     
    8696          }
    8797        }
     98        if($include)
    8899        foreach($cache['related'] as $pid => $value) {
    89100          if(empty($data['related'][$pid]))
  • quick-playground/trunk/expro-quickplayground-sync.php

    r3432091 r3436764  
    77 */
    88function qckply_sync() {
    9     if((!empty($_POST) || isset($_REQUEST['update']) || isset($_REQUEST['profile']) || isset($_REQUEST['reset'])) && !wp_verify_nonce( sanitize_text_field( wp_unslash ( $_REQUEST['playground'])), 'quickplayground' ) )
     9    if(!empty($_POST) && !wp_verify_nonce( sanitize_text_field( wp_unslash ( $_REQUEST['playground'])), 'quickplayground' ) )
    1010    {
    1111        echo '<h2>'.esc_html__('Security Error','quick-playground').'</h2>';
     
    4242    $saved = json_decode(file_get_contents($savedfile),true);
    4343    }   
    44     $savedfile = $qckply_site_uploads.'/quickplayground_meta_'.$profile.'.json';
    45     if(file_exists($savedfile)) {
    46     $temp = json_decode(file_get_contents($savedfile),true);
    47     if(is_array($temp))
    48         $saved = array_merge($saved,$temp);
    49     }
    5044    $savedfile = $qckply_site_uploads.'/quickplayground_settings_'.$profile.'.json';
    5145    if(file_exists($savedfile)) {
     
    189183    printf('<form method="post" action="%s">',esc_attr($action));
    190184    wp_nonce_field('quickplayground','playground',true,true);
     185    $taxtracker = [];
    191186    foreach($saved['posts'] as $index => $saved_post) {
     187        $out = '';
    192188        if(is_array($saved_post)) {
    193189            $iddate = $saved_post['ID'].$saved_post['post_date'];
     190            $pid = 'p'.$saved_post['ID'];
    194191            if(in_array($iddate,$shown))
    195192                continue;
     
    197194            $existing_post = empty($playground_imported[$iddate]) ? get_post($saved_post['ID']) : get_post($playground_imported[$iddate]);
    198195            if(empty($existing_post) || $existing_post->post_date != $saved_post['post_date']) {
    199                 printf('<h2>%s</h2>',esc_html($saved_post['post_title']));
    200                 printf('<p><input type="checkbox" name="import_from[]" value="%d"> New content, ID %s %s</p>',esc_attr($saved_post['ID']),esc_html($saved_post['ID']), esc_html($saved_post['post_title']));
    201                 printf('<input type="hidden" name="new_posts[]" value="%d" />',esc_html($saved_post['ID']));
     196                $out .= sprintf('<h2>%s (%s)</h2>',esc_html($saved_post['post_title']),esc_html($saved_post['post_type']));
     197                $out .= sprintf('<p><input type="checkbox" name="import_from[]" value="%d"> New content, ID %s %s</p>',esc_attr($saved_post['ID']),esc_html($saved_post['ID']), esc_html($saved_post['post_title']));
     198                $out .= sprintf('<input type="hidden" name="new_posts[]" value="%d" />',esc_html($saved_post['ID']));
    202199            }
    203200            else {
    204201                if($existing_post->post_modified != $saved_post['post_modified']) {
    205                     printf('<h2>%s</h2>',esc_html($saved_post['post_title']));
     202                    $out .= sprintf('<h2>%s (%s)</h2>',esc_html($saved_post['post_title']),esc_html($saved_post['post_type']));
    206203                    $oldernewer = $saved_post['post_modified'] > $existing_post->post_modified ? '<strong>Newer</strong>' : 'Older';
    207                     printf('<p><input type="checkbox" name="import_from[]" value="%d"> Modified content, ID %s %s<br />Playground version %s, Live site version %s (playground version is '.$oldernewer.')</p>',esc_html($saved_post['ID']),esc_html($saved_post['ID']),esc_html($saved_post['post_title']), esc_html($saved_post['post_modified']), esc_html($existing_post->post_modified));
     204                    $out .= sprintf('<p><input type="checkbox" name="import_from[]" value="%d"> Modified content, ID %s %s<br />Playground version %s, Live site version %s (playground version is '.$oldernewer.')</p>',esc_html($saved_post['ID']),esc_html($saved_post['ID']),esc_html($saved_post['post_title']), esc_html($saved_post['post_modified']), esc_html($existing_post->post_modified));
    208205                }
    209206            }
     207            if(!empty($saved['related'][$pid])) {
     208                if(!empty($saved['related'][$pid]['term_join'])) {
     209                    ksort($saved['related'][$pid]['term_join']);
     210                    $out .= '<div>Taxonomy: ';
     211                    $track = $saved_post['post_title'];
     212                    foreach($saved['related'][$pid]['term_join'] as $taxonomy => $values_array) {
     213                        foreach($values_array as $values) {
     214                            $out .= sprintf('%s: <strong>%s</strong> ',$taxonomy, $values['name']);
     215                            $track .= '/'.$taxonomy.':'.$values['name'];
     216                        }
     217                    }
     218                    if(in_array($track,$taxtracker))
     219                    {
     220                        printf('<p>Skipping duplicate %s</p>',$track);
     221                        continue; //next post
     222                    }
     223                    $out .= '</div>';
     224                }
     225                if(!empty($saved['related'][$pid]['postmeta'])) {
     226                    $out .= '<div>Metadata: ';
     227                    foreach($saved['related'][$pid]['postmeta'] as $meta) {
     228                        $out .= sprintf('%s: <strong>%s</strong> ',$meta['meta_key'], $meta['meta_value']);
     229                    }
     230                    $out .= '</div>';
     231                }
     232                //printf('<pre>%s</pre>',var_export($saved['related'][$pid],true));
     233            }
     234            $out .= sprintf('<div id="detail_control_%d"><button href="#qckply_hidden_detail_%d" class="detail_control_button" value="%s">Show Code</button></div><pre class="qckply_hidden_detail" id="qckply_hidden_detail_%d">%s</pre>',$saved_post['ID'],$saved_post['ID'],$saved_post['ID'],$saved_post['ID'],esc_html($saved_post['post_content']));
     235            echo $out;
    210236        }
    211237    }
    212238    printf('<p><input type="checkbox" name="show_details" value="1" /> %s</p>',esc_html__('Show Details for Debugging','quick-playground'));
    213     if($qckply_stylesheet != $current_stylesheet) {
     239    if(!empty($qckply_stylesheet) && $qckply_stylesheet != $current_stylesheet) {
    214240        printf('<p><input type="checkbox" name="switch_theme" value="%s" /> Switch to Playground theme to "%s" (currently "%s").</p>',esc_attr($qckply_stylesheet),esc_html($qckply_stylesheet),esc_html($current_stylesheet));
    215241    }
  • quick-playground/trunk/qckply-loading.php

    r3432395 r3436764  
    5151        $output = '';
    5252            qckply_clone( 'settings' );
    53             //qckply_clone( 'taxonomy' );
    5453            qckply_clone( 'custom' );
    55             //qckply_clone( 'prompts' );
    5654            qckply_top_ids(true);
    5755            set_transient('qckply_welcome_shown',false);
    5856            $url = qckply_link();
    5957            printf('<div id="qckply-overlay-message"><p>Done, redirect to <a href="%s">%s</a></p></div>',esc_attr($url),esc_html($url));
    60             //$output = ob_get_clean();
    61             //echo '<div id="qckply-overlay-message"><p>Loading images ...</p></div>';
     58            error_log('qckply landing url '.$url);
    6259            wp_print_inline_script_tag('window.location.href="'.$url.'"',
    6360                array(
  • quick-playground/trunk/quick-playground.php

    r3432395 r3436764  
    44 * Plugin URI:  https://quickplayground.com
    55 * Description: Preview your content in different themes or test plugins using WordPress Playground. Quickly create Theme and Plugin demo, testing, and staging websites.
    6  * Version:     1.0.9
     6 * Version:     1.1
    77 * Author:      David F. Carr
    88*  License:     GPL2
     
    108108        return;
    109109    }
    110     wp_enqueue_script( 'qckply_script', plugin_dir_url( __FILE__ ) . 'quickplayground.js', array(), '0.75',['in_footer'=>true] );
    111     wp_enqueue_style( 'qckply_style', plugin_dir_url( __FILE__ ) . 'quickplayground.css', array(), '1.2' );
     110    wp_enqueue_script( 'qckply_script', plugin_dir_url( __FILE__ ) . 'quickplayground.js', array(), '0.9.2',['in_footer'=>true] );
     111    wp_enqueue_style( 'qckply_style', plugin_dir_url( __FILE__ ) . 'quickplayground.css', array(), '1.3' );
    112112}
    113113function qckply_enqueue_script( $hook = '' ) {
    114114    if ( qckply_is_playground()) {
    115         wp_enqueue_script( 'qckply_script', plugin_dir_url( __FILE__ ) . 'quickplayground.js', array(), '0.6',['in_footer'=>true] );
    116         wp_enqueue_style( 'qckply_style', plugin_dir_url( __FILE__ ) . 'quickplayground.css', array(), '1.2' );
     115        wp_enqueue_script( 'qckply_script', plugin_dir_url( __FILE__ ) . 'quickplayground.js', array(), '0.9.2',['in_footer'=>true] );
     116        wp_enqueue_style( 'qckply_style', plugin_dir_url( __FILE__ ) . 'quickplayground.css', array(), '1.3' );
    117117    }
    118118}
  • quick-playground/trunk/quickplayground-updates.php

    r3431953 r3436764  
    55    //if we're in a playground and the initial import is done
    66    if(qckply_is_playground()) {
    7     add_action('wp_after_insert_post','qckply_post_updated');
    8     add_action('post_updated','qckply_post_updated');
     7    add_action('wp_after_insert_post','qckply_post_updated',10,2);
     8    add_action('post_updated','qckply_post_updated',10,2);
    99    add_action('updated_option','qckply_updated_option');
    1010    add_action('added_option','qckply_updated_option');
     
    3131}
    3232
    33 function qckply_post_updated($post_id) {
     33function qckply_post_updated($post_id, $post) {
     34    if('attachment' == $post->post_type)
     35        update_post_meta($post_id,'attachment_updated',time());
    3436    $updated = get_option('qckply_updated_posts',array());
    3537    if(!in_array($post_id,$updated)) {
  • quick-playground/trunk/quickplayground.css

    r3362734 r3436764  
    264264    }
    265265}
     266.qckply_hidden_detail {
     267  display: none;
     268}
  • quick-playground/trunk/quickplayground.js

    r3362734 r3436764  
    3131
    3232    const showTest = document.getElementById('showtest');
    33 
     33    if(showTest)
    3434    showTest.addEventListener('click', function(event) {
    3535      const info = document.getElementById('qckply-builder-info');
     
    5959  });
    6060});
     61
     62document.addEventListener('DOMContentLoaded', function () {
     63
     64  // attach click listeners to buttons with class "detail_control"
     65  document.querySelectorAll('.detail_control_button').forEach(function (btn) {
     66    btn.addEventListener('click', function (event) {
     67      event.preventDefault();
     68      console.log('show detail clicked');
     69
     70      // get numeric ID from the button's value and show the matching detail
     71      var idNum = parseInt(btn.value, 10);
     72      if (isNaN(idNum)) return;
     73
     74      var detail = document.getElementById('qckply_hidden_detail_' + idNum);
     75      if (!detail) return;
     76
     77      detail.style.display = 'block';
     78
     79      var detail_control = document.getElementById('detail_control_' + idNum);
     80      if (!detail) return;
     81
     82      detail_control.style.display = 'none';
     83    });
     84  });
     85});
  • quick-playground/trunk/readme.txt

    r3432395 r3436764  
    99Tested up to: 6.9
    1010
    11 Stable tag: 1.0.9
     11Stable tag: 1.1
    1212
    1313License: GPLv2 or later 
     
    9797== Changelog ==
    9898
     99= 1.1 =
     100
     101Improved handling of images and metadata
     102
    99103= 1.0.9 =
    100104
  • quick-playground/trunk/utility.php

    r3432395 r3436764  
    288288    if(!empty($clone['added_images'])) {
    289289        foreach($clone['added_images'] as $index => $img) {
     290            $search = str_replace('/','\/',$sync_origin.$img);
     291            $replace = str_replace('/','\/',$playground.$img);
     292            $json = str_replace($search,$replace,$json);
     293        }
     294    }
     295    //also check for backslashed references
     296   
     297    $playground = str_replace('/','\/',$playground);
     298    $sync_origin = str_replace('/','\/',$sync_origin);
     299    $pattern = '/'.preg_quote($sync_origin, '/').'(?!.{1,3}wp-content)/';
     300    $json = preg_replace($pattern,$playground,$json);
     301    if(!empty($clone['added_images'])) {
     302        foreach($clone['added_images'] as $index => $img) {
     303            $img = str_replace('/','\/',$img);
    290304            $search = str_replace('/','\/',$sync_origin.$img);
    291305            $replace = str_replace('/','\/',$playground.$img);
     
    663677      if(!empty($clone['related'][$pid]) && empty($_GET['nocache']))
    664678        continue; //don't overwrite cached data if present
     679    $post = get_post($post_id);
     680    $clone['related'][$pid]['post_title'] = $post->post_title;
     681    $clone['related'][$pid]['post_type'] = $post->post_type;
     682    $clone['related'][$pid]['postmeta'] = $wpdb->get_results($wpdb->prepare("select * from %i where post_id=%d",$wpdb->postmeta,$post_id));
    665683$cat = $wpdb->get_results($wpdb->prepare("SELECT p.ID, p.post_title, p.post_type, tr.*,tt.*, terms.*
    666684  FROM %i AS p
     
    668686  LEFT JOIN %i AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
    669687  LEFT JOIN %i AS terms ON terms.term_id = tt.term_id
    670  WHERE p.ID=%d",$wpdb->posts,$wpdb->term_relationships,$wpdb->term_taxonomy,$wpdb->terms,$post_id ));
     688 WHERE p.ID=%d AND tt.taxonomy IS NOT NULL",$wpdb->posts,$wpdb->term_relationships,$wpdb->term_taxonomy,$wpdb->terms,$post_id ));
    671689
    672690 $terms = [];
     
    674692        if(!empty($cat))
    675693        foreach($cat as $c) {
    676             $clone['related'][$pid]['post_title'] = $c->post_title;
    677             $clone['related'][$pid]['post_type'] = $c->post_type;
    678             $clone['related'][$pid]['postmeta'] = $wpdb->get_results($wpdb->prepare("select * from %i where post_id=%d",$wpdb->postmeta,$post_id));
    679694            $clone['related'][$pid]['term_join'][$c->taxonomy][] = $c;
    680695            if($c->object_id) {               
     
    12141229    return $attr;
    12151230}, 10, 3 );
     1231
     1232function qckply_theme_template_tracking_key($post_id, $saved) {
     1233    $pid = 'p'.$id;
     1234    if(!is_array($saved) || empty($saved['related']) || empty($saved['related'][$pid]) || empty($saved['related'][$pid]['term_join']) || empty($saved['related'][$pid]['term_join']['wp_theme']) )
     1235        return;
     1236    ksort($saved['related'][$pid]['term_join']);
     1237    $track = $saved_post['post_title'];
     1238    foreach($saved['related'][$pid]['term_join'] as $taxonomy => $values_array) {
     1239        foreach($values_array as $values) {
     1240            $track .= '/'.$taxonomy.':'.$values['name'];
     1241        }
     1242    }
     1243    return $track;
     1244}
Note: See TracChangeset for help on using the changeset viewer.