Changeset 1745585
- Timestamp:
- 10/12/2017 05:39:50 PM (8 years ago)
- Location:
- wpsitesynccontent
- Files:
-
- 48 added
- 19 edited
-
tags/1.3.1 (added)
-
tags/1.3.1/.htaccess (added)
-
tags/1.3.1/assets (added)
-
tags/1.3.1/assets/css (added)
-
tags/1.3.1/assets/css/sync-admin.css (added)
-
tags/1.3.1/assets/imgs (added)
-
tags/1.3.1/assets/imgs/ajax-loader.gif (added)
-
tags/1.3.1/assets/imgs/wpsitesync-logo-blue.png (added)
-
tags/1.3.1/assets/imgs/wpsitesync-logo.svg (added)
-
tags/1.3.1/assets/js (added)
-
tags/1.3.1/assets/js/settings.js (added)
-
tags/1.3.1/assets/js/sync.js (added)
-
tags/1.3.1/classes (added)
-
tags/1.3.1/classes/admin.php (added)
-
tags/1.3.1/classes/ajax.php (added)
-
tags/1.3.1/classes/apicontroller.php (added)
-
tags/1.3.1/classes/apiheaders.php (added)
-
tags/1.3.1/classes/apimodel.php (added)
-
tags/1.3.1/classes/apirequest.php (added)
-
tags/1.3.1/classes/apiresponse.php (added)
-
tags/1.3.1/classes/attachmodel.php (added)
-
tags/1.3.1/classes/auth.php (added)
-
tags/1.3.1/classes/debug.php (added)
-
tags/1.3.1/classes/extensionmodel.php (added)
-
tags/1.3.1/classes/extensionsettings.php (added)
-
tags/1.3.1/classes/input.php (added)
-
tags/1.3.1/classes/licensesettings.php (added)
-
tags/1.3.1/classes/licensing.php (added)
-
tags/1.3.1/classes/logmodel.php (added)
-
tags/1.3.1/classes/mediamodel.php (added)
-
tags/1.3.1/classes/model.php (added)
-
tags/1.3.1/classes/options.php (added)
-
tags/1.3.1/classes/settings.php (added)
-
tags/1.3.1/classes/sourcesmodel.php (added)
-
tags/1.3.1/classes/view.php (added)
-
tags/1.3.1/index.php (added)
-
tags/1.3.1/install (added)
-
tags/1.3.1/install/activate.php (added)
-
tags/1.3.1/install/deactivate.php (added)
-
tags/1.3.1/install/pluginupdater.php (added)
-
tags/1.3.1/languages (added)
-
tags/1.3.1/readme.txt (added)
-
tags/1.3.1/views (added)
-
tags/1.3.1/views/content_details.php (added)
-
tags/1.3.1/wpsitesynccontent.php (added)
-
trunk/assets/css/sync-admin.css (modified) (1 diff)
-
trunk/assets/js/sync.js (modified) (15 diffs)
-
trunk/classes/admin.php (modified) (7 diffs)
-
trunk/classes/ajax.php (modified) (1 diff)
-
trunk/classes/apicontroller.php (modified) (25 diffs)
-
trunk/classes/apiheaders.php (modified) (1 diff)
-
trunk/classes/apimodel.php (modified) (2 diffs)
-
trunk/classes/apirequest.php (modified) (23 diffs)
-
trunk/classes/apiresponse.php (modified) (2 diffs)
-
trunk/classes/auth.php (modified) (2 diffs)
-
trunk/classes/debug.php (modified) (3 diffs)
-
trunk/classes/licensing.php (modified) (2 diffs)
-
trunk/classes/model.php (modified) (5 diffs)
-
trunk/classes/options.php (modified) (1 diff)
-
trunk/classes/postmodel.php (added)
-
trunk/classes/serialize.php (added)
-
trunk/classes/settings.php (modified) (9 diffs)
-
trunk/classes/sourcesmodel.php (modified) (1 diff)
-
trunk/install/activate.php (modified) (1 diff)
-
trunk/languages/placeholder.txt (added)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/wpsitesynccontent.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
wpsitesynccontent/trunk/assets/css/sync-admin.css
r1492115 r1745585 128 128 } 129 129 130 #spectrom_sync #sync-message-container #sync-message span.error {130 #spectrom_sync #sync-message-container span.sync-error { 131 131 color: red; 132 132 } -
wpsitesynccontent/trunk/assets/js/sync.js
r1560226 r1745585 22 22 this.original_value = ''; 23 23 this.nonce = jQuery('#_sync_nonce').val(); 24 this.push_xhr = null; 25 this.push_callback = null; // callback to perform push; returns true to continue processing; false to stop processing 26 this.pull_callback = null; // callback to perform pull; returns true to continue processing; false to stop processing 24 27 } 25 28 … … 65 68 * @param {boolean|null} anim If set to true, display the animation image; otherwise animation will not be shown. 66 69 * @param {boolean|null) dismiss If set to true, will include a dismiss button for the message 67 */ 68 WPSiteSyncContent.prototype.set_message = function(msg, anim, dismiss) 70 * @param {string|null} CSS class to add to the message container 71 */ 72 WPSiteSyncContent.prototype.set_message = function(msg, anim, dismiss, css_class) 69 73 { 70 74 if (!this.inited) 71 75 return; 72 76 73 jQuery('#sync-message').html(msg); 77 jQuery('#sync-message').attr('class', '').html(msg); 78 if ('string' === typeof(css_class)) 79 jQuery('#sync-message').addClass(css_class); 80 74 81 if ('boolean' === typeof(anim) && anim) 75 82 jQuery('#sync-content-anim').show(); … … 110 117 111 118 /** 112 * Disables Sync Button every time the content changes. 119 * Disables Sync Button every time the content changes. 113 120 */ 114 121 WPSiteSyncContent.prototype.on_content_change = function() … … 117 124 this.disable = true; 118 125 jQuery('#sync-content').attr('disabled', true); 119 this.set_message(jQuery('#sync-msg-update-changes').html() );126 this.set_message(jQuery('#sync-msg-update-changes').html(), false, false, 'sync-error'); 120 127 // jQuery('#disabled-notice-sync').show(); 121 128 } else { … … 132 139 WPSiteSyncContent.prototype.force_refresh = function() 133 140 { 134 jQuery(window).trigger('resize');135 jQuery('#sync-message').parent().hide().show(0);141 // jQuery(window).trigger('resize'); 142 // jQuery('#sync-message').parent().hide().show(0); 136 143 }; 137 144 … … 140 147 * @param {string} op The name of the API to call 141 148 * @param {int} post_id The post ID for the API call or null if not applicable 149 * @param {string} msg The message to be set 150 * @param {string} msg_success The success message to be set 151 * @param {object} values Optional values to add to data 142 152 * @returns {undefined} 143 153 */ 144 WPSiteSyncContent.prototype.api = function(op, post_id, msg, msg_success )145 { 146 console.log('wpsitesync.api() performing "' + op + '" api request... ' + msg);154 WPSiteSyncContent.prototype.api = function(op, post_id, msg, msg_success, values) 155 { 156 //console.log('wpsitesync.api() performing "' + op + '" api request... ' + msg); 147 157 // Do nothing when in a disabled state 148 158 if (this.disable || !this.inited) 149 159 return; 160 161 // add callback checks based on 'op' parameter values ... see .push() example 162 switch (op) { 163 case 'push': 164 // check for a callback function - used to alter the behavior of the Push operation 165 if (null !== this.push_callback) { 166 var res = this.push_callback(post_id); 167 if (!res) // if the callback returns a false 168 return; // do not continue processing 169 } 170 break; 171 case 'pull': 172 // check for a callback function - used to alter the behavior of the Pull operation 173 if (null !== this.pull_callback) { 174 var res = this.pull_callback(post_id); 175 if (!res) // if the callback returns a false 176 return; // do not continue processing 177 } 178 break; 179 } 150 180 151 181 // set the message while API is running … … 157 187 operation: op, 158 188 post_id: post_id, 159 _sync_nonce: 160 this.nonce 189 _sync_nonce: this.nonce 161 190 }; 162 191 163 var push_xhr = { 192 if ('undefined' !== typeof(values)) { 193 _.extend(data, values); 194 } 195 196 this.push_xhr = { 164 197 type: 'post', 165 198 async: true, // false, … … 190 223 if ('undefined' !== typeof(response.error_message)) 191 224 wpsitesynccontent.set_message('<span class="error">' + response.error_message + '</span>', false, true); 225 else 226 wpsitesynccontent.set_message('<span class="error">' + jQuery('#sync-runtime-err-msg').html() + '</span>', false, true) 192 227 // jQuery('#sync-content-anim').hide(); 193 228 } … … 195 230 196 231 // Allow other plugins to alter the ajax request 197 jQuery(document).trigger('sync_api_call', [op, push_xhr]);232 jQuery(document).trigger('sync_api_call', [op, this.push_xhr]); 198 233 //console.log('push() calling jQuery.ajax'); 199 jQuery.ajax( push_xhr);234 jQuery.ajax(this.push_xhr); 200 235 //console.log('push() returned from ajax call'); 201 236 }; … … 212 247 return; 213 248 214 // clear the message to start things off 215 // jQuery('#sync-message').html(''); 216 // jQuery('#sync-message').html(jQuery('#sync-working-msg').html()); 217 // jQuery('#sync-content-anim').show(); 218 // jQuery('#sync-message').parent().hide().show(0); 249 // check for a callback function - used to alter the behavior of the Push operation 250 if (null !== this.push_callback) { 251 var res = this.push_callback(post_id); 252 if (!res) // if the callback returns a false 253 return; // do not continue processing 254 } 255 219 256 // set message to "working..." 220 257 this.set_message(jQuery('#sync-msg-working').text(), true); … … 223 260 var data = { action: 'spectrom_sync', operation: 'push', post_id: post_id, _sync_nonce: jQuery('#_sync_nonce').val() }; 224 261 262 //console.log('push() calling AJAX'); 225 263 var push_xhr = { 226 264 type: 'post', … … 233 271 wpsitesynccontent.clear_message(); 234 272 if (response.success) { 273 //console.log('push() response.success'); 235 274 // jQuery('#sync-message').text(jQuery('#sync-success-msg').text()); 236 275 wpsitesynccontent.set_message(jQuery('#sync-success-msg').text(), false, true); … … 241 280 } 242 281 } else { 282 //console.log('push() !response.success'); 243 283 if ('undefined' !== typeof(response.data.message)) 244 284 // jQuery('#sync-message').text(response.data.message); 245 wpsitesynccontent.set_message(response.data.message, false, true );285 wpsitesynccontent.set_message(response.data.message, false, true, 'sync-error'); 246 286 } 247 287 }, … … 252 292 if ('undefined' !== typeof(response.error_message)) 253 293 wpsitesynccontent.set_message('<span class="error">' + response.error_message + '</span>', false, true); 294 else 295 wpsitesynccontent.set_message('<span class="error">' + jQuery('#sync-runtime-err-msg').html() + '</span>', false, true) 254 296 // jQuery('#sync-content-anim').hide(); 255 297 } … … 264 306 265 307 /** 308 * Set a callback function to be used to alter behavior of .push() method 309 * @param {function} fn The function to store and use as a callback in .push() 310 */ 311 WPSiteSyncContent.prototype.set_push_callback = function(fn) 312 { 313 this.push_callback = fn; 314 }; 315 316 /** 317 * Set a callback function to be used to alter behavior of .pull() method 318 * @param {function} fn The function to store and use as a callback in .pull() 319 */ 320 WPSiteSyncContent.prototype.set_pull_callback = function(fn) 321 { 322 this.pull_callback = fn; 323 }; 324 325 /** 266 326 * Display message about WPSiteSync Pull feature 267 327 */ -
wpsitesynccontent/trunk/classes/admin.php
r1510336 r1745585 20 20 add_filter('plugin_action_links_wpsitesynccontent/wpsitesynccontent.php', array(&$this, 'plugin_action_links')); 21 21 22 add_action('before_delete_post', array($this, 'before_delete_post')); 23 22 24 // TODO: only init if running settings page 23 SyncSettings::get_instance(); 25 SyncSettings::get_instance(); 24 26 } 25 27 … … 135 137 136 138 // display the content details 137 $content_details = $this-> _get_content_details();139 $content_details = $this->get_content_details(); 138 140 // TODO: set details content 139 141 echo '<div id="sync-details" style="display:none">'; … … 186 188 if (!class_exists('WPSiteSync_Pull', FALSE)) 187 189 echo '<div id="sync-pull-msg"><div style="color: #0085ba;">', __('Please activate the Pull extension.', 'wpsitesynccontent'), '</div></div>'; 190 echo '<div id="sync-runtime-err-msg">', __('A PHP runtime error occured while processing your request. Examine Target log files for more information.', 'wpsitesynccontent'), '</div>'; 188 191 echo '</div>'; 189 192 … … 192 195 echo '<div style="display:none">'; 193 196 echo '<span id="sync-msg-working">', __('Pushing Content to Target...', 'wpsitesynccontent'), '</span>'; 194 echo '<span id="sync-msg-update-changes">< span class="error"><b>', __('Please UPDATE your changes in order to Sync.', 'wpsitesynccontent'), '</b></span></span>';197 echo '<span id="sync-msg-update-changes"><b>', __('Please UPDATE your changes in order to Sync.', 'wpsitesynccontent'), '</b></span>'; 195 198 do_action('spectrom_sync_ui_messages'); 196 199 echo '</div>'; … … 212 215 * @return string HTML contents to display within the Details section within the UI 213 216 */ 214 p rivate function _get_content_details()217 public function get_content_details() 215 218 { 216 219 global $post; … … 274 277 $response_data = $response_body->data; 275 278 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' - target data: ' . var_export($response_data, TRUE)); 276 // take the data returned from the API and 279 // take the data returned from the API and 277 280 $content_data = array( 278 281 'target' => SyncOptions::get('target'), … … 303 306 return $content; 304 307 } 308 309 /** 310 * Callback for delete post action. Removes all sync records associated with Content. 311 * @param int $post_id The post ID being deleted 312 */ 313 public function before_delete_post($post_id) 314 { 315 $model = new SyncModel(); 316 $model->remove_all_sync_data($post_id); 317 } 305 318 } 306 319 -
wpsitesynccontent/trunk/classes/ajax.php
r1560226 r1745585 40 40 SyncDebug::log(__METHOD__."('{$operation}')"); 41 41 $response = new SyncApiResponse(TRUE); 42 43 // set headers 44 // header('Content-Type: text/html; charset=ISO-utf-8'); 45 header('Content-Type: application/json; charset=utf-8'); 46 header('Content-Encoding: ajax'); 47 header('Cache-Control: private, max-age=0'); 48 header('Expires: -1'); 42 49 43 50 // perform authentication checking: must be logged in, an 'Author' role or higher -
wpsitesynccontent/trunk/classes/apicontroller.php
r1573030 r1745585 12 12 private static $_instance = NULL; 13 13 14 protected $media_id = 0; 14 protected $media_id = 0; // id of the media being handled 15 15 protected $local_media_name = ''; 16 public $source_site_key = NULL; // the Source site's key16 public $source_site_key = NULL; // the Source site's key 17 17 18 18 private $_headers = NULL; // stores request headers … … 53 53 $response->nosend = TRUE; 54 54 55 $this->source_site_key = isset($args['site_key']) ? $args['site_key'] : $this-> _get_header(self::HEADER_SITE_KEY);56 57 $this->source = untrailingslashit(isset($args['source']) ? $args['source'] : $this-> _get_header(self::HEADER_SOURCE));55 $this->source_site_key = isset($args['site_key']) ? $args['site_key'] : $this->get_header(self::HEADER_SITE_KEY); 56 57 $this->source = untrailingslashit(isset($args['source']) ? $args['source'] : $this->get_header(self::HEADER_SOURCE)); 58 58 SyncDebug::log(__METHOD__.'() action=' . $action . ' source=' . $this->source . ' key=' . $this->source_site_key); 59 59 … … 177 177 * @return string|NULL The requested header value or NULL if the named header is not found 178 178 */ 179 p rivate function _get_header($name)179 public function get_header($name) 180 180 { 181 181 if (NULL === $this->_headers) { … … 263 263 do_action('spectrom_sync_pre_push_content', $post_data, $this->source_post_id, $target_post_id, $response); 264 264 265 // allow add-ons to modify the content type 266 $content_type = apply_filters('spectrom_sync_push_content_type', 'post', $target_post_id, $this); 267 265 268 $post = NULL; 266 269 if (0 !== $target_post_id) { … … 275 278 // use source's site_key for the lookup 276 279 // TODO: use a better variable name than $sync_data 277 $sync_data = $model->get_sync_data($this->source_post_id, $this->source_site_key );280 $sync_data = $model->get_sync_data($this->source_post_id, $this->source_site_key, $content_type); 278 281 SyncDebug::log(' sync_data: ' . var_export($sync_data, TRUE)); 279 282 if (NULL !== $sync_data) { … … 285 288 $this->post_id = $target_post_id; 286 289 } 287 290 ###$post = NULL; ### 288 291 // Get post by title, if new 289 292 if (NULL === $post) { 290 SyncDebug::log(' - still no post found - look up bytitle');291 $post = $this->get_post_by_title($post_data['post_title']);292 if (NULL !== $post)293 $target_post_id = $post->ID;293 $mode = $this->get_header(self::HEADER_MATCH_MODE, 'title'); 294 //SyncDebug::log(__METHOD__ . '():' . __LINE__ . ' - still no post found - use lookup_post() mode=' . $mode); 295 $post_model = new SyncPostModel(); 296 $target_post_id = $post_model->lookup_post($post_data, $mode); 294 297 } 295 298 … … 310 313 311 314 // check parent page- don't allow if parent doesn't exist 312 if (0 !== intval($post_data['post_parent'])) {315 if (0 !== abs($post_data['post_parent'])) { 313 316 $model = new SyncModel(); // does this already exist? 314 317 SyncDebug::log(__METHOD__.'() looking up parent post #' . $post_data['post_parent']); 315 // $parent_post = $model->get_sync_target_data( intval($post_data['post_parent']), $this->post('site_key'));316 $parent_post = $model->get_sync_data( intval($post_data['post_parent']), $this->source_site_key);318 // $parent_post = $model->get_sync_target_data(abs($post_data['post_parent']), $this->post('site_key')); 319 $parent_post = $model->get_sync_data(abs($post_data['post_parent']), $this->source_site_key, $content_type); 317 320 if (NULL === $parent_post) { 318 321 // cannot find parent post on Target system- cannot allow push operation to continue … … 322 325 // fixup the Source's parent post id with the Target's id value 323 326 SyncDebug::log(__METHOD__.'() setting parent post to #' . $parent_post->target_content_id); 324 $post_data['post_parent'] = intval($parent_post->target_content_id);327 $post_data['post_parent'] = abs($parent_post->target_content_id); 325 328 } 326 329 327 330 // change references to source URL to target URL 328 331 $post_data['post_content'] = str_replace($this->source, site_url(), $post_data['post_content']); 332 $post_data['post_excerpt'] = str_replace($this->source, site_url(), $post_data['post_excerpt']); 329 333 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' converting URLs ' . $this->source . ' -> ' . site_url()); 330 334 // $post_data['post_content'] = str_replace($this->post('origin'), $url['host'], $post_data['post_content']); 331 // TODO: check if we need to update anything else like `guid`, `post_ excerpt`, `post_content_filtered`335 // TODO: check if we need to update anything else like `guid`, `post_content_filtered` 332 336 333 337 // set the user for post creation/update #70 334 wp_set_current_user($this->_user->ID); 338 if (isset($this->_user->ID)) 339 wp_set_current_user($this->_user->ID); 335 340 336 341 // add/update post … … 370 375 'source_content_id' => $this->source_post_id, 371 376 'target_content_id' => $this->post_id, 377 'content_type' => $content_type, 372 378 ); 373 379 $model->save_sync_data($save_sync); … … 405 411 // TOOD: probably better to remove all postmeta, then add_post_meta() for each item found 406 412 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' handling meta data'); 413 $ser = NULL; 407 414 foreach ($post_meta as $meta_key => $meta_value) { 408 415 foreach ($meta_value as $value) // loop through meta_value array … … 413 420 //$_v = maybe_unserialize($_v); 414 421 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' new value=' . var_export($_v, TRUE)); 422 // change Source URL references to Target URL references in meta data 423 $temp_val = maybe_unserialize(stripslashes ($value)); 424 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' meta key: "' . $meta_key . '" meta data: ' . $value); 425 //SyncDebug::log(' -- ' . var_export($temp_val, TRUE)); 426 if (is_array($temp_val)) { 427 if (NULL === $ser) 428 $ser = new SyncSerialize(); 429 $fix_data = str_replace($this->source, site_url(), $value); 430 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' fix data: ' . $fix_data); 431 $fix_data = $ser->fix_serialized_data($fix_data); 432 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' fixing serialized data: ' . $fix_data); 433 $value = $fix_data; 434 } else { 435 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' not fixing serialized data'); 436 $value = str_replace($this->source, site_url(), $value); 437 } 415 438 update_post_meta($target_post_id, $meta_key, maybe_unserialize(stripslashes($value))); 416 439 } … … 509 532 if (isset($taxonomies['flat']) && !empty($taxonomies['flat'])) { 510 533 $tags = $taxonomies['flat']; 511 SyncDebug::log(__METHOD__.'() found ' . count($tags) . ' taxonomy tags');534 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' found ' . count($tags) . ' taxonomy tags'); 512 535 foreach ($tags as $term_info) { 513 536 $tax_type = $term_info['taxonomy']; 514 $term = get_term ('slug', $term_info['slug'], $tax_type, OBJECT);515 SyncDebug::log(__METHOD__.'() found taxonomy ' . $tax_type);537 $term = get_term_by('slug', $term_info['slug'], $tax_type, OBJECT); 538 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' found taxonomy ' . $tax_type . ': ' . var_export($term, TRUE)); 516 539 if (FALSE === $term) { 517 540 // term not found - create it … … 521 544 'taxonomy' => $term_info['taxonomy'], 522 545 ); 546 SyncDebug::log(__METHOD__.'():' . __LINE__ . " wp_insert_term('{$term_info['name']}', {$tax_type}, " . var_export($args, TRUE) . ')'); 523 547 $ret = wp_insert_term($term_info['name'], $tax_type, $args); 524 SyncDebug::log(__METHOD__.'() insert term [flat] result: ' . var_export($ret, TRUE));548 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' insert term [flat] result: ' . var_export($ret, TRUE)); 525 549 } else { 526 SyncDebug::log(__METHOD__.'() term already exists');550 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' term already exists'); 527 551 } 528 552 $ret = wp_add_object_terms($post_id, $term_info['slug'], $tax_type); 529 SyncDebug::log(__METHOD__.'() add [flat] object terms result: ' . var_export($ret, TRUE));553 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' add [flat] object terms result: ' . var_export($ret, TRUE)); 530 554 } 531 555 } … … 545 569 $terms = $taxonomies['hierarchical']; 546 570 foreach ($terms as $term_info) { 547 $tax_type = $term_info['taxonomy']; 548 SyncDebug::log(__METHOD__.'() build lineage for taxonomy: ' . $tax_type); 549 550 // first, build a lineage list of the taxonomy terms 551 $lineage = array(); 552 $lineage[] = $term_info; // always add the current term to the lineage 553 $parent = intval($term_info['parent']); 554 SyncDebug::log(__METHOD__.'() looking for parent term #' . $parent); 555 if (isset($taxonomies['lineage'][$tax_type])) { 556 while (0 !== $parent) { 557 foreach ($taxonomies['lineage'][$tax_type] as $tax_term) { 558 SyncDebug::log(__METHOD__.'() checking lineage for #' . $tax_term['term_id'] . ' - ' . $tax_term['slug']); 559 if ($tax_term['term_id'] == $parent) { 560 SyncDebug::log(__METHOD__.'() - found term ' . $tax_term['slug'] . ' as a child of ' . $parent); 561 $lineage[] = $tax_term; 562 $parent = intval($tax_term['parent']); 563 break; 564 } 565 } 566 } 567 } else { 568 SyncDebug::log(__METHOD__.'() no taxonomy lineage found for: ' . $tax_type); 569 } 570 $lineage = array_reverse($lineage); // swap array order to start loop with top-most term first 571 SyncDebug::log(__METHOD__.'() taxonomy lineage: ' . var_export($lineage, TRUE)); 572 573 // next, make sure each term in the hierarchy exists - we'll end on the taxonomy id that needs to be assigned 574 SyncDebug::log(__METHOD__.'() setting taxonomy terms for taxonomy "' . $tax_type . '"'); 575 $generation = $parent = 0; 576 foreach ($lineage as $tax_term) { 577 SyncDebug::log(__METHOD__.'() checking term #' . $tax_term['term_id'] . ' ' . $tax_term['slug'] . ' parent=' . $tax_term['parent']); 578 $term = NULL; 579 if (0 === $parent) { 580 SyncDebug::log(__METHOD__.'() getting top level taxonomy ' . $tax_term['slug'] . ' in taxonomy ' . $tax_type); 581 $term = get_term_by('slug', $tax_term['slug'], $tax_type, OBJECT); 582 if (is_wp_error($term) || FALSE === $term) { 583 SyncDebug::log(__METHOD__.'() error=' . var_export($term, TRUE)); 584 $term = NULL; // term not found, set to NULL so code below creates it 585 } 586 SyncDebug::log(__METHOD__.'() no parent but found term: ' . var_export($term, TRUE)); 587 } else { 588 $child_terms = get_term_children($parent, $tax_type); 589 SyncDebug::log(__METHOD__.'() found ' . count($child_terms) . ' term children for #' . $parent); 590 if (!is_wp_error($child_terms)) { 591 // loop through the children until we find one that matches 592 foreach ($child_terms as $term_id) { 593 $term_child = get_term_by('id', $term_id, $tax_type); 594 SyncDebug::log(__METHOD__.'() term child: ' . $term_child->slug); 595 if ($term_child->slug === $tax_term['slug']) { 596 // found the child term 597 $term = $term_child; 598 break; 599 } 600 } 601 } 602 } 603 604 // see if the term needs to be created 605 if (NULL === $term) { 606 // term not found - create it 607 $args = array( 608 'description'=> $tax_term['description'], 609 'slug' => $tax_term['slug'], 610 'taxonomy' => $tax_term['taxonomy'], 611 'parent' => $parent, // indicate parent for next loop iteration 612 ); 613 SyncDebug::log(__METHOD__.'() term does not exist- adding name ' . $tax_term['name'] . ' under "' . $tax_type . '" args=' . var_export($args, TRUE)); 614 $ret = wp_insert_term($tax_term['name'], $tax_type, $args); 615 if (is_wp_error($ret)) { 616 $term_id = 0; 617 $parent = 0; 618 } else { 619 $term_id = intval($ret['term_id']); 620 $parent = $term_id; // set the parent to this term id so next loop iteraction looks for term's children 621 } 622 SyncDebug::log(__METHOD__.'() insert term [hier] result: ' . var_export($ret, TRUE)); 623 } else { 624 SyncDebug::log(__METHOD__.'() found term: ' . var_export($term, TRUE)); 625 if (isset($term->term_id)) { 626 $term_id = $term->term_id; 627 $parent = $term_id; // indicate parent for next loop iteration 628 } else { 629 SyncDebug::log(__METHOD__.'() ERROR: invalid term object'); 630 } 631 } 632 ++$generation; 633 } 634 // the loop exits with $term_id set to 0 (error) or the child-most term_id to be assigned to the object 571 $tax_type = $term_info['taxonomy']; // get taxonomy name from API contents 572 $term_id = $this->process_hierarchical_term($term_info, $taxonomies); 635 573 if (0 !== $term_id) { 636 SyncDebug::log(__METHOD__.'() adding term #' . $term_id . ' to object ' . $post_id);574 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' adding term #' . $term_id . ' to object ' . $post_id); 637 575 $ret = wp_add_object_terms($post_id, $term_id, $tax_type); 638 576 SyncDebug::log(__METHOD__.'() add [hier] object terms result: ' . var_export($ret, TRUE)); 639 577 } 640 } 578 } // END FOREACH 641 579 } 642 580 … … 687 625 // if the $post_term assigned to the post is NOT in the $taxonomies list, it needs to be removed 688 626 SyncDebug::log(__METHOD__.'() ** removing term #' . $post_term->term_id . ' ' . $post_term->slug . ' [' . $post_term->taxonomy . ']'); 689 wp_remove_object_terms($post_id, intval($post_term->term_id), $post_term->taxonomy);627 wp_remove_object_terms($post_id, abs($post_term->term_id), $post_term->taxonomy); 690 628 } 691 629 } … … 698 636 */ 699 637 // TODO: move this to a model class - doesn't belong in a controller class 700 private function get_post_by_title($title)638 /* private function get_post_by_title($title) 701 639 { 702 640 global $wpdb; … … 717 655 } 718 656 return NULL; 719 } 657 } */ 720 658 721 659 /** … … 747 685 // https://en.wikipedia.org/wiki/List_of_file_signatures 748 686 749 $featured = isset($_POST['featured']) ? intval($_POST['featured']) : 0;687 $featured = isset($_POST['featured']) ? abs($_POST['featured']) : 0; 750 688 $path = $_FILES['sync_file_upload']['name']; 751 689 752 690 // check file type 691 $img_type = wp_check_filetype($path); 753 692 // TODO: add validating method to SyncAttachModel class 754 $img_type = wp_check_filetype($path); 755 $mime_type = $img_type['type']; 693 add_filter('spectrom_sync_upload_media_allowed_mime_type', array($this, 'filter_allowed_mime_types'), 10, 2); 756 694 SyncDebug::log(__METHOD__.'() found image type=' . $img_type['ext'] . '=' . $img_type['type']); 757 if (FALSE === strpos($mime_type, 'image/') && 'pdf' !== $img_type['ext']) {695 if (FALSE === apply_filters('spectrom_sync_upload_media_allowed_mime_type', FALSE, $img_type)) { 758 696 $response->error_code(SyncApiRequest::ERROR_INVALID_IMG_TYPE); 759 697 $response->send(); … … 770 708 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' query results: ' . var_export($get_posts, TRUE)); 771 709 772 // TODO: move this to a model710 // TODO: move this to SyncAttachModel 773 711 global $wpdb; 774 712 $sql = "SELECT `ID` … … 778 716 $attachment_id = 0; 779 717 if (0 != count($res)) 780 $attachment_id = intval($res[0]);718 $attachment_id = abs($res[0]); 781 719 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' id=' . $attachment_id . ' sql=' . $stmt . ' res=' . var_export($res, TRUE)); 782 720 // TODO: need to assume error and only set to success(TRUE) when file successfully processed … … 784 722 785 723 // convert source post id to target post id 786 $source_post_id = intval($_POST['post_id']);724 $source_post_id = abs($_POST['post_id']); 787 725 $target_post_id = 0; 788 726 $model = new SyncModel(); 789 $sync_data = $model->get_sync_data($source_post_id, $this->source_site_key); 727 $content_type = apply_filters('spectrom_sync_upload_media_content_type', 'post'); 728 $sync_data = $model->get_sync_data($source_post_id, $this->source_site_key, $content_type); 790 729 if (NULL !== $sync_data) 791 $target_post_id = intval($sync_data->target_content_id);730 $target_post_id = abs($sync_data->target_content_id); 792 731 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' source id=' . $source_post_id . ' target id=' . $target_post_id); 793 732 … … 812 751 // $file = media_handle_upload('sync_file_upload', $this->post('post_id', 0), array(), $overrides); 813 752 // $response->notice_code(SyncApiRequest::NOTICE_FILE_EXISTS); 753 $this->media_id = $attachment_id; 814 754 815 755 // if it's the featured image, set that … … 854 794 wp_update_attachment_metadata($attach_id, $attach); 855 795 $response->set('post_id', $this->post('post_id')); 796 $this->media_id = $attach_id; 856 797 857 798 // if it's the featured image, set that 858 799 if ($featured && 0 !== $target_post_id) { 859 800 SyncDebug::log(__METHOD__."() set_post_thumbnail({$target_post_id}, {$attach_id})"); 860 set_post_thumbnail($target_post_id, $attach_id /* intval($file)*/);801 set_post_thumbnail($target_post_id, $attach_id /*abs($file)*/); 861 802 } 862 803 } … … 878 819 $media = new SyncMediaModel(); 879 820 $media->log($media_data); 880 } 821 822 // notify add-ons about media 823 do_action('spectrom_sync_media_processed', $target_post_id, $attachment_id, $this->media_id); 824 } 825 } 826 827 /** 828 * Filter the mime types allowed in upload_media() 829 * @param boolean $default Current allowed state 830 * @param array $img_type The mime type information with array keys of ['type'] and ['ext'] 831 * @return boolean TRUE to allow this mime type; otherwise FALSE 832 */ 833 public function filter_allowed_mime_types($default, $img_type) 834 { 835 // TODO: use get_allowed_mime_types() 836 // if the type contains 'image/' 837 if (FALSE !== stripos($img_type['type'], 'image/')) 838 return TRUE; 839 // allow PDF files 840 if ('pdf' === $img_type['ext']) 841 return TRUE; 842 843 return $default; 881 844 } 882 845 … … 926 889 return $info; 927 890 } 891 892 /** 893 * Process hierarchical term. Searches for and creates taxonomy lineages in order to find child most term id that matches hierarchy. 894 * @param array $term_info Array of term info from the Source site 895 * @param array $taxonomies Array of taxonomies sent via API POST request 896 * @return int 0 to indicate error or the child-most term_id to be assigned to the target 897 */ 898 public function process_hierarchical_term($term_info, $taxonomies) 899 { 900 $tax_type = $term_info['taxonomy']; 901 SyncDebug::log(__METHOD__ . '() build lineage for taxonomy: ' . $tax_type); 902 903 // first, build a lineage list of the taxonomy terms 904 $lineage = array(); 905 $lineage[] = $term_info; // always add the current term to the lineage 906 $parent = abs($term_info['parent']); 907 SyncDebug::log(__METHOD__ . '() looking for parent term #' . $parent); 908 if (isset($taxonomies['lineage'][$tax_type])) { 909 while (0 !== $parent) { 910 foreach ($taxonomies['lineage'][$tax_type] as $tax_term) { 911 SyncDebug::log(__METHOD__ . '() checking lineage for #' . $tax_term['term_id'] . ' - ' . $tax_term['slug']); 912 if ($tax_term['term_id'] == $parent) { 913 SyncDebug::log(__METHOD__ . '() - found term ' . $tax_term['slug'] . ' as a child of ' . $parent); 914 $lineage[] = $tax_term; 915 $parent = abs($tax_term['parent']); 916 break; 917 } 918 } 919 } 920 } else { 921 SyncDebug::log(__METHOD__ . '() no taxonomy lineage found for: ' . $tax_type); 922 } 923 $lineage = array_reverse($lineage); // swap array order to start loop with top-most term first 924 SyncDebug::log(__METHOD__ . '() taxonomy lineage: ' . var_export($lineage, TRUE)); 925 926 // next, make sure each term in the hierarchy exists - we'll end on the taxonomy id that needs to be assigned 927 SyncDebug::log(__METHOD__ . '() setting taxonomy terms for taxonomy "' . $tax_type . '"'); 928 $generation = $parent = 0; 929 foreach ($lineage as $tax_term) { 930 SyncDebug::log(__METHOD__ . '() checking term #' . $tax_term['term_id'] . ' ' . $tax_term['slug'] . ' parent=' . $tax_term['parent']); 931 $term = NULL; 932 if (0 === $parent) { 933 SyncDebug::log(__METHOD__ . '() getting top level taxonomy ' . $tax_term['slug'] . ' in taxonomy ' . $tax_type); 934 $term = get_term_by('slug', $tax_term['slug'], $tax_type, OBJECT); 935 if (is_wp_error($term) || FALSE === $term) { 936 SyncDebug::log(__METHOD__ . '() error=' . var_export($term, TRUE)); 937 $term = NULL; // term not found, set to NULL so code below creates it 938 } 939 SyncDebug::log(__METHOD__ . '() no parent but found term: ' . var_export($term, TRUE)); 940 } else { 941 $child_terms = get_term_children($parent, $tax_type); 942 SyncDebug::log(__METHOD__ . '() found ' . count($child_terms) . ' term children for #' . $parent); 943 if (!is_wp_error($child_terms)) { 944 // loop through the children until we find one that matches 945 foreach ($child_terms as $term_id) { 946 $term_child = get_term_by('id', $term_id, $tax_type); 947 SyncDebug::log(__METHOD__ . '() term child: ' . $term_child->slug); 948 if ($term_child->slug === $tax_term['slug']) { 949 // found the child term 950 $term = $term_child; 951 break; 952 } 953 } 954 } 955 } 956 957 // see if the term needs to be created 958 if (NULL === $term) { 959 // term not found - create it 960 $args = array( 961 'description' => $tax_term['description'], 962 'slug' => $tax_term['slug'], 963 'taxonomy' => $tax_term['taxonomy'], 964 'parent' => $parent, // indicate parent for next loop iteration 965 ); 966 SyncDebug::log(__METHOD__ . '() term does not exist- adding name ' . $tax_term['name'] . ' under "' . $tax_type . '" args=' . var_export($args, TRUE)); 967 $ret = wp_insert_term($tax_term['name'], $tax_type, $args); 968 if (is_wp_error($ret)) { 969 $term_id = 0; 970 $parent = 0; 971 } else { 972 $term_id = abs($ret['term_id']); 973 $parent = $term_id; // set the parent to this term id so next loop iteraction looks for term's children 974 } 975 SyncDebug::log(__METHOD__ . '() insert term [hier] result: ' . var_export($ret, TRUE)); 976 } else { 977 SyncDebug::log(__METHOD__ . '() found term: ' . var_export($term, TRUE)); 978 if (isset($term->term_id)) { 979 $term_id = $term->term_id; 980 $parent = $term_id; // indicate parent for next loop iteration 981 } else { 982 SyncDebug::log(__METHOD__ . '() ERROR: invalid term object'); 983 } 984 } 985 ++$generation; 986 } 987 988 // the loop exits with $term_id set to 0 (error) or the child-most term_id to be assigned to the object 989 return $term_id; 990 } 928 991 } 929 992 -
wpsitesynccontent/trunk/classes/apiheaders.php
r1400702 r1745585 10 10 const HEADER_SOURCE = 'x-sync-source'; // Source site's URL; used in requests 11 11 const HEADER_SITE_KEY = 'x-sync-site-key'; // Source site's site_key; used in requests 12 const HEADER_MATCH_MODE = 'x-sync-match-mode'; // How to match Content on Target 12 13 } 13 14 -
wpsitesynccontent/trunk/classes/apimodel.php
r1492115 r1745585 21 21 22 22 $this->options = wp_parse_args($options, $default_options); 23 24 // check for maintenance mode plugins 25 $this->_maintenance_check(); 23 26 24 27 add_action('init', array(&$this, 'register_api'), 1000); … … 169 172 return array_combine($keys, $values); 170 173 } 174 175 /** 176 * Check for maintenance mode plugins and disable their actions that may interfere with WPSiteSync's API 177 */ 178 private function _maintenance_check() 179 { 180 // first, check to see if the current request is for a WPSiteSync API call 181 if (!isset($_GET['pagename']) || WPSiteSyncContent::API_ENDPOINT !== $_GET['pagename']) 182 return; 183 184 // now we know it's a WPSiteSync API call. Detect and disable any maintenance mode type plugins 185 186 // look for 'WP Maintenance Mode' plugin - https://wordpress.org/plugins/wp-maintenance-mode/ - 400,000 installs 187 if (class_exists('WP_Maintenance_Mode', FALSE)) { 188 add_filter('option_wpmm_settings', array($this, 'filter_wpmm_options'), 10, 2); 189 return; 190 } 191 // look for 'Maintenance' plugin - https://wordpress.org/plugins/maintenance/ - 300,000 installs 192 if (class_exists('maintenance', FALSE)) { 193 add_filter('option_maintenance_options', array($this, 'filter_maintenance_options'), 10, 2); 194 return; 195 } 196 // look for 'Coming Soon' plugin - https://wordpress.org/plugins/coming-soon/ - 300,000 installs 197 if (class_exists('SEED_CSP4', FALSE)) { 198 add_filter('seed_csp4_get_settings', array($this, 'filter_coming_soon_options'), 10 ,1); 199 return; 200 } 201 202 //die('inside ' . __METHOD__. '():' . __LINE__ . ' set=' . var_export($settings, TRUE)); 203 } 204 205 /** 206 * Filter for WP Maintenance Mode plugins' configuration settings. Used to deactivate plugin behavior 207 * @param array $value The settings to filter; called from get_option() 208 * @param string $option The option name, in this case always 'maintenance_options' 209 * @return array The modified settings for WP Maintenance Mode; with the maintenance mode deactivated. 210 */ 211 public function filter_wpmm_options($value, $option = '') 212 { 213 $value['general']['status'] = 0; 214 return $value; 215 } 216 217 /** 218 * Filter for the Maintenance plugin's configuration settings. Used to turn off maintenance mode. 219 * @param array $value The settings to filter; called from get_option() 220 * @param string $option The option name, in this case always 'maintenance_options' 221 * @return array The modified settings for Maintenance; with the maintenance mode turned off. 222 */ 223 public function filter_maintenance_options($value, $option = '') 224 { 225 if (isset($value['state']) && !empty($value['state'])) 226 $value['state'] = 0; // this makes load_maintenance_page() not load the maintenance page 227 return $value; 228 } 229 230 /** 231 * Filter for the Coming Soon plugin's configuration settings. Used to turn off it's features 232 * @param array $settings The Coming Soon plugins settings 233 * @return array The modified settings, with the 'status' value set to 0 to disable it 234 */ 235 public function filter_coming_soon_options($settings) 236 { 237 $settings['status'] = '0'; 238 return $settings; 239 } 171 240 } 172 241 -
wpsitesynccontent/trunk/classes/apirequest.php
r1573030 r1745585 34 34 const ERROR_CANNOT_WRITE_TOKEN = 27; 35 35 const ERROR_UPLOAD_NO_CONTENT = 28; 36 const ERROR_PHP_ERROR_ON_TARGET = 29; 36 37 37 38 const NOTICE_FILE_EXISTS = 1; … … 43 44 private $_source_domain = NULL; // domain sending the post information 44 45 45 private $_response = NULL; 46 private $_response = NULL; // the SyncApiResponse instance for the current request 46 47 47 48 private $_user_id = 0; … … 124 125 if (is_wp_error($data) || $response->has_errors()) { 125 126 // an error occured somewhere along the way. report it and return 126 // $response->error_code( intval($res->get_message()));127 // $response->error_code(abs($res->get_message())); 127 128 return $response; 128 129 } … … 143 144 // $remote_args['headers'][self::HEADER_SITE_KEY] = WPSiteSyncContent::get_option('site_key'); // $model->generate_site_key(); 144 145 $remote_args['headers'][self::HEADER_SITE_KEY] = SyncOptions::get('site_key'); // $model->generate_site_key(); 146 $remote_args['headers'][self::HEADER_MATCH_MODE] = SyncOptions::get('match_mode', 'title'); 145 147 //SyncDebug::log(__METHOD__.'() plugin sitekey=' . WPSiteSyncContent::get_option('site_key') . ' // option sitekey=' . SyncOptions::get('site_key')); 146 148 if (!isset($remote_args['timeout'])) … … 166 168 // validate the host and credentials 167 169 if (!($request['response']['code'] >= 200 && $request['response']['code'] < 300)) { 168 $response->error_code(self::ERROR_BAD_POST_RESPONSE, intval($request['response']['code']));170 $response->error_code(self::ERROR_BAD_POST_RESPONSE, abs($request['response']['code'])); 169 171 } else if (!isset($request['headers'][self::HEADER_SYNC_VERSION])) { 170 172 $response->error_code(self::ERROR_NOT_INSTALLED); … … 179 181 // API request went through, check for error_code returned in JSON results 180 182 $request_body = $this->_adjust_response_body($request['body']); 181 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' response body: ' . $request_body); // $request['body']);183 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' response body: ' . $request_body); // $request['body']); 182 184 $response->response = json_decode($request_body /*$request['body']*/); 183 185 // TODO: convert error/notice codes into strings at this point. 184 186 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' received response from Target for "' . $action . '":'); 185 SyncDebug::log(var_export($response->response, TRUE)); 187 //SyncDebug::log(__METHOD__.'():' . __LINE__ .' body: ' . $request_body); 188 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' - ' . var_export($response->response, TRUE)); 186 189 187 190 // examine the Target response's error codes and assign them to the local system's response object … … 217 220 //$response->response->error_code) { // 218 221 // if (0 === $response->get_error_code()) { 219 if (0 === intval($response->response->error_code)) {222 if (0 === abs($response->response->error_code)) { 220 223 $response->success(TRUE); 221 224 // if it was an authentication request, store the auth cookies in user meta … … 227 230 case 'auth': // no logging, but add to source table and set target site_key 228 231 if (isset($response->response->data)) { 232 // TODO: deprecated 229 233 update_user_meta($this->_user_id, 'spectrom_site_cookies', $response->response->data->auth_cookie); 230 234 update_user_meta($this->_user_id, 'spectrom_site_nonce', $response->response->data->access_nonce); … … 287 291 private function _adjust_response_body($body) 288 292 { 293 $body = trim($body); 294 $error = FALSE; 289 295 if ('{' !== $body[0]) { 296 SyncDebug::log(__METHOD__.'() found extra data in response content: ' . var_export($body, TRUE)); 297 // checks to see that the JSON payload starts with '{"error_code":' - which is the initial data send in a SyncApiResponse object 290 298 $pos = strpos($body, '{"error_code":'); 291 299 if (FALSE !== $pos) 292 300 $body = substr($body, $pos); 293 $pos = strpos($body, '"}}'); 294 if (FALSE !== $pos) 295 $body = substr($body, 0, $pos + 3); 301 // $pos = strpos($body, '"}}'); 302 // if (FALSE !== $pos) 303 // $body = substr($body, 0, $pos + 3); 304 // make sure that a '}' is the last character of the response data 305 $pos = strrpos($body, '}'); 306 if ($pos !== strlen($body) - 1) 307 $body = substr($body, 0, $pos + 1); 308 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' response body=' . var_export($body, TRUE)); 309 } 310 if (FALSE === strpos($body, '{')) { 311 // no JSON data present in response 312 $body = '{"error_code":' . self::ERROR_PHP_ERROR_ON_TARGET . ',"has_errors":1,"success":0,"data":{"error":"none"}}'; 296 313 } 297 314 return $body; … … 545 562 $auth = new SyncAuth(); 546 563 $data['password'] = $auth->encode_password($data['password'], $data['host']); 564 565 $parts = explode(':', $data['password']); 566 $this->_target_data['password'] = $data['password'] = $parts[0]; 567 $this->_target_data['encode'] = $data['encode'] = $parts[1]; 547 568 } 548 569 //SyncDebug::log(__METHOD__.'() data: ' . var_export($data, TRUE)); … … 604 625 private function _push($data) 605 626 { 606 $post_id = intval($data['post_id']);627 $post_id = abs($data['post_id']); 607 628 return $this->get_push_data($post_id, $data); 608 629 } … … 682 703 683 704 // if no content, there's nothing to do 684 if (empty($content))685 return;705 // if (empty($content)) 706 // return; 686 707 687 708 // sometimes the insert media into post doesn't add a space...this will hopefully fix that 688 709 $content = str_replace('alt="', ' alt="', $content); 710 if (empty($content)) 711 return TRUE; 689 712 690 713 // TODO: add try..catch … … 733 756 foreach ($classes as $class) { 734 757 if ('wp-image-' === substr($class, 0, 9)) { 735 $img_id = intval(substr($class, 9));758 $img_id = abs(substr($class, 9)); 736 759 $img_post = get_post($img_id, OBJECT); 737 760 if (NULL !== $img_post) { … … 756 779 } 757 780 } 758 if ($this->send_media($src_attr, $post_id, $post_thumbnail_id, $img_id)) 759 return FALSE; 781 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' calling send_media("' . $src_attr . '", ' . $post_id . ', ' . $post_thumbnail_id . ', ' . $img_id . ')'); 782 // if ($this->send_media($src_attr, $post_id, $post_thumbnail_id, $img_id)) 783 // return FALSE; 784 $this->send_media($src_attr, $post_id, $post_thumbnail_id, $img_id); 760 785 } 761 786 } … … 783 808 } 784 809 } 785 $this->send_media($href_attr, $post_id, $post_thumbnail_id, $attach_id); 810 if (0 !== $attach_id) // https://wordpress.org/support/topic/bugs-68/ 811 $this->send_media($href_attr, $post_id, $post_thumbnail_id, $attach_id); 786 812 } else { 787 813 //SyncDebug::log(' - no attachment to send'); … … 792 818 if ('' !== $post_thumbnail_id) { 793 819 SyncDebug::log(__METHOD__.'() featured image:'); 794 $img = wp_get_attachment_image_src($post_thumbnail_id, ' large');820 $img = wp_get_attachment_image_src($post_thumbnail_id, 'full'); 795 821 SyncDebug::log(' src=' . var_export($img, TRUE)); 796 822 // convert site url to relative path … … 819 845 public function set_source_domain($domain) 820 846 { 847 //SyncDebug::log(__METHOD__.'() domain=' . $domain); 821 848 // sanitize value to remove protocol and slashes 822 $this->_source_domain = parse_url($domain, PHP_URL_HOST); 849 if (FALSE !== stripos($domain, 'http') || FALSE !== strpos($domain, '/')) 850 $domain = parse_url($domain, PHP_URL_HOST); 851 852 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' domain: ' . $domain); 853 $this->_source_domain = $domain; 823 854 } 824 855 … … 879 910 // 'name' => 'value', 880 911 'post_id' => $post_id, 881 'featured' => intval($featured),912 'featured' => abs($featured), 882 913 'boundary' => wp_generate_password(24), // TODO: remove and generate when formatting POST content in _media() 883 914 'img_path' => dirname($file_path), … … 892 923 'attach_alt' => (NULL !== $attach_post) ? $attach_alt : '', 893 924 ); 925 // allow extensions to include data in upload_media operations 926 $post_fields = apply_filters('spectrom_sync_upload_media_fields', $post_fields); 927 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' fields: ' . var_export($post_fields, TRUE)); 928 894 929 //$post_fields['content-len'] = strlen($post_fields['contents']); 895 930 //$post_fields['content-type'] = gettype($post_fields['contents']); … … 937 972 case self::ERROR_BAD_NONCE: $error = __('Unable to validate AJAX request.', 'wpsitesynccontent'); break; 938 973 case self::ERROR_UNRESOLVED_PARENT: $error = __('Content has a Parent Page that has not been Sync\'d.', 'wpsitesynccontent'); break; 939 case self::ERROR_NO_AUTH_TOKEN: $error = __('Unable to authenticat ionwith Target site. Please re-enter credentials for this site.', 'wpsitesynccontent'); break;974 case self::ERROR_NO_AUTH_TOKEN: $error = __('Unable to authenticate with Target site. Please re-enter credentials for this site.', 'wpsitesynccontent'); break; 940 975 case self::ERROR_NO_PERMISSION: $error = __('User does not have permission to perform Sync. Check configured user on Target.', 'wpsitesynccontent'); break; 941 976 case self::ERROR_INVALID_IMG_TYPE: $error = __('The image uploaded is not a valid image type.', 'wpsitesynccontent'); break; … … 944 979 case self::ERROR_CANNOT_WRITE_TOKEN: $error = __('Cannot write authentication token.', 'wpsitesynccontent'); break; 945 980 case self::ERROR_UPLOAD_NO_CONTENT: $error = __('Attachment upload failed. No content found; is there a broken link?', 'wpsitesynccontent'); break; 981 case self::ERROR_PHP_ERROR_ON_TARGET: $error = __('A PHP error occurred on Target while processing your request. Examine log files for more information.', 'wpsitesynccontent'); break; 946 982 947 983 default: … … 983 1019 public static function get_error($error_code, $error_data = NULL) 984 1020 { 985 $error_code = intval($error_code);1021 $error_code = abs($error_code); 986 1022 $msg = self::error_code_to_string($error_code); 987 1023 if (NULL !== $error_data) … … 990 1026 return new WP_Error($error_code, $msg); 991 1027 } 1028 1029 /** 1030 * Returns the SyncApiResponse instance used to reply to the current API request 1031 * @return SyncApiResponse instance 1032 */ 1033 public function get_response() 1034 { 1035 return $this->_response; 1036 } 992 1037 } 993 1038 -
wpsitesynccontent/trunk/classes/apiresponse.php
r1573030 r1745585 46 46 public function has_errors() 47 47 { 48 if ( count($this->errors) || count($this->validation) || 0 !== $this->error_code)48 if (0 !== $this->error_code || count($this->errors) || count($this->validation)) 49 49 return TRUE; 50 50 return FALSE; … … 150 150 // only allow one error code 151 151 if (0 === $this->error_code) { 152 $this->error_code = intval($code);152 $this->error_code = abs($code); 153 153 if (NULL !== $data) 154 154 $this->error_data = $data; -
wpsitesynccontent/trunk/classes/auth.php
r1560226 r1745585 142 142 //SyncDebug::log(' - key: ' . $key); 143 143 144 $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB); 145 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 146 $encrypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, utf8_encode($password), MCRYPT_MODE_ECB, $iv); 147 $encoded = base64_encode($encrypted); 144 $left = $right = ''; 145 if (function_exists('mcrypt_get_iv_size')) { 146 $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB); 147 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 148 $encrypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, utf8_encode($password), MCRYPT_MODE_ECB, $iv); 149 $left = base64_encode($encrypted); 150 } 151 152 $right = $this->enc_str($password, $key); 153 154 $encoded = $left . ':' . $right; 148 155 return $encoded; 149 156 } … … 160 167 $key = $this->get_key($target); 161 168 //SyncDebug::log(' key: ' . $key); 162 $decoded = base64_decode($password); 169 170 $left = $password; 171 if (!empty($_POST['encode'])) 172 $right = $_POST['encode']; 173 174 $cleartext = NULL; 175 if (function_exists('mcrypt_get_iv_size')) { 176 $decoded = base64_decode($left); 163 177 //SyncDebug::log(' decoded: ' . $decoded); 164 178 165 $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);166 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);167 $cleartext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $decoded, MCRYPT_MODE_ECB, $iv);179 $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB); 180 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 181 $cleartext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $decoded, MCRYPT_MODE_ECB, $iv); 168 182 //SyncDebug::log(' cleartext: ' . var_export($cleartext, TRUE)); 169 $cleartext = trim($cleartext, "\0"); 183 $cleartext = trim($cleartext, "\0"); 184 //SyncDebug::log(__METHOD__.'() decoded left "' . $left . '" into "' . $cleartext . '"'); 185 } 186 if (empty($cleartext) && !empty($right)) { 187 $cleartext = $this->dec_str($right, $key); 188 //SyncDebug::log(__METHOD__.'() decoded right "' . $right . '" into "' . $cleartext . '"'); 189 } 190 170 191 //SyncDebug::log(' cleartext: ' . var_export($cleartext, TRUE)); 171 192 return $cleartext; 193 } 194 195 /** 196 * Encrypts a string 197 * @param type $string 198 * @param type $key 199 * @return type 200 */ 201 private function enc_str($string, $key) 202 { 203 $result = ''; 204 for ($i = 0; $i < strlen($string); ++$i) { 205 $char = substr($string, $i, 1); 206 $keychar = substr($key, ($i % strlen($key)) - 1, 1); 207 $char = chr(ord($char) + ord($keychar)); 208 $result .= $char; 209 } 210 211 return base64_encode($result); 212 } 213 214 /** 215 * Decrypts a string 216 * @param type $string 217 * @param type $key 218 * @return type 219 */ 220 function dec_str($string, $key) 221 { 222 $result = ''; 223 $string = base64_decode($string); 224 225 for ($i = 0; $i < strlen($string); ++$i) { 226 $char = substr($string, $i, 1); 227 $keychar = substr($key, ($i % strlen($key)) - 1, 1); 228 $char = chr(ord($char) - ord($keychar)); 229 $result .= $char; 230 } 231 232 return $result; 172 233 } 173 234 -
wpsitesynccontent/trunk/classes/debug.php
r1560226 r1745585 4 4 { 5 5 const DEBUG = TRUE; 6 7 public static $_debug = FALSE; 6 8 7 9 public static $_debug_output = FALSE; … … 32 34 public static function log($msg = NULL, $backtrace = FALSE) 33 35 { 34 if (! defined('WP_DEBUG') || !WP_DEBUG)36 if (!self::$_debug && !defined('WP_DEBUG') || !WP_DEBUG) 35 37 return; 36 38 … … 58 60 59 61 if ($backtrace) { 60 $callers = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS);62 $callers = debug_backtrace(defined('DEBUG_BACKTRACE_IGNORE_ARGS') ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE); 61 63 array_shift($callers); 62 64 $path = dirname(dirname(dirname(plugin_dir_path(__FILE__)))) . DIRECTORY_SEPARATOR; -
wpsitesynccontent/trunk/classes/licensing.php
r1560226 r1745585 125 125 ); 126 126 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' sending ' . var_export($api_params, TRUE) . ' to ' . $this->_get_api_url()); 127 $response = wp_remote_get( add_query_arg($api_params, $this->_get_api_url()), array('timeout' => 15, 'sslverify' => FALSE));127 $response = wp_remote_get($remote_url = add_query_arg($api_params, $this->_get_api_url()), array('timeout' => 15, 'sslverify' => FALSE)); 128 128 if (is_wp_error($response)) { 129 129 self::$_status[$slug] = FALSE; … … 133 133 134 134 // check response 135 $license_data = json_decode(wp_remote_retrieve_body($response)); 135 $response_body = wp_remote_retrieve_body($response); 136 if (!empty($response_body)) { 137 $license_data = json_decode($response_body); 136 138 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' license data=' . var_export($license_data, TRUE)); 137 if ('valid' === $license_data->license) {138 // this license is still valid139 self::$_licenses[$slug . '_st'] = self::STATE_ACTIVE;140 self::$_licenses[$slug . '_tr'] = time() + self::LICENSE_TTL;141 self::$_licenses[$slug . '_vl'] = md5($slug . $name);139 if ('valid' === $license_data->license) { 140 // this license is still valid 141 self::$_licenses[$slug . '_st'] = self::STATE_ACTIVE; 142 self::$_licenses[$slug . '_tr'] = time() + self::LICENSE_TTL; 143 self::$_licenses[$slug . '_vl'] = md5($slug . $name); 142 144 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' [' . $slug . '] vl=' . self::$_licenses[$slug . '_vl']); 145 } else { 146 // this license is no longer valid 147 self::$_licenses[$slug . '_st'] = self::STATE_UNKNOWN; 148 self::$_licenses[$slug . '_vl'] = ''; 149 } 150 self::$_dirty = TRUE; 151 $this->save_licenses(); 143 152 } else { 144 // this license is no longer valid 145 self::$_licenses[$slug . '_st'] = self::STATE_UNKNOWN; 146 self::$_licenses[$slug . '_vl'] = ''; 147 } 148 self::$_dirty = TRUE; 149 $this->save_licenses(); 153 SyncDebug::log(__METHOD__.'():' . __LINE__ . ' slug=' . $slug . ' url=' . $remote_url . ' with params: ' . var_export($api_params, TRUE) . ' returned: ' . $response_body); 154 } 150 155 //SyncDebug::log(__METHOD__.'():' . __LINE__ . ' setting dirty flag'); 151 156 } -
wpsitesynccontent/trunk/classes/model.php
r1492115 r1745585 7 7 private $_sync_table = NULL; 8 8 private static $_taxonomies = array(); 9 private $_edit_user_id = FALSE; 9 10 10 11 public function __construct() … … 43 44 44 45 /** 46 * Removes all WPSiteSync data for a given post ID 47 * @param int $post_id The ID of the Content to remove. Can be used on Source or Target; uses site key to distinguish context. 48 */ 49 public function remove_all_sync_data($post_id) 50 { 51 $site_key = SyncOptions::get('site_key'); 52 53 global $wpdb; 54 $sql = "DELETE FROM `{$this->_sync_table}` 55 WHERE (`source_content_id`=%d AND `site_key`=%s) OR 56 (`target_content_id`=%d AND `target_site_key`=%s)"; 57 $sql = $wpdb->prepare($sql, $post_id, $site_key, $post_id, $site_key); 58 SyncDebug::log(__METHOD__.'() sql=' . $sql); 59 $wpdb->query($sql); 60 } 61 62 /** 45 63 * Saves a sync record to the database. 46 64 * @param array $data The sync data. … … 78 96 } else { 79 97 SyncDebug::log(__METHOD__.'() inserting ' . $data['source_content_id']); 80 $wpdb->insert($this->_sync_table, $data); 98 $res = $wpdb->insert($this->_sync_table, $data); 99 // TODO: when insert fails, display error message/recover 100 //SyncDebug::log(__METHOD__.'() res=' . var_export($res, TRUE)); 101 //if (FALSE === $res) 102 // SyncDebug::log(__METHOD__.'() sql=' . $wpdb->last_query); 81 103 } 82 104 } … … 165 187 166 188 /** 189 * Updates an existing record in the table with new information 190 * @global type $wpdb 191 * @param type $where 192 * @param type $update 193 */ 194 public function update($where, $update) 195 { 196 global $wpdb; 197 $wpdb->update($this->_sync_table, $update, $where); 198 } 199 200 /** 167 201 * Build the array of post data to be used in a Sync call 168 202 * @param int $post_id The post ID … … 249 283 foreach ($post_meta as $key => $value) { 250 284 // remove any '_spectrom_sync_' meta data and the '_edit...' meta data 251 if ( strpos('_spectrom_sync_', $key) || in_array($key, $skip_keys)) {285 if ('_spectrom_sync_' === substr($key, 0, 15) || in_array($key, $skip_keys)) { 252 286 unset($post_meta[$key]); 253 287 continue; -
wpsitesynccontent/trunk/classes/options.php
r1446190 r1745585 23 23 * 'min_role' = minimum role allowed to perform SYNC operations 24 24 * 'remove' = remove settings/tables on plugin deactivation 25 * 'match_mode' = method for matching content on Target: 'title', 'slug', 'id' 25 26 */ 26 27 -
wpsitesynccontent/trunk/classes/settings.php
r1560226 r1745585 155 155 echo '<input type="hidden" name="sync-settings-tab" value="', esc_attr($this->_tab), '" />'; 156 156 do_settings_sections('sync'); 157 submit_button(); 157 submit_button(); 158 158 echo '</form>'; 159 159 echo '<p>', __('WPSiteSync for Content Site key: ', 'wpsitesynccontent'), '<b>', SyncOptions::get('site_key'), '</b></p>'; … … 210 210 'min_role' => '', 211 211 'remove' => '0', 212 'match_mode' => 'title', 212 213 ) 213 214 ); … … 308 309 ); 309 310 311 switch ($data['match_mode']) { 312 case 'slug': $desc = __('Slug - Search for matching Content on Target by Post Slug.', 'wpsitesynccontent'); 313 break; 314 case 'id': $desc = __('ID - Search for matching Content on Target by Post ID.', 'wpsitesynccontent'); 315 break; 316 case 'title': $desc = __('Post Title - Search for matching Content on Target by Post Title.', 'wpsitesynccontent'); 317 default: 318 break; 319 } 320 321 add_settings_field( 322 'match_mode', // field id 323 __('Content Match Mode:', 'wpsitesynccontent'), // title 324 array($this, 'render_select_field'), // callback 325 self::SETTINGS_PAGE, // page 326 $section_id, // section id 327 array( // args 328 'name' => 'match_mode', 329 'value' => $data['match_mode'], 330 'options' => array( 331 'title' => __('Post Title', 'wpsitesynccontent'), 332 'slug' => __('Post Slug', 'wpsitesynccontent'), 333 // 'id' => __('Post ID', 'wpsitesynccontent'), 334 ), 335 'description' => $desc, 336 ) 337 ); 338 310 339 /* 311 340 add_settings_field( … … 390 419 $args['name'], $args['name'], esc_attr($args['value'])); 391 420 foreach ($args['options'] as $key => $value) { 392 echo '<option value="', esc_attr($key), '" >', esc_html($value), '</option>';421 echo '<option value="', esc_attr($key), '" ', selected($key, $args['value']), '>', esc_html($value), '</option>'; 393 422 } 394 423 echo '</select>'; 424 425 if (!empty($args['description'])) 426 echo '<p><em>', esc_html($args['description']), '</em></p>'; 395 427 } 396 428 … … 485 517 $missing_error = FALSE; 486 518 $re_auth = FALSE; 519 487 520 foreach ($values as $key => $value) { 488 521 //SyncDebug::log(" key={$key} value=[{$value}]"); … … 491 524 } else { 492 525 if ('host' === $key) { 493 if (FALSE === $this->_is_valid_url($value)) { 494 add_settings_error('sync_options_group', 'invalid-url', __('Invalid URL.', 'wpsitesynccontent')); 526 // check to see if 'host' is changing and force use of password 527 if ($value !== $settings['host'] && empty($values['password'])) { 528 add_settings_error('sync_host_password', 'missing-password', __('When changing Target site, a password is required.', 'wpsitesynccontent')); 495 529 $out[$key] = $settings[$key]; 496 530 } else { 497 $out[$key] = $value; 498 if ($out[$key] !== $settings[$key]) 499 $re_auth = TRUE; 531 if (FALSE === $this->_is_valid_url($value)) { 532 add_settings_error('sync_options_group', 'invalid-url', __('Invalid URL.', 'wpsitesynccontent')); 533 $out[$key] = $settings[$key]; 534 } else { 535 $out[$key] = $this->_normalize_url($value); 536 if ($out[$key] !== $settings[$key]) 537 $re_auth = TRUE; 538 } 539 } 540 } else if ('username' === $key) { 541 // TODO: refactor so that 'host' and 'username' password checking is combined 542 // check to see if 'username' is changing and force use of password 543 if ($value !== $settings['username'] && empty($values['password'])) { 544 add_settings_error('sync_username_password', 'missing-password', __('When changing Username, a password is required.', 'wpsitesynccontent')); 545 $out[$key] = $settings[$key]; 546 } else { 547 if (!empty($value)) { 548 if ($value !== $settings[$key]) 549 $re_auth = TRUE; 550 $out[$key] = $value; 551 } else 552 $out[$key] = $settings['username']; 500 553 } 501 554 } else if (0 === strlen(trim($value))) { … … 511 564 } else { 512 565 $out[$key] = $value; 513 if ('username' === $key && $out[$key] !== $settings[$key])514 $re_auth = TRUE;566 // if ('username' === $key && $out[$key] !== $settings[$key]) 567 // $re_auth = TRUE; 515 568 } 516 569 } … … 578 631 579 632 /** 633 * Normalizes the Target url, removes usernames, passwords, queries and fragments and forces trailing slash only when path is present. 634 * @param string $url The URL to be normalized 635 * @return string The normalized URL 636 */ 637 private function _normalize_url($url) 638 { 639 $parts = parse_url($url); 640 //SyncDebug::log(__METHOD__.'() parts=' . var_export($parts, TRUE)); 641 $ret = $parts['scheme'] . '://' . $parts['host']; 642 if (!empty($parts['port'])) 643 $ret .= ':' . $parts['port']; 644 $path = isset($parts['path']) ? trim($parts['path'], '/') : ''; 645 if (!empty($path)) 646 $ret .= '/' . $path . '/'; 647 return $ret; 648 } 649 650 /** 580 651 * Callback for adding contextual help to Sync Settings page 581 652 */ … … 605 676 '<p>' . __('<strong>Username on Target</strong>: Enter the Administrator username for the Target website.', 'wpsitesynccontent') . '</p>' . 606 677 '<p>' . __('<strong>Password on Target</strong>: Enter the Administrator password for the Target website.', 'wpsitesynccontent') . '</p>' . 607 '<p>' . __('<strong>Strict Mode:</strong>: Select if WordPress and WPSiteSync for Content should be the same versions on the Source and the Target.', 'wpsitesynccontent') . '</p>' 678 '<p>' . __('<strong>Strict Mode</strong>: Select if WordPress and WPSiteSync for Content should be the same versions on the Source and the Target.', 'wpsitesynccontent') . '</p>' . 679 '<p>' . __('<strong>Match Mode</strong>: How WPSiteSync should match posts on the Target. You can select "Post Title" (default), or "Post Slug" to match Content by Title or Slug.', 'wpsitesynccontent') . '</p>' 608 680 // '<p>' . __('<strong>Authentication Salt:</strong>: Enter a salt to use when Content is sent to current site or leave blank.', 'wpsitesynccontent') . '</p>' . 609 681 // '<p>' . __('<strong>Minimum Role allowed to SYNC Content</strong>: Select minimum role of user who can Sync Content to current site.', 'wpsitesynccontent') . '</p>' -
wpsitesynccontent/trunk/classes/sourcesmodel.php
r1560226 r1745585 56 56 $username = $res->auth_name; 57 57 $user = get_user_by('login', $username); 58 // if lookup by login name failed, try email address #118 59 if (FALSE === $user) 60 $user = get_user_by('email', $username); 58 61 if (FALSE !== $user) 59 62 return $user; -
wpsitesynccontent/trunk/install/activate.php
r1510336 r1745585 124 124 require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); 125 125 126 $charset_collate = '';127 if (!empty($wpdb->charset))128 $charset_collate = " DEFAULT CHARACTER SET {$wpdb->charset} ";126 // $charset_collate = ''; 127 // if (!empty($wpdb->charset)) 128 // $charset_collate = " DEFAULT CHARACTER SET {$wpdb->charset} "; 129 129 130 130 // determine default collation for tables being created 131 $collate = NULL; 132 if (defined('DB_COLLATE')) 133 $collate = DB_COLLATE; // if the constant is declared, use it 134 if ('utf8_unicode_ci' === $collate) // fix for CREATE TABLEs on WPEngine 135 $collate = 'utf8mb4_unicode_ci'; 136 if (empty($collate) && !empty($wpdb->collate)) // otherwise allow wpdb class to specify 137 $collate = $wpdb->collate; 138 if (!empty($collate)) 139 $charset_collate .= " COLLATE {$collate} "; 131 // $collate = NULL; 132 // if (defined('DB_COLLATE')) 133 // $collate = DB_COLLATE; // if the constant is declared, use it 134 // if ('utf8_unicode_ci' === $collate) // fix for CREATE TABLEs on WPEngine 135 // $collate = 'utf8mb4_unicode_ci'; 136 // if (empty($collate) && !empty($wpdb->collate)) // otherwise allow wpdb class to specify 137 // $collate = $wpdb->collate; 138 // if (!empty($collate)) 139 // $charset_collate .= " COLLATE {$collate} "; 140 $charset_collate = $wpdb->get_charset_collate(); 140 141 141 142 $aTables = $this->get_table_data(); -
wpsitesynccontent/trunk/readme.txt
r1573030 r1745585 4 4 Tags: attachments, content, content sync, data migration, desktopserver, export, import, migrate content, moving data, staging, synchronization, taxonomies 5 5 Requires at least: 3.5 6 Tested up to: 4.7 6 Requires PHP: 5.3.1 7 Tested up to: 4.8.2 7 8 Stable tag: trunk 8 9 License: GPLv2 or later … … 111 112 112 113 == Changelog == 114 = 1.3.2 - Oct 12, 2017 = 115 * fix: improve checking for sync-specific meta data to be ignored 116 * fix: only set user id if available in SyncApiController->push() 117 * fix: improved code that recovers from errors displayed within JSON response data 118 * fix: set $media_id property during 'upload_media' API calls to media type after create/update of image 119 * fix: adjust parameter for wp_get_attachment_image_src() 120 * fix: check parameter passed to debug_backtrace() in case of old (< 5.3.6) versions of PHP 121 * fix: handle empty post content and featured images correctly (Thanks to Lucas C.) 122 * fix: correct taxonomy term lookup on Target to preserve naming (Thanks to Calvin C.) 123 * fix: when changing Target or Username configs, require passwords (Thanks to Erin M.) 124 * fix: javascript compatibility issue with Visual Composer backend editor (Thanks to Carlos) 125 * fix: set taxonmy type for each taxonomy entries when processing hierarchical taxonomies 126 * fix: recover and continue from failures of media attachments rather than aborting 127 * fix: add Source to Target URL fixups in meta data and excerpt (Thanks to Bryan A.) 128 * enhancement: add hook to notify add-ons that images have completed processing 129 * enhancement: allow add-ons to modify HTTP post content during 'upload_media' API calls 130 * enhancement: allow authentication to check for email address, in addition to user name 131 * enhancement: add detection and circumvention of 'Coming Soon' / 'Maintenance Mode' plugins during API calls 132 * enhancement: allow add-ons to modify allowed mime types during 'upload_media' API calls 133 * enhancement: allow add-ons to modify `content_type` column in sync table 134 * enhancement: make display of error messages via UI easier 135 * enhancement: add callback to remove data from WPSS tables when content is deleted 136 * enhancement: add appropriate headers for AJAX responses 137 * enhancement: add 'match-mode' option to allow users to perform new content lookups on target by post title or slug; deprecate SyncApiController::get_post_by_title() 138 * enhancement: add fallback encryption when mcrypt is not available 139 113 140 = 1.3.1 - Jan 11, 2017 = 114 141 * Fix: add placeholder file to force creation of languages/ directory. -
wpsitesynccontent/trunk/wpsitesynccontent.php
r1573030 r1745585 6 6 Author: WPSiteSync 7 7 Author URI: http://wpsitesync.com 8 Version: 1.3. 18 Version: 1.3.2 9 9 Text Domain: wpsitesynccontent 10 10 Domain path: /language … … 25 25 class WPSiteSyncContent 26 26 { 27 const PLUGIN_VERSION = '1.3. 1';27 const PLUGIN_VERSION = '1.3.2'; 28 28 const PLUGIN_NAME = 'WPSiteSyncContent'; 29 29 … … 47 47 register_deactivation_hook(__FILE__, array(&$this, 'deactivate')); 48 48 49 add_action('plugins_loaded', array(&$this, 'endpoints_init') );49 add_action('plugins_loaded', array(&$this, 'endpoints_init'), 1); 50 50 // don't need the wp_ajax_noprov callback- AJAX calls are always within the admin 51 51 add_action('wp_ajax_spectrom_sync', array(&$this, 'check_ajax_query')); … … 242 242 return $filename; 243 243 } 244 244 245 /** 245 246 * Callback for 'upgrader_pre_download' filter called in WP_Upgrader->download_package().
Note: See TracChangeset
for help on using the changeset viewer.