CTX Feed – WooCommerce Product Feed Manager Plugin - Version 3.3.9

Version Description

(2020-03-18) = * Fix: Replace space character with underscore (_). * Fix: Fix and optimize sortable table initialization.

Download this release

Release Info

Developer wahid0003
Plugin Icon 128x128 CTX Feed – WooCommerce Product Feed Manager Plugin
Version 3.3.9
Comparing to
See all releases

Code changes from version 3.3.8 to 3.3.9

README.txt CHANGED
@@ -5,7 +5,7 @@ Tags:product feed,woocommerce product feed,google shopping feed,google shopping,
5
  Requires at least: 3.6
6
  Tested Up To: 5.3.2
7
  Requires PHP: 5.6
8
- Stable tag: 3.3.8
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -305,6 +305,10 @@ Using pro version:
305
 
306
  == Changelog ==
307
 
 
 
 
 
308
  = 3.3.8 (2020-03-16) =
309
  * Compatibility: Tested Upto WooCommerce 4.0
310
  * Improve: Cleanup and minify assets (CSS & JS)
5
  Requires at least: 3.6
6
  Tested Up To: 5.3.2
7
  Requires PHP: 5.6
8
+ Stable tag: 3.3.9
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
305
 
306
  == Changelog ==
307
 
308
+ = 3.3.9 (2020-03-18) =
309
+ * Fix: Replace space character with underscore (`_`).
310
+ * Fix: Fix and optimize sortable table initialization.
311
+
312
  = 3.3.8 (2020-03-16) =
313
  * Compatibility: Tested Upto WooCommerce 4.0
314
  * Improve: Cleanup and minify assets (CSS & JS)
admin/js/woo-feed-admin.js CHANGED
@@ -29,8 +29,7 @@
29
  */
30
  $.fn.disabled = function( status ) {
31
  $(this).each( function(){
32
- // noinspection ES6ConvertVarToLetConst
33
- var self = $(this), prop = 'disabled';
34
  if( typeof( self.prop( prop ) ) !== 'undefined' ) {
35
  self.prop( prop, status === void 0 || status === true );
36
  } else {
@@ -43,8 +42,7 @@
43
  * Check if a HTMLElement or jQuery is disabled
44
  */
45
  $.fn.isDisabled = function() {
46
- // noinspection ES6ConvertVarToLetConst
47
- var self = $(this), prop = 'disabled';
48
  return ( typeof( self.prop( prop ) ) !== 'undefined' ) ? self.prop( prop ) : self.hasClass( prop );
49
  };
50
 
@@ -63,8 +61,7 @@
63
  }
64
 
65
  function fallbackMessage(action) {
66
- // noinspection ES6ConvertVarToLetConst
67
- var actionMsg, actionKey = (action === 'cut' ? 'X' : 'C');
68
  if (/iPhone|iPad/i.test(navigator.userAgent)) {
69
  actionMsg = 'No support :(';
70
  } else if (/Mac/i.test(navigator.userAgent)) {
@@ -82,8 +79,7 @@
82
  * @param {Object} _args
83
  */
84
  const extend = ( _default, _args ) => $.extend( true, {}, _default, _args );
85
- // noinspection ES6ConvertVarToLetConst
86
- var $copyBtn, clipboard, googleCategories,
87
  helper = {
88
  in_array: function( needle, haystack ) {
89
  try {
@@ -100,24 +96,26 @@
100
  alert( ( e.hasOwnProperty( 'statusText' ) && e.hasOwnProperty( 'status' ) ) ? opts.ajax.error + '\n' + e.statusText + ' (' + e.status + ')' : e );
101
  },
102
  sortable: function( el, config ) {
103
- console.log( ( el || $('.sorted_table') ) );
104
- ( el || $('.sorted_table') ).wf_sortable( extend( {
105
- containerSelector: 'table',
106
- itemPath: '> tbody',
107
- itemSelector: 'tr',
108
- handle: 'i.wf_sortedtable',
109
- placeholder: '<tr class="placeholder"><td colspan="9"></td></tr>',
110
- }, config ));
 
 
111
  },
112
  selectize: function( el, config ) {
113
- return ( el || $('select.selectize') ).not('.selectized').each(function(){
114
  let self = $(this);
115
- self.selectize( extend( {
116
  create: self.data('create') || false,
117
- plugins: self.data('plugins') ? self.data('plugins').split(',').map( s => s.trim() ): [],//['remove_button'],
118
  render: {item: helper.selectize_render_item,}
119
- }, config ) );
120
- } );
121
  }
122
  }, // helper functions
123
  feedEditor = {
@@ -134,8 +132,7 @@
134
  let self = this;
135
  self.form = $('.generateFeed');
136
  if( ! self.form.length ) return;
137
- // noinspection ES6ConvertVarToLetConst
138
- var outOfStockVisibilityRow = $('.out-of-stock-visibility');
139
  // Initialize Table Sorting
140
  // noinspection JSUnresolvedFunction
141
  helper.sortable();
@@ -150,8 +147,7 @@
150
  })
151
  .on('change', '.attr_type', function () {
152
  // Attribute type selection
153
- // noinspection ES6ConvertVarToLetConst
154
- var type = $(this).val(), row = $(this).closest('tr');
155
  if (type === 'pattern') {
156
  row.find('.wf_attr').hide();
157
  row.find('.wf_attr').val('');
@@ -163,29 +159,25 @@
163
  }
164
  })
165
  .on('change', '.wf_mattributes, .attr_type', function () {
166
- // noinspection ES6ConvertVarToLetConst
167
- var row = $(this).closest('tr'),
168
  attribute = row.find('.wf_mattributes'),
169
  type = row.find('.attr_type'),
170
  valueColumn = row.find('td:eq(4)'),
171
  provider = $('#provider').val();
172
  if (attribute.val() === 'current_category' && type.val() === 'pattern' && helper.in_array(provider, ['google', 'facebook', 'pinterest'])) {
173
  if (valueColumn.find('select.selectize').length === 0) {
174
- // noinspection ES6ConvertVarToLetConst
175
- var selectizeOpts = {
176
  options: googleCategories,
177
  config: {render: {item: helper.selectize_render_item,}},
178
  };
179
  valueColumn.find('input.wf_default').remove();
180
  valueColumn.append('<span class="wf_default wf_attributes"><select name="default[]" class="selectize"></select></span>');
181
  // valueColumn.find('.wf_attributes select').selectize({render: {item: helper.selectize_render_item,}});
182
- // noinspection JSUnresolvedVariable
183
  valueColumn.append('<span style="font-size:x-small;"><a style="color: red" href="http://webappick.helpscoutdocs.com/article/19-how-to-map-store-category-with-merchant-category" target="_blank">' + opts.learn_more + '</a></span>');
184
  if( ! googleCategories ) {
185
  valueColumn.append('<span class="spinner is-active" style="margin: 0;"></span>');
186
  }
187
- // noinspection ES6ConvertVarToLetConst
188
- var select = valueColumn.find('.wf_attributes select');
189
  helper.selectize( select, {
190
  preload: true,
191
  placeholder: opts.form.select_category,
@@ -230,20 +222,16 @@
230
  * @param {Object} r ajax response object
231
  */
232
  renderMerchantInfo: function( merchantInfo, feedType, r ) {
233
- // noinspection ES6ConvertVarToLetConst
234
- for( var k in r ) {
235
  if( r.hasOwnProperty( k ) ) {
236
  merchantInfo.find( '.merchant-info-section.' + k + ' .data' ).html( r[k] ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
237
  if( 'feed_file_type' === k ) {
238
- // noinspection ES6ConvertVarToLetConst,JSUnresolvedVariable
239
- var types = r[k].split(",").map(function(t){return t.trim().toLowerCase()}).filter(function(t){
240
- // noinspection JSUnresolvedVariable
241
  return t !== '' && t !== opts.na.toLowerCase()
242
  });
243
  if( types.length ) {
244
  feedType.find('option').removeAttr('selected').each( function(){
245
- // noinspection ES6ConvertVarToLetConst
246
- var opt = $(this);
247
  opt.val() && ! helper.in_array(opt.val(),types) ? opt.disabled( ! 0) : opt.disabled( ! 1);
248
  } );
249
  if( types.length === 1 ) feedType.find('option[value="' + types[0] + '"]').attr( 'selected', 'selected' );
@@ -262,18 +250,15 @@
262
  * @param {object} r merchant template ajax response object
263
  */
264
  renderMerchantTemplate: function( feedForm, r ) {
265
- // noinspection ES6ConvertVarToLetConst
266
- for ( var k in r ) {
267
  if ( r.hasOwnProperty( k ) ) {
268
  if ( 'tabs' === k ) {
269
  feedForm.html( r[k]); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
270
  } else {
271
- // noinspection ES6ConvertVarToLetConst
272
- var contentSettings = $('[name="'+k+'"]');
273
  if ( contentSettings.length ) {
274
  contentSettings.each( function() {
275
- // noinspection ES6ConvertVarToLetConst
276
- var elem = $(this);
277
  if ( elem.is( 'select' ) ) {
278
  elem.find( '[value="'+r[k]+'"]').prop( 'selected', true );
279
  } else if ( ( elem.is('[type=checkbox]') || elem.is('[type=radio]') ) && elem.val() === r[k] ) {
@@ -331,44 +316,43 @@
331
 
332
  // XML Feed Wrapper
333
  $('#feedType,#provider').on('change', function () {
334
- // noinspection ES6ConvertVarToLetConst,
335
- var type = $('#feedType').val(), provider = $('#provider').val(), itemWrapper = $('.itemWrapper'), wf_csv_txt = $('.wf_csvtxt');
336
- // noinspection JSUnresolvedVariable
337
- if ( type === 'xml' ) {
 
 
 
 
 
338
  itemWrapper.show();
339
  wf_csv_txt.hide();
340
  } else if ( type === 'csv' || type === 'txt' ) {
341
  itemWrapper.hide();
342
  wf_csv_txt.show();
343
- } else if ( type === '' ) {
344
  itemWrapper.hide();
345
  wf_csv_txt.hide();
346
  }
347
- if( type !== '' && helper.in_array( provider, ['google', 'facebook', 'pinterest'] ) ) {
348
- itemWrapper.hide();
349
- }
350
  }).trigger( 'change' );
 
351
  // Tooltip only Text
352
- {
353
- $('.wfmasterTooltip').hover(function () {
354
- // Hover over code
355
- // noinspection ES6ConvertVarToLetConst
356
- var title = $(this).attr('wftitle');
357
- $(this).data('tipText', title).removeAttr('wftitle');
358
- $('<p class="wftooltip"></p>').text(title).appendTo('body').fadeIn('slow');
359
- }, function () {
360
- // Hover out code
361
- $(this).attr('wftitle', $(this).data('tipText'));
362
- $('.wftooltip').remove();
363
- }).mousemove(function (e) {
364
- $('.wftooltip').css({top: e.pageY + 10, left: e.pageX + 20})
365
- });
366
- }
367
 
368
  // Attribute type selection for dynamic attribute
369
  $(document).on('change', '.dType', function () {
370
- // noinspection ES6ConvertVarToLetConst
371
- var type = $(this).val(), row = $(this).closest('tr');
372
  if (type === 'pattern') {
373
  row.find('.value_attribute').hide();
374
  row.find('.value_pattern').show();
@@ -416,13 +400,11 @@
416
  $("#provider").on('change', function ( event ) {
417
  event.preventDefault();
418
  if( ! $(this).closest('.generateFeed').hasClass('add-new') ) return; // only for new feed.
419
- // noinspection ES6ConvertVarToLetConst
420
- var merchant = $(this).val(),
421
  feedType = $("#feedType"),
422
  feedForm = $("#providerPage"),
423
  merchantInfo = $('#feed_merchant_info');
424
  // set loading..
425
- // noinspection JSUnresolvedVariable
426
  feedForm.html('<h3><span style="float:none;margin: -3px 0 0;" class="spinner is-active"></span> ' + opts.form.loading_tmpl + '</h3>'); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html, WordPressVIPMinimum.JS.StringConcat.Found
427
  merchantInfo.find( '.spinner' ).addClass( 'is-active' );
428
  feedType.disabled( ! 0 ); // disable dropdown
@@ -457,8 +439,7 @@
457
 
458
  // Feed Active and Inactive status change via ajax
459
  $('.woo_feed_status_input').on('change',function(){
460
- // noinspection ES6ConvertVarToLetConst
461
- var $feedName = $(this).val(), counter = ( $(this)[0].checked ) ? 1 : 0;
462
  wpAjax.post( 'update_feed_status', { _ajax_nonce: opts.nonce, feedName: $feedName, status: counter }, );
463
  });
464
 
@@ -472,22 +453,17 @@
472
 
473
  //Checking whether php ssh2 extension is added or not
474
  $(document).on('change', '.ftporsftp', function () {
475
- // noinspection ES6ConvertVarToLetConst
476
- var server = $(this).val(), status = $('.ssh2_status');
477
  if (server === 'sftp') {
478
- // noinspection JSUnresolvedVariable
479
  status.show().css('color', 'dodgerblue').text(opts.form.sftp_checking);
480
- // noinspection JSUnresolvedVariable
481
  wpAjax.post('get_ssh2_status', {_ajax_nonce: opts.nonce, server: server})
482
  .then(function (response) {
483
  if ( response === 'exists' ) {
484
- // noinspection JSUnresolvedVariable
485
  status.css('color', '#2CC185').text(opts.form.sftp_available);
486
  setTimeout( function () {
487
  status.hide();
488
  }, 1500 );
489
  } else {
490
- // noinspection JSUnresolvedVariable
491
  status.show().css('color', 'red').text(opts.form.sftp_warning);
492
  }
493
  })
29
  */
30
  $.fn.disabled = function( status ) {
31
  $(this).each( function(){
32
+ let self = $(this), prop = 'disabled';
 
33
  if( typeof( self.prop( prop ) ) !== 'undefined' ) {
34
  self.prop( prop, status === void 0 || status === true );
35
  } else {
42
  * Check if a HTMLElement or jQuery is disabled
43
  */
44
  $.fn.isDisabled = function() {
45
+ let self = $(this), prop = 'disabled';
 
46
  return ( typeof( self.prop( prop ) ) !== 'undefined' ) ? self.prop( prop ) : self.hasClass( prop );
47
  };
48
 
61
  }
62
 
63
  function fallbackMessage(action) {
64
+ let actionMsg, actionKey = (action === 'cut' ? 'X' : 'C');
 
65
  if (/iPhone|iPad/i.test(navigator.userAgent)) {
66
  actionMsg = 'No support :(';
67
  } else if (/Mac/i.test(navigator.userAgent)) {
79
  * @param {Object} _args
80
  */
81
  const extend = ( _default, _args ) => $.extend( true, {}, _default, _args );
82
+ let $copyBtn, clipboard, googleCategories,
 
83
  helper = {
84
  in_array: function( needle, haystack ) {
85
  try {
96
  alert( ( e.hasOwnProperty( 'statusText' ) && e.hasOwnProperty( 'status' ) ) ? opts.ajax.error + '\n' + e.statusText + ' (' + e.status + ')' : e );
97
  },
98
  sortable: function( el, config ) {
99
+ return (el || $('.sorted_table')).each(function () {
100
+ let self = $(this), column = self.find('tbody > tr:eq(0) > td').length;
101
+ self.wf_sortable(extend({
102
+ containerSelector: 'table',
103
+ itemPath: '> tbody',
104
+ itemSelector: 'tr',
105
+ handle: 'i.wf_sortedtable',
106
+ placeholder: `<tr class="placeholder"><td colspan="${column}"></td></tr>`,
107
+ }, config));
108
+ });
109
  },
110
  selectize: function( el, config ) {
111
+ return (el || $('select.selectize')).not('.selectized').each(function () {
112
  let self = $(this);
113
+ self.selectize(extend({
114
  create: self.data('create') || false,
115
+ plugins: self.data('plugins') ? self.data('plugins').split(',').map(s => s.trim()) : [],//['remove_button'],
116
  render: {item: helper.selectize_render_item,}
117
+ }, config));
118
+ });
119
  }
120
  }, // helper functions
121
  feedEditor = {
132
  let self = this;
133
  self.form = $('.generateFeed');
134
  if( ! self.form.length ) return;
135
+ let outOfStockVisibilityRow = $('.out-of-stock-visibility');
 
136
  // Initialize Table Sorting
137
  // noinspection JSUnresolvedFunction
138
  helper.sortable();
147
  })
148
  .on('change', '.attr_type', function () {
149
  // Attribute type selection
150
+ let type = $(this).val(), row = $(this).closest('tr');
 
151
  if (type === 'pattern') {
152
  row.find('.wf_attr').hide();
153
  row.find('.wf_attr').val('');
159
  }
160
  })
161
  .on('change', '.wf_mattributes, .attr_type', function () {
162
+ let row = $(this).closest('tr'),
 
163
  attribute = row.find('.wf_mattributes'),
164
  type = row.find('.attr_type'),
165
  valueColumn = row.find('td:eq(4)'),
166
  provider = $('#provider').val();
167
  if (attribute.val() === 'current_category' && type.val() === 'pattern' && helper.in_array(provider, ['google', 'facebook', 'pinterest'])) {
168
  if (valueColumn.find('select.selectize').length === 0) {
169
+ let selectizeOpts = {
 
170
  options: googleCategories,
171
  config: {render: {item: helper.selectize_render_item,}},
172
  };
173
  valueColumn.find('input.wf_default').remove();
174
  valueColumn.append('<span class="wf_default wf_attributes"><select name="default[]" class="selectize"></select></span>');
175
  // valueColumn.find('.wf_attributes select').selectize({render: {item: helper.selectize_render_item,}});
 
176
  valueColumn.append('<span style="font-size:x-small;"><a style="color: red" href="http://webappick.helpscoutdocs.com/article/19-how-to-map-store-category-with-merchant-category" target="_blank">' + opts.learn_more + '</a></span>');
177
  if( ! googleCategories ) {
178
  valueColumn.append('<span class="spinner is-active" style="margin: 0;"></span>');
179
  }
180
+ const select = valueColumn.find('.wf_attributes select');
 
181
  helper.selectize( select, {
182
  preload: true,
183
  placeholder: opts.form.select_category,
222
  * @param {Object} r ajax response object
223
  */
224
  renderMerchantInfo: function( merchantInfo, feedType, r ) {
225
+ for( let k in r ) {
 
226
  if( r.hasOwnProperty( k ) ) {
227
  merchantInfo.find( '.merchant-info-section.' + k + ' .data' ).html( r[k] ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
228
  if( 'feed_file_type' === k ) {
229
+ let types = r[k].split(",").map(function(t){return t.trim().toLowerCase()}).filter(function(t){
 
 
230
  return t !== '' && t !== opts.na.toLowerCase()
231
  });
232
  if( types.length ) {
233
  feedType.find('option').removeAttr('selected').each( function(){
234
+ let opt = $(this);
 
235
  opt.val() && ! helper.in_array(opt.val(),types) ? opt.disabled( ! 0) : opt.disabled( ! 1);
236
  } );
237
  if( types.length === 1 ) feedType.find('option[value="' + types[0] + '"]').attr( 'selected', 'selected' );
250
  * @param {object} r merchant template ajax response object
251
  */
252
  renderMerchantTemplate: function( feedForm, r ) {
253
+ for ( let k in r ) {
 
254
  if ( r.hasOwnProperty( k ) ) {
255
  if ( 'tabs' === k ) {
256
  feedForm.html( r[k]); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
257
  } else {
258
+ let contentSettings = $('[name="'+k+'"]');
 
259
  if ( contentSettings.length ) {
260
  contentSettings.each( function() {
261
+ let elem = $(this);
 
262
  if ( elem.is( 'select' ) ) {
263
  elem.find( '[value="'+r[k]+'"]').prop( 'selected', true );
264
  } else if ( ( elem.is('[type=checkbox]') || elem.is('[type=radio]') ) && elem.val() === r[k] ) {
316
 
317
  // XML Feed Wrapper
318
  $('#feedType,#provider').on('change', function () {
319
+ let type = $('#feedType').val(), provider = $('#provider').val(), itemWrapper = $('.itemWrapper'), wf_csv_txt = $('.wf_csvtxt');
320
+ const hidden = [
321
+ 'google', 'facebook', 'pinterest', 'fruugo.au', 'stylight.com', 'nextad', 'skinflint.co.uk',
322
+ 'comparer.be', 'dooyoo', 'hintaseuranta.fi', 'incurvy', 'kijiji.ca', 'marktplaats.nl',
323
+ 'rakuten.de', 'shopalike.fr', 'spartoo.fi', 'webmarchand',
324
+ ];
325
+ if (type !== '' && helper.in_array(provider, hidden)) {
326
+ itemWrapper.hide();
327
+ } else if ( type === 'xml' ) {
328
  itemWrapper.show();
329
  wf_csv_txt.hide();
330
  } else if ( type === 'csv' || type === 'txt' ) {
331
  itemWrapper.hide();
332
  wf_csv_txt.show();
333
+ } else {
334
  itemWrapper.hide();
335
  wf_csv_txt.hide();
336
  }
337
+
 
 
338
  }).trigger( 'change' );
339
+
340
  // Tooltip only Text
341
+ $('.wfmasterTooltip').hover(function () {
342
+ // Hover over code
343
+ let title = $(this).attr('wftitle');
344
+ $(this).data('tipText', title).removeAttr('wftitle');
345
+ $('<p class="wftooltip"></p>').text(title).appendTo('body').fadeIn('slow');
346
+ }, function () { // Hover out code
347
+ $(this).attr('wftitle', $(this).data('tipText'));
348
+ $('.wftooltip').remove();
349
+ }).mousemove(function (e) {
350
+ $('.wftooltip').css({top: e.pageY + 10, left: e.pageX + 20})
351
+ });
 
 
 
 
352
 
353
  // Attribute type selection for dynamic attribute
354
  $(document).on('change', '.dType', function () {
355
+ let type = $(this).val(), row = $(this).closest('tr');
 
356
  if (type === 'pattern') {
357
  row.find('.value_attribute').hide();
358
  row.find('.value_pattern').show();
400
  $("#provider").on('change', function ( event ) {
401
  event.preventDefault();
402
  if( ! $(this).closest('.generateFeed').hasClass('add-new') ) return; // only for new feed.
403
+ let merchant = $(this).val(),
 
404
  feedType = $("#feedType"),
405
  feedForm = $("#providerPage"),
406
  merchantInfo = $('#feed_merchant_info');
407
  // set loading..
 
408
  feedForm.html('<h3><span style="float:none;margin: -3px 0 0;" class="spinner is-active"></span> ' + opts.form.loading_tmpl + '</h3>'); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html, WordPressVIPMinimum.JS.StringConcat.Found
409
  merchantInfo.find( '.spinner' ).addClass( 'is-active' );
410
  feedType.disabled( ! 0 ); // disable dropdown
439
 
440
  // Feed Active and Inactive status change via ajax
441
  $('.woo_feed_status_input').on('change',function(){
442
+ let $feedName = $(this).val(), counter = ( $(this)[0].checked ) ? 1 : 0;
 
443
  wpAjax.post( 'update_feed_status', { _ajax_nonce: opts.nonce, feedName: $feedName, status: counter }, );
444
  });
445
 
453
 
454
  //Checking whether php ssh2 extension is added or not
455
  $(document).on('change', '.ftporsftp', function () {
456
+ let server = $(this).val(), status = $('.ssh2_status');
 
457
  if (server === 'sftp') {
 
458
  status.show().css('color', 'dodgerblue').text(opts.form.sftp_checking);
 
459
  wpAjax.post('get_ssh2_status', {_ajax_nonce: opts.nonce, server: server})
460
  .then(function (response) {
461
  if ( response === 'exists' ) {
 
462
  status.css('color', '#2CC185').text(opts.form.sftp_available);
463
  setTimeout( function () {
464
  status.hide();
465
  }, 1500 );
466
  } else {
 
467
  status.show().css('color', 'red').text(opts.form.sftp_warning);
468
  }
469
  })
admin/js/woo-feed-admin.min.js CHANGED
@@ -5,4 +5,4 @@
5
  * @copyright 2020 WebAppick
6
  *
7
  */
8
- !function(r,e,t,s,l){"use strict";function n(e){r(e.currentTarget).removeClass(function(e,t){return(t.match(/\btooltipped-\S+/g)||[]).join(" ")}).removeClass("tooltipped").removeAttr("aria-label")}function a(e,t){r(e).addClass("tooltipped tooltipped-s").attr("aria-label",t)}r.fn.disabled=function(n){return r(this).each(function(){var e=r(this),t="disabled";void 0!==e.prop(t)?e.prop(t,void 0===n||!0===n):!0===n?e.addClass(t):e.removeClass(t)}),self},r.fn.isDisabled=function(){var e=r(this),t="disabled";return void 0!==e.prop(t)?e.prop(t):e.hasClass(t)};function i(e,t){return r.extend(!0,{},e,t)}var o,c,d={in_array:function(e,t){try{return-1!==t.indexOf(e)}catch(e){return!1}},selectize_render_item:function(e,t){return'<div class="item wapk-selectize-item">'+t(e.text)+"</div>"},ajax_fail:function(e){console.warn(e),alert(e.hasOwnProperty("statusText")&&e.hasOwnProperty("status")?l.ajax.error+"\n"+e.statusText+" ("+e.status+")":e)},sortable:function(e,t){console.log(e||r(".sorted_table")),(e||r(".sorted_table")).wf_sortable(i({containerSelector:"table",itemPath:"> tbody",itemSelector:"tr",handle:"i.wf_sortedtable",placeholder:'<tr class="placeholder"><td colspan="9"></td></tr>'},t))},selectize:function(e,t){return(e||r("select.selectize")).not(".selectized").each(function(){var e=r(this);e.selectize(i({create:e.data("create")||!1,plugins:e.data("plugins")?e.data("plugins").split(",").map(function(e){return e.trim()}):[],render:{item:d.selectize_render_item}},t))})}},f={form:null,init:function(){if(this.form=r(".generateFeed"),this.form.length){var e=r(".out-of-stock-visibility");d.sortable(),d.selectize(),r(t).on("change",'[name="is_outOfStock"], [name="product_visibility"]',function(){"n"===r('[name="is_outOfStock"]:checked').val()&&"1"===r('[name="product_visibility"]:checked').val()?e.show():e.hide()}).on("change",".attr_type",function(){var e=r(this).val(),t=r(this).closest("tr");"pattern"===e?(t.find(".wf_attr").hide(),t.find(".wf_attr").val(""),t.find(".wf_default").show()):(t.find(".wf_attr").show(),t.find(".wf_default").hide(),t.find(".wf_default").val(""))}).on("change",".wf_mattributes, .attr_type",function(){var e=r(this).closest("tr"),t=e.find(".wf_mattributes"),n=e.find(".attr_type"),a=e.find("td:eq(4)"),i=r("#provider").val();if("current_category"===t.val()&&"pattern"===n.val()&&d.in_array(i,["google","facebook","pinterest"])){if(0===a.find("select.selectize").length){d.selectize_render_item;a.find("input.wf_default").remove(),a.append('<span class="wf_default wf_attributes"><select name="default[]" class="selectize"></select></span>'),a.append('<span style="font-size:x-small;"><a style="color: red" href="http://webappick.helpscoutdocs.com/article/19-how-to-map-store-category-with-merchant-category" target="_blank">'+l.learn_more+"</a></span>"),c||a.append('<span class="spinner is-active" style="margin: 0;"></span>');var o=a.find(".wf_attributes select");d.selectize(o,{preload:!0,placeholder:l.form.select_category,load:function(e,t){c?t(c):s.send("get_google_categories",{type:"GET",data:{_ajax_nonce:l.nonce,action:"get_google_categories",provider:i}}).then(function(e){t(c=e),a.find(".spinner").remove()}).fail(d.ajax_fail)}})}}else"current_category"!==t.val()&&0===a.find("input.wf_default").length&&(a.find("span").remove(),a.append('<input autocomplete="off" class="wf_default wf_attributes" type="text" name="default[]" value="">'),"pattern"!==n.val()&&a.find("input.wf_default").hide())}).trigger("change"),r(".outputType").fancySelect(),r(t).trigger(new jQuery.Event("feedEditor.init",{target:this.form}))}},renderMerchantInfo:function(e,t,n){for(var a in n)if(n.hasOwnProperty(a)&&(e.find(".merchant-info-section."+a+" .data").html(n[a]),"feed_file_type"===a)){var i=n[a].split(",").map(function(e){return e.trim().toLowerCase()}).filter(function(e){return""!==e&&e!==l.na.toLowerCase()});i.length?(t.find("option").removeAttr("selected").each(function(){var e=r(this);e.val()&&!d.in_array(e.val(),i)?e.disabled(!0):e.disabled(!1)}),1===i.length&&t.find('option[value="'+i[0]+'"]').attr("selected","selected")):t.find("option").disabled(!1)}e.find(".spinner").removeClass("is-active"),t.disabled(!1),t.trigger("change"),t.parent().find(".spinner").removeClass("is-active")},renderMerchantTemplate:function(e,t){for(var n in t)if(t.hasOwnProperty(n))if("tabs"===n)e.html(t[n]);else{var a=r('[name="'+n+'"]');a.length&&a.each(function(){var e=r(this);e.is("select")?e.find('[value="'+t[n]+'"]').prop("selected",!0):(e.is("[type=checkbox]")||e.is("[type=radio]"))&&e.val()===t[n]?e.prop("checked",!0):e.val(t[n])}).trigger("change")}f.init()}},p=[],u=[];e.wf={helper:d,feedEditor:f},r(e).load(function(){o=r(".toClipboard"),null!=r(location).attr("href").match(/webappick.*feed/g)&&r("#wpbody-content").addClass("woofeed-body-content"),r("[data-toggle_slide]").on("click",function(e){e.preventDefault(),r(r(this).data("toggle_slide")).slideToggle("fast")}),postboxes.add_postbox_toggles(pagenow),!ClipboardJS.isSupported()||/iPhone|iPad/i.test(navigator.userAgent)?o.find("img").hide(0):(o.each(function(){r(this).on("mouseleave",n).on("blur",n)}),new ClipboardJS(".toClipboard").on("error",function(e){var t,n;a(e.trigger,(t=e.action,n="cut"===t?"X":"C",/iPhone|iPad/i.test(navigator.userAgent)?"No support :(":/Mac/i.test(navigator.userAgent)?"Press ⌘-"+n+" to "+t:"Press Ctrl-"+n+" to "+t))}).on("success",function(e){a(e.trigger,"Copied!")})),f.init(),d.selectize(),r(t).on("click","#wf_newRow",function(){r("#table-1 tbody tr:first").clone().find("input").val("").end().find("select:not('.wfnoempty')").val("").end().insertAfter("#table-1 tbody tr:last"),r(".outputType").each(function(e){r(this).attr("name","output_type["+e+"][]")})}),r("#feedType,#provider").on("change",function(){var e=r("#feedType").val(),t=r("#provider").val(),n=r(".itemWrapper"),a=r(".wf_csvtxt");"xml"===e?(n.show(),a.hide()):"csv"===e||"txt"===e?(n.hide(),a.show()):""===e&&(n.hide(),a.hide()),""!==e&&d.in_array(t,["google","facebook","pinterest"])&&n.hide()}).trigger("change"),r(".wfmasterTooltip").hover(function(){var e=r(this).attr("wftitle");r(this).data("tipText",e).removeAttr("wftitle"),r('<p class="wftooltip"></p>').text(e).appendTo("body").fadeIn("slow")},function(){r(this).attr("wftitle",r(this).data("tipText")),r(".wftooltip").remove()}).mousemove(function(e){r(".wftooltip").css({top:e.pageY+10,left:e.pageX+20})}),r(t).on("change",".dType",function(){var e=r(this).val(),t=r(this).closest("tr");"pattern"===e?(t.find(".value_attribute").hide(),t.find(".value_pattern").show()):"attribute"===e?(t.find(".value_attribute").show(),t.find(".value_pattern").hide()):"remove"===e&&(t.find(".value_attribute").hide(),t.find(".value_pattern").hide())}),r(t).on("click",".delRow",function(e){e.preventDefault(),r(this).closest("tr").remove()}),r(".generateFeed").validate(),r(t).on("submit","#generateFeed",function(){r(this).validate(),r(this).valid()&&r(".makeFeedResponse").show().html('<b style="color: darkblue;"><i class="dashicons dashicons-sos wpf_spin"></i> '+l.form.generate+"</b>")}),r(".updatefeed").validate(),r('[name="save_feed_config"]').on("click",function(e){e.preventDefault(),r("#updatefeed").trigger("submit",{save:!0})}),r(t).on("submit","#updatefeed",function(e,t){r(this).validate(),r(this).valid()&&r(".makeFeedResponse").show().html('<b style="color: darkblue;"><i class="dashicons dashicons-sos wpf_spin"></i> '+(t&&t.save?l.form.save:l.form.generate)+"</b>")}),r("#provider").on("change",function(e){if(e.preventDefault(),r(this).closest(".generateFeed").hasClass("add-new")){var t=r(this).val(),n=r("#feedType"),a=r("#providerPage"),i=r("#feed_merchant_info");a.html('<h3><span style="float:none;margin: -3px 0 0;" class="spinner is-active"></span> '+l.form.loading_tmpl+"</h3>"),i.find(".spinner").addClass("is-active"),n.disabled(!0),n.parent().find(".spinner").addClass("is-active"),i.find(".merchant-info-section .data").html(""),p.hasOwnProperty(t)?f.renderMerchantInfo(i,n,p[t]):s.send("woo_feed_get_merchant_info",{type:"GET",data:{nonce:l.nonce,provider:t}}).then(function(e){p[t]=e,f.renderMerchantInfo(i,n,e)}).fail(d.ajax_fail),u.hasOwnProperty(t)?f.renderMerchantTemplate(a,u[t]):s.post("get_feed_merchant",{_ajax_nonce:l.nonce,merchant:t}).then(function(e){u[t]=e,f.renderMerchantTemplate(a,e)}).fail(d.ajax_fail)}}),r(".woo_feed_status_input").on("change",function(){var e=r(this).val(),t=r(this)[0].checked?1:0;s.post("update_feed_status",{_ajax_nonce:l.nonce,feedName:e,status:t})}),r("#woo_feed_settings_error_copy_clipboard_button").on("click",function(){r("#woo_feed_settings_error_report").select(),t.execCommand("copy"),e.getSelection?e.getSelection().removeAllRanges():t.selection&&t.selection.empty()}),r(t).on("change",".ftporsftp",function(){var e=r(this).val(),t=r(".ssh2_status");"sftp"===e?(t.show().css("color","dodgerblue").text(l.form.sftp_checking),s.post("get_ssh2_status",{_ajax_nonce:l.nonce,server:e}).then(function(e){"exists"===e?(t.css("color","#2CC185").text(l.form.sftp_available),setTimeout(function(){t.hide()},1500)):t.show().css("color","red").text(l.form.sftp_warning)}).fail(function(e){t.hide(),d.ajax_fail(e)})):t.hide()})})}(jQuery,window,document,wp.ajax,wpf_ajax_obj);
5
  * @copyright 2020 WebAppick
6
  *
7
  */
8
+ !function(r,e,t,s,l){"use strict";function n(e){r(e.currentTarget).removeClass(function(e,t){return(t.match(/\btooltipped-\S+/g)||[]).join(" ")}).removeClass("tooltipped").removeAttr("aria-label")}function a(e,t){r(e).addClass("tooltipped tooltipped-s").attr("aria-label",t)}r.fn.disabled=function(n){return r(this).each(function(){var e=r(this),t="disabled";void 0!==e.prop(t)?e.prop(t,void 0===n||!0===n):!0===n?e.addClass(t):e.removeClass(t)}),self},r.fn.isDisabled=function(){var e=r(this),t="disabled";return void 0!==e.prop(t)?e.prop(t):e.hasClass(t)};function i(e,t){return r.extend(!0,{},e,t)}var o,c,d={in_array:function(e,t){try{return-1!==t.indexOf(e)}catch(e){return!1}},selectize_render_item:function(e,t){return'<div class="item wapk-selectize-item">'+t(e.text)+"</div>"},ajax_fail:function(e){console.warn(e),alert(e.hasOwnProperty("statusText")&&e.hasOwnProperty("status")?l.ajax.error+"\n"+e.statusText+" ("+e.status+")":e)},sortable:function(e,n){return(e||r(".sorted_table")).each(function(){var e=r(this),t=e.find("tbody > tr:eq(0) > td").length;e.wf_sortable(i({containerSelector:"table",itemPath:"> tbody",itemSelector:"tr",handle:"i.wf_sortedtable",placeholder:'<tr class="placeholder"><td colspan="'.concat(t,'"></td></tr>')},n))})},selectize:function(e,t){return(e||r("select.selectize")).not(".selectized").each(function(){var e=r(this);e.selectize(i({create:e.data("create")||!1,plugins:e.data("plugins")?e.data("plugins").split(",").map(function(e){return e.trim()}):[],render:{item:d.selectize_render_item}},t))})}},f={form:null,init:function(){if(this.form=r(".generateFeed"),this.form.length){var e=r(".out-of-stock-visibility");d.sortable(),d.selectize(),r(t).on("change",'[name="is_outOfStock"], [name="product_visibility"]',function(){"n"===r('[name="is_outOfStock"]:checked').val()&&"1"===r('[name="product_visibility"]:checked').val()?e.show():e.hide()}).on("change",".attr_type",function(){var e=r(this).val(),t=r(this).closest("tr");"pattern"===e?(t.find(".wf_attr").hide(),t.find(".wf_attr").val(""),t.find(".wf_default").show()):(t.find(".wf_attr").show(),t.find(".wf_default").hide(),t.find(".wf_default").val(""))}).on("change",".wf_mattributes, .attr_type",function(){var e=r(this).closest("tr"),t=e.find(".wf_mattributes"),n=e.find(".attr_type"),a=e.find("td:eq(4)"),i=r("#provider").val();if("current_category"===t.val()&&"pattern"===n.val()&&d.in_array(i,["google","facebook","pinterest"])){if(0===a.find("select.selectize").length){d.selectize_render_item;a.find("input.wf_default").remove(),a.append('<span class="wf_default wf_attributes"><select name="default[]" class="selectize"></select></span>'),a.append('<span style="font-size:x-small;"><a style="color: red" href="http://webappick.helpscoutdocs.com/article/19-how-to-map-store-category-with-merchant-category" target="_blank">'+l.learn_more+"</a></span>"),c||a.append('<span class="spinner is-active" style="margin: 0;"></span>');var o=a.find(".wf_attributes select");d.selectize(o,{preload:!0,placeholder:l.form.select_category,load:function(e,t){c?t(c):s.send("get_google_categories",{type:"GET",data:{_ajax_nonce:l.nonce,action:"get_google_categories",provider:i}}).then(function(e){t(c=e),a.find(".spinner").remove()}).fail(d.ajax_fail)}})}}else"current_category"!==t.val()&&0===a.find("input.wf_default").length&&(a.find("span").remove(),a.append('<input autocomplete="off" class="wf_default wf_attributes" type="text" name="default[]" value="">'),"pattern"!==n.val()&&a.find("input.wf_default").hide())}).trigger("change"),r(".outputType").fancySelect(),r(t).trigger(new jQuery.Event("feedEditor.init",{target:this.form}))}},renderMerchantInfo:function(e,n,a){for(var i in a)a.hasOwnProperty(i)&&(e.find(".merchant-info-section."+i+" .data").html(a[i]),"feed_file_type"===i&&function(){var t=a[i].split(",").map(function(e){return e.trim().toLowerCase()}).filter(function(e){return""!==e&&e!==l.na.toLowerCase()});t.length?(n.find("option").removeAttr("selected").each(function(){var e=r(this);e.val()&&!d.in_array(e.val(),t)?e.disabled(!0):e.disabled(!1)}),1===t.length&&n.find('option[value="'+t[0]+'"]').attr("selected","selected")):n.find("option").disabled(!1)}());e.find(".spinner").removeClass("is-active"),n.disabled(!1),n.trigger("change"),n.parent().find(".spinner").removeClass("is-active")},renderMerchantTemplate:function(n,a){function e(t){if(a.hasOwnProperty(t))if("tabs"===t)n.html(a[t]);else{var e=r('[name="'+t+'"]');e.length&&e.each(function(){var e=r(this);e.is("select")?e.find('[value="'+a[t]+'"]').prop("selected",!0):(e.is("[type=checkbox]")||e.is("[type=radio]"))&&e.val()===a[t]?e.prop("checked",!0):e.val(a[t])}).trigger("change")}}for(var t in a)e(t);f.init()}},p=[],u=[];e.wf={helper:d,feedEditor:f},r(e).load(function(){o=r(".toClipboard"),null!=r(location).attr("href").match(/webappick.*feed/g)&&r("#wpbody-content").addClass("woofeed-body-content"),r("[data-toggle_slide]").on("click",function(e){e.preventDefault(),r(r(this).data("toggle_slide")).slideToggle("fast")}),postboxes.add_postbox_toggles(pagenow),!ClipboardJS.isSupported()||/iPhone|iPad/i.test(navigator.userAgent)?o.find("img").hide(0):(o.each(function(){r(this).on("mouseleave",n).on("blur",n)}),new ClipboardJS(".toClipboard").on("error",function(e){var t,n;a(e.trigger,(t=e.action,n="cut"===t?"X":"C",/iPhone|iPad/i.test(navigator.userAgent)?"No support :(":/Mac/i.test(navigator.userAgent)?"Press ⌘-"+n+" to "+t:"Press Ctrl-"+n+" to "+t))}).on("success",function(e){a(e.trigger,"Copied!")})),f.init(),d.selectize(),r(t).on("click","#wf_newRow",function(){r("#table-1 tbody tr:first").clone().find("input").val("").end().find("select:not('.wfnoempty')").val("").end().insertAfter("#table-1 tbody tr:last"),r(".outputType").each(function(e){r(this).attr("name","output_type["+e+"][]")})}),r("#feedType,#provider").on("change",function(){var e=r("#feedType").val(),t=r("#provider").val(),n=r(".itemWrapper"),a=r(".wf_csvtxt");""!==e&&d.in_array(t,["google","facebook","pinterest","fruugo.au","stylight.com","nextad","skinflint.co.uk","comparer.be","dooyoo","hintaseuranta.fi","incurvy","kijiji.ca","marktplaats.nl","rakuten.de","shopalike.fr","spartoo.fi","webmarchand"])?n.hide():"xml"===e?(n.show(),a.hide()):"csv"===e||"txt"===e?(n.hide(),a.show()):(n.hide(),a.hide())}).trigger("change"),r(".wfmasterTooltip").hover(function(){var e=r(this).attr("wftitle");r(this).data("tipText",e).removeAttr("wftitle"),r('<p class="wftooltip"></p>').text(e).appendTo("body").fadeIn("slow")},function(){r(this).attr("wftitle",r(this).data("tipText")),r(".wftooltip").remove()}).mousemove(function(e){r(".wftooltip").css({top:e.pageY+10,left:e.pageX+20})}),r(t).on("change",".dType",function(){var e=r(this).val(),t=r(this).closest("tr");"pattern"===e?(t.find(".value_attribute").hide(),t.find(".value_pattern").show()):"attribute"===e?(t.find(".value_attribute").show(),t.find(".value_pattern").hide()):"remove"===e&&(t.find(".value_attribute").hide(),t.find(".value_pattern").hide())}),r(t).on("click",".delRow",function(e){e.preventDefault(),r(this).closest("tr").remove()}),r(".generateFeed").validate(),r(t).on("submit","#generateFeed",function(){r(this).validate(),r(this).valid()&&r(".makeFeedResponse").show().html('<b style="color: darkblue;"><i class="dashicons dashicons-sos wpf_spin"></i> '+l.form.generate+"</b>")}),r(".updatefeed").validate(),r('[name="save_feed_config"]').on("click",function(e){e.preventDefault(),r("#updatefeed").trigger("submit",{save:!0})}),r(t).on("submit","#updatefeed",function(e,t){r(this).validate(),r(this).valid()&&r(".makeFeedResponse").show().html('<b style="color: darkblue;"><i class="dashicons dashicons-sos wpf_spin"></i> '+(t&&t.save?l.form.save:l.form.generate)+"</b>")}),r("#provider").on("change",function(e){if(e.preventDefault(),r(this).closest(".generateFeed").hasClass("add-new")){var t=r(this).val(),n=r("#feedType"),a=r("#providerPage"),i=r("#feed_merchant_info");a.html('<h3><span style="float:none;margin: -3px 0 0;" class="spinner is-active"></span> '+l.form.loading_tmpl+"</h3>"),i.find(".spinner").addClass("is-active"),n.disabled(!0),n.parent().find(".spinner").addClass("is-active"),i.find(".merchant-info-section .data").html(""),p.hasOwnProperty(t)?f.renderMerchantInfo(i,n,p[t]):s.send("woo_feed_get_merchant_info",{type:"GET",data:{nonce:l.nonce,provider:t}}).then(function(e){p[t]=e,f.renderMerchantInfo(i,n,e)}).fail(d.ajax_fail),u.hasOwnProperty(t)?f.renderMerchantTemplate(a,u[t]):s.post("get_feed_merchant",{_ajax_nonce:l.nonce,merchant:t}).then(function(e){u[t]=e,f.renderMerchantTemplate(a,e)}).fail(d.ajax_fail)}}),r(".woo_feed_status_input").on("change",function(){var e=r(this).val(),t=r(this)[0].checked?1:0;s.post("update_feed_status",{_ajax_nonce:l.nonce,feedName:e,status:t})}),r("#woo_feed_settings_error_copy_clipboard_button").on("click",function(){r("#woo_feed_settings_error_report").select(),t.execCommand("copy"),e.getSelection?e.getSelection().removeAllRanges():t.selection&&t.selection.empty()}),r(t).on("change",".ftporsftp",function(){var e=r(this).val(),t=r(".ssh2_status");"sftp"===e?(t.show().css("color","dodgerblue").text(l.form.sftp_checking),s.post("get_ssh2_status",{_ajax_nonce:l.nonce,server:e}).then(function(e){"exists"===e?(t.css("color","#2CC185").text(l.form.sftp_available),setTimeout(function(){t.hide()},1500)):t.show().css("color","red").text(l.form.sftp_warning)}).fail(function(e){t.hide(),d.ajax_fail(e)})):t.hide()})})}(jQuery,window,document,wp.ajax,wpf_ajax_obj);
includes/classes/class-woo-feed-products-v3.php CHANGED
@@ -84,6 +84,52 @@ class Woo_Feed_Products_v3 {
84
  'subscription_period_length',
85
  'subscription_amount',
86
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  /**
88
  * Product types for query
89
  * @var array
@@ -122,6 +168,9 @@ class Woo_Feed_Products_v3 {
122
  if ( ! in_array( $this->queryType, [ 'wc', 'wp', 'both' ] ) ) {
123
  $this->queryType = 'wc';
124
  }
 
 
 
125
 
126
  // woo_feed_log_feed_process( $this->config['filename'], sprintf( 'Current Query Type is %s', $this->queryType ) );
127
  }
@@ -254,37 +303,18 @@ class Woo_Feed_Products_v3 {
254
  do_action( 'woo_feed_before_product_loop', $productIds, $this->config );
255
 
256
  foreach ( $productIds as $key => $pid ) {
257
-
258
  $product = wc_get_product( $pid );
259
 
260
- // For WP_Query check available product types
261
- if ( 'wp' == $this->queryType ) {
262
- if ( ! in_array( $product->get_type(), $this->product_types ) ) {
263
- // woo_feed_log_feed_process( $this->config['filename'], sprintf( 'Skipping Product :: Invalid Post/Product Type : %s.', $product->get_type() ) );
264
- continue;
265
- }
266
- }
267
-
268
- // Skip for invalid products
269
- if ( ! is_object( $product ) ) {
270
- // woo_feed_log_feed_process( $this->config['filename'], 'Skipping Product :: Product data is not a valid WC_Product object.' );
271
  continue;
272
  }
273
 
274
- // Skip for invisible products
275
- if ( ! $product->is_visible() ) {
276
- // woo_feed_log_feed_process( $this->config['filename'], 'Skipping Product :: Product is not visible.' );
277
  continue;
278
  }
279
-
280
- // Apply variable and variation settings
281
- if ( $product->is_type( 'variable' ) && $product->has_child() ) {
282
- $this->pi ++;
283
- $variations = $product->get_visible_children();
284
- if ( is_array( $variations ) && ( sizeof( $variations ) > 0 ) ) {
285
- $this->get_products( $variations );
286
- }
287
- }
288
 
289
  // Add Single item wrapper before product info loop start
290
  if ( 'xml' == $this->config['feedType'] ) {
@@ -293,113 +323,14 @@ class Woo_Feed_Products_v3 {
293
  $this->feedBody .= "\n";
294
  }
295
 
296
- // Unique Merchant Attributes
297
- $mAttributes = array();
298
- // Get Product Attribute values by type and assign to product array
299
- foreach ( $this->config['attributes'] as $attr_key => $attribute ) {
300
-
301
- // Continue for Google Shipping and Tax attributes
302
- $skipFor = array( 'google', 'facebook' );
303
- if (
304
- 'xml' == $this->config['feedType'] &&
305
- in_array( $this->config['mattributes'][ $attr_key ], $this->google_shipping_tax ) &&
306
- in_array( $this->config['provider'], $skipFor )
307
- ) {
308
- continue;
309
- }
310
-
311
- if ( in_array( $this->config['mattributes'][ $attr_key ], $mAttributes ) ) {
312
- continue;
313
- }
314
-
315
- if ( 'pattern' == $this->config['type'][ $attr_key ] ) {
316
- $attributeValue = $this->config['default'][ $attr_key ];
317
- } else { # Get Pattern value
318
- $attributeValue = $this->getAttributeValueByType( $product, $attribute );
319
- }
320
-
321
- // Format Output according to Output Type config.
322
- $outputType = $this->config['output_type'][ $attr_key ];
323
- if ( 'default' != $outputType ) {
324
- $attributeValue = $this->format_output( $attributeValue, $outputType, $product, $attribute );
325
- }
326
-
327
- // Limit Output
328
- $limit = $this->config['limit'][ $attr_key ];
329
- if ( ! empty( $limit ) && is_numeric( $limit ) ) {
330
- if ( strpos( $attributeValue, '<![CDATA[' ) !== false ) {
331
- $attributeValue = str_replace( array( '<![CDATA[', ']]>' ), array( '', '' ), $attributeValue );
332
- $attributeValue = substr( $attributeValue, 0, $limit );
333
- $attributeValue = '<![CDATA[' . $attributeValue . ']]>';
334
- } else {
335
- $attributeValue = substr( $attributeValue, 0, $limit );
336
- }
337
- }
338
-
339
- // Add Prefix and Suffix into Output
340
- $prefix = $this->config['prefix'][ $attr_key ];
341
- $suffix = $this->config['suffix'][ $attr_key ];
342
-
343
- if ( '' != $prefix || '' != $suffix ) {
344
- $attributeValue = $this->process_prefix_suffix( $attributeValue, $prefix, $suffix, $attribute );
345
- }
346
-
347
- $pluginAttribute = $this->config['mattributes'][ $attr_key ];
348
- $merchant = $this->config['provider'];
349
- $feedType = $this->config['feedType'];
350
- if ( 'xml' == $this->config['feedType'] ) {
351
-
352
- # Replace XML Nodes according to merchant requirement
353
- $getReplacedAttribute = woo_feed_replace_to_merchant_attribute( $pluginAttribute,
354
- $merchant,
355
- $feedType );
356
-
357
- # XML does not support space in node. So replace Space with Underscore
358
- $getReplacedAttribute = str_replace( '', '_', $getReplacedAttribute );
359
-
360
- if ( ! empty( $attributeValue ) ) {
361
- $attributeValue = trim( $attributeValue );
362
- }
363
-
364
- // Add closing XML node if value is empty
365
- if ( '' != $attributeValue ) {
366
- # Add CDATA wrapper for XML feed to prevent XML error.
367
- $attributeValue = woo_feed_add_cdata( $pluginAttribute, $attributeValue, $merchant );
368
-
369
- #TODO Move to proper place
370
- # Replace Google Color attribute value according to requirements
371
- if ( 'g:color' == $getReplacedAttribute ) {
372
- $attributeValue = str_replace( ', ', '/', $attributeValue );
373
- }
374
-
375
- # Strip slash from output
376
- $attributeValue = stripslashes( $attributeValue );
377
-
378
- $this->feedBody .= '<' . $getReplacedAttribute . '>' . "$attributeValue" . '</' . $getReplacedAttribute . '>';
379
- $this->feedBody .= "\n";
380
-
381
- } else {
382
- $this->feedBody .= '<' . $getReplacedAttribute . '/>';
383
- $this->feedBody .= "\n";
384
- }
385
- } elseif ( 'csv' == $this->config['feedType'] ) {
386
- $pluginAttribute = woo_feed_replace_to_merchant_attribute( $pluginAttribute, $merchant, $feedType );
387
- $pluginAttribute = $this->processStringForCSV( $pluginAttribute );
388
- $attributeValue = $this->processStringForCSV( $attributeValue );
389
- } elseif ( 'txt' == $this->config['feedType'] ) {
390
- $pluginAttribute = woo_feed_replace_to_merchant_attribute( $pluginAttribute, $merchant, $feedType );
391
- $pluginAttribute = $this->processStringForTXT( $pluginAttribute );
392
- $attributeValue = $this->processStringForTXT( $attributeValue );
393
- }
394
-
395
- $mAttributes[ $attr_key ] = $this->config['mattributes'][ $attr_key ];
396
- $this->products[ $this->pi ][ $pluginAttribute ] = $attributeValue;
397
- }
398
 
399
  // try {
400
  // woo_feed_log_feed_process( $this->config['filename'], 'Processing Merchant Specific Fields' );
401
  // Process feed data for uncommon merchant feed like Google,Facebook,Pinterest
402
- # Process feed data for uncommon merchant feed like Google,Facebook,Pinterest
403
  $this->process_for_merchant( $product, $this->pi );
404
  // } catch ( Exception $e ) {
405
  // $message = 'Error Processing Merchant Specific Fields.' . PHP_EOL . 'Caught Exception :: ' . $e->getMessage();
@@ -411,12 +342,10 @@ class Woo_Feed_Products_v3 {
411
  if ( empty( $this->feedHeader ) ) {
412
  $this->feedHeader = $this->process_xml_feed_header();
413
  $this->feedFooter = $this->process_xml_feed_footer();
414
-
415
  }
416
 
417
  $this->feedBody .= '</' . $this->config['itemWrapper'] . '>';
418
 
419
-
420
  } elseif ( 'txt' == $this->config['feedType'] ) {
421
  if ( empty( $this->feedHeader ) ) {
422
  $this->process_txt_feed_header();
@@ -445,6 +374,204 @@ class Woo_Feed_Products_v3 {
445
  return $this->products;
446
  }
447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
 
449
  /**
450
  * Process feed data according to merchant uncommon requirements like Google
@@ -678,8 +805,7 @@ class Woo_Feed_Products_v3 {
678
 
679
  $product = $this->products[ $this->pi ];
680
  $headers = array_keys( $product );
681
- $this->feedHeader .= $this->enclosure . implode( "$this->enclosure$this->delimiter$this->enclosure",
682
- $headers ) . $this->enclosure . $eol;
683
 
684
  return $this->feedHeader;
685
  }
@@ -697,8 +823,7 @@ class Woo_Feed_Products_v3 {
697
  if ( 'trovaprezzi' === $this->config['provider'] ) {
698
  $eol = '<endrecord>' . PHP_EOL;
699
  }
700
- $this->feedBody .= $this->enclosure . implode( "$this->enclosure$this->delimiter$this->enclosure",
701
- $productInfo ) . $this->enclosure . $eol;
702
 
703
  return $this->feedBody;
704
  }
84
  'subscription_period_length',
85
  'subscription_amount',
86
  );
87
+
88
+ /**
89
+ * Attribute to skip in attribute loop for processing separately
90
+ * @var array
91
+ */
92
+ protected $skipped_merchant_attributes = array(
93
+ 'google' => array(
94
+ 'shipping_country',
95
+ 'shipping_region',
96
+ 'shipping_service',
97
+ 'shipping_price',
98
+ 'tax_country',
99
+ 'tax_region',
100
+ 'tax_rate',
101
+ 'tax_ship',
102
+ 'installment_months',
103
+ 'installment_amount',
104
+ 'subscription_period',
105
+ 'subscription_period_length',
106
+ 'subscription_amount',
107
+ ),
108
+ 'facebook' => array(
109
+ 'shipping_country',
110
+ 'shipping_region',
111
+ 'shipping_service',
112
+ 'shipping_price',
113
+ 'tax_country',
114
+ 'tax_region',
115
+ 'tax_rate',
116
+ 'tax_ship',
117
+ 'installment_months',
118
+ 'installment_amount',
119
+ 'subscription_period',
120
+ 'subscription_period_length',
121
+ 'subscription_amount',
122
+ ),
123
+ );
124
+
125
+ /**
126
+ * Already Processed merchant attributes by the attribute loop
127
+ * this will ensure unique merchant attribute.
128
+ * @see Woo_Feed_Products_v3::exclude_current_attribute()
129
+ * @var array
130
+ */
131
+ protected $processed_merchant_attributes = array();
132
+
133
  /**
134
  * Product types for query
135
  * @var array
168
  if ( ! in_array( $this->queryType, [ 'wc', 'wp', 'both' ] ) ) {
169
  $this->queryType = 'wc';
170
  }
171
+
172
+ $this->config['itemWrapper'] = str_replace( ' ', '_', $this->config['itemWrapper'] );
173
+ $this->config['itemsWrapper'] = str_replace( ' ', '_', $this->config['itemsWrapper'] );
174
 
175
  // woo_feed_log_feed_process( $this->config['filename'], sprintf( 'Current Query Type is %s', $this->queryType ) );
176
  }
303
  do_action( 'woo_feed_before_product_loop', $productIds, $this->config );
304
 
305
  foreach ( $productIds as $key => $pid ) {
306
+ // woo_feed_log_feed_process( $this->config['filename'], sprintf( 'Loading Product Data For %d.', $pid ) );
307
  $product = wc_get_product( $pid );
308
 
309
+ if ( $this->exclude_from_loop( $product ) ) {
 
 
 
 
 
 
 
 
 
 
310
  continue;
311
  }
312
 
313
+ if ( $this->process_variation( $product ) ) {
 
 
314
  continue;
315
  }
316
+
317
+ // woo_feed_log_feed_process( $this->config['filename'], 'Formatting Feed Data...' );
 
 
 
 
 
 
 
318
 
319
  // Add Single item wrapper before product info loop start
320
  if ( 'xml' == $this->config['feedType'] ) {
323
  $this->feedBody .= "\n";
324
  }
325
 
326
+ // reset processed attribute list before loop
327
+ $this->processed_merchant_attributes = [];
328
+ // Process attribute values
329
+ $this->process_attributes( $product );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
 
331
  // try {
332
  // woo_feed_log_feed_process( $this->config['filename'], 'Processing Merchant Specific Fields' );
333
  // Process feed data for uncommon merchant feed like Google,Facebook,Pinterest
 
334
  $this->process_for_merchant( $product, $this->pi );
335
  // } catch ( Exception $e ) {
336
  // $message = 'Error Processing Merchant Specific Fields.' . PHP_EOL . 'Caught Exception :: ' . $e->getMessage();
342
  if ( empty( $this->feedHeader ) ) {
343
  $this->feedHeader = $this->process_xml_feed_header();
344
  $this->feedFooter = $this->process_xml_feed_footer();
 
345
  }
346
 
347
  $this->feedBody .= '</' . $this->config['itemWrapper'] . '>';
348
 
 
349
  } elseif ( 'txt' == $this->config['feedType'] ) {
350
  if ( empty( $this->feedHeader ) ) {
351
  $this->process_txt_feed_header();
374
  return $this->products;
375
  }
376
 
377
+ /**
378
+ * Process product variations
379
+ * @param WC_Abstract_Legacy_Product $product
380
+ *
381
+ * @return bool
382
+ * @since 3.3.9
383
+ */
384
+ protected function process_variation( $product ) {
385
+ // Apply variable and variation settings
386
+ if ( $product->is_type( 'variable' ) && $product->has_child() ) {
387
+ $this->pi ++;
388
+ $variations = $product->get_visible_children();
389
+ if ( is_array( $variations ) && ( sizeof( $variations ) > 0 ) ) {
390
+ // if( woo_feed_is_debugging_enabled() ) {
391
+ // woo_feed_log_feed_process( $this->config['filename'], sprintf( 'Getting Variation Product(s) :: %s', implode( ', ', $variations ) ) );
392
+ // }
393
+ $this->get_products( $variations );
394
+ }
395
+ }
396
+ return false;
397
+ }
398
+
399
+ /**
400
+ * Process The Attributes and assign value to merchant attribute
401
+ *
402
+ * @param WC_Abstract_Legacy_Product $product
403
+ *
404
+ * @return void
405
+ * @since 3.3.9
406
+ */
407
+ protected function process_attributes( $product ) {
408
+ // Get Product Attribute values by type and assign to product array
409
+ foreach ( $this->config['attributes'] as $attr_key => $attribute ) {
410
+
411
+ $merchant_attribute = $this->config['mattributes'][ $attr_key ];
412
+
413
+ if ( $this->exclude_current_attribute( $product, $merchant_attribute, $attribute ) ) {
414
+ continue;
415
+ }
416
+
417
+ // Add Prefix and Suffix into Output
418
+ $prefix = $this->config['prefix'][ $attr_key ];
419
+ $suffix = $this->config['suffix'][ $attr_key ];
420
+ $merchant = $this->config['provider'];
421
+ $feedType = $this->config['feedType'];
422
+
423
+ if ( 'pattern' == $this->config['type'][ $attr_key ] ) {
424
+ $attributeValue = $this->config['default'][ $attr_key ];
425
+ } else { # Get Pattern value
426
+ $attributeValue = $this->getAttributeValueByType( $product, $attribute );
427
+ }
428
+
429
+ // Format Output according to Output Type config.
430
+ $outputType = $this->config['output_type'][ $attr_key ];
431
+ $attributeValue = $this->format_output( $attributeValue, $this->config['output_type'][ $attr_key ], $product, $attribute );
432
+
433
+ // Limit Output.
434
+ $attributeValue = $this->crop_string( $attributeValue, 0, $this->config['limit'][ $attr_key ] );
435
+
436
+ // Process prefix and suffix.
437
+ $attributeValue = $this->process_prefix_suffix( $attributeValue, $prefix, $suffix, $attribute );
438
+
439
+ if ( 'xml' == $feedType ) {
440
+
441
+ // Replace XML Nodes according to merchant requirement.
442
+ $getReplacedAttribute = woo_feed_replace_to_merchant_attribute( $merchant_attribute, $merchant, $feedType );
443
+
444
+ // XML does not support space in node. So replace Space with Underscore.
445
+ $getReplacedAttribute = str_replace( ' ', '_', $getReplacedAttribute );
446
+
447
+ if ( ! empty( $attributeValue ) ) {
448
+ $attributeValue = trim( $attributeValue );
449
+ }
450
+
451
+ // Add closing XML node if value is empty
452
+ if ( '' != $attributeValue ) {
453
+ # Add CDATA wrapper for XML feed to prevent XML error.
454
+ $attributeValue = woo_feed_add_cdata( $merchant_attribute, $attributeValue, $merchant );
455
+
456
+ #TODO Move to proper place
457
+ # Replace Google Color attribute value according to requirements
458
+ if ( 'g:color' == $getReplacedAttribute ) {
459
+ $attributeValue = str_replace( ', ', '/', $attributeValue );
460
+ }
461
+
462
+ # Strip slash from output
463
+ $attributeValue = stripslashes( $attributeValue );
464
+
465
+ $this->feedBody .= '<' . $getReplacedAttribute . '>' . "$attributeValue" . '</' . $getReplacedAttribute . '>';
466
+ $this->feedBody .= "\n";
467
+
468
+ } else {
469
+ $this->feedBody .= '<' . $getReplacedAttribute . '/>';
470
+ $this->feedBody .= "\n";
471
+ }
472
+ } elseif ( 'csv' == $feedType ) {
473
+ $merchant_attribute = woo_feed_replace_to_merchant_attribute( $merchant_attribute, $merchant, $feedType );
474
+ $merchant_attribute = $this->processStringForCSV( $merchant_attribute );
475
+ $attributeValue = $this->processStringForCSV( $attributeValue );
476
+ } elseif ( 'txt' == $feedType ) {
477
+ $merchant_attribute = woo_feed_replace_to_merchant_attribute( $merchant_attribute, $merchant, $feedType );
478
+ $merchant_attribute = $this->processStringForTXT( $merchant_attribute );
479
+ $attributeValue = $this->processStringForTXT( $attributeValue );
480
+ }
481
+
482
+ $this->products[ $this->pi ][ $merchant_attribute ] = $attributeValue;
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Check if current product should be processed for feed
488
+ * This should be using by Woo_Feed_Products_v3::get_products()
489
+ *
490
+ * @param WC_Product $product
491
+ *
492
+ * @return bool
493
+ * @since 3.3.9
494
+ *
495
+ */
496
+ protected function exclude_from_loop( $product ) {
497
+ // For WP_Query check available product types
498
+ if ( 'wp' == $this->queryType && ! in_array( $product->get_type(), $this->product_types ) ) {
499
+ // woo_feed_log_feed_process( $this->config['filename'], sprintf( 'Skipping Product :: Invalid Post/Product Type : %s.', $product->get_type() ) );
500
+ return true;
501
+ }
502
+
503
+ // Skip for invalid products
504
+ if ( ! is_object( $product ) ) {
505
+ // woo_feed_log_feed_process( $this->config['filename'], 'Skipping Product :: Product data is not a valid WC_Product object.' );
506
+ return true;
507
+ }
508
+
509
+ // Skip for invisible products
510
+ if ( ! $product->is_visible() ) {
511
+ // woo_feed_log_feed_process( $this->config['filename'], 'Skipping Product :: Product is not visible.' );
512
+ return true;
513
+ }
514
+ return false;
515
+ }
516
+
517
+ /**
518
+ * Check if current attribute/merchant attribute should be processed for feed
519
+ * This should be using by Woo_Feed_Products_v3::get_products()
520
+ *
521
+ * @param WC_Product $product
522
+ * @param string $merchant_attribute
523
+ * @param string $product_attribute
524
+ * @param string $feedType
525
+ *
526
+ * @return bool
527
+ *
528
+ * @since 3.3.9
529
+ *
530
+ */
531
+ protected function exclude_current_attribute( $product, $merchant_attribute, $product_attribute, $feedType = 'xml' ) {
532
+ if (
533
+ $feedType == $this->config['feedType'] &&
534
+ in_array( $this->config['provider'], array_keys( $this->skipped_merchant_attributes ) ) &&
535
+ in_array( $merchant_attribute, $this->skipped_merchant_attributes[ $this->config['provider'] ] )
536
+
537
+ ) {
538
+ return true;
539
+ }
540
+
541
+ if ( in_array( $merchant_attribute, $this->processed_merchant_attributes ) ) {
542
+ return true;
543
+ }
544
+
545
+ $this->processed_merchant_attributes[] = $merchant_attribute;
546
+
547
+ return false;
548
+ }
549
+
550
+ /**
551
+ * Wrapper for substr with <![CDATA[string]]> support
552
+ *
553
+ * @see substr
554
+ *
555
+ * @param string $string
556
+ * @param int $start
557
+ * @param int $limit
558
+ *
559
+ * @return string
560
+ */
561
+ protected function crop_string( $string, $start = 0, $limit = null ) {
562
+ $limit = absint( $limit );
563
+ if ( $limit > 0 ) {
564
+ $start = absint( $start );
565
+ if ( strpos( $string, '<![CDATA[' ) !== false ) {
566
+ $string = str_replace( array( '<![CDATA[', ']]>' ), array( '', '' ), $string );
567
+ $string = substr( $string, $start, $limit );
568
+ $string = '<![CDATA[' . $string . ']]>';
569
+ } else {
570
+ $string = substr( $string, $start, $limit );
571
+ }
572
+ }
573
+ return $string;
574
+ }
575
 
576
  /**
577
  * Process feed data according to merchant uncommon requirements like Google
805
 
806
  $product = $this->products[ $this->pi ];
807
  $headers = array_keys( $product );
808
+ $this->feedHeader .= $this->enclosure . implode( "$this->enclosure$this->delimiter$this->enclosure", $headers ) . $this->enclosure . $eol;
 
809
 
810
  return $this->feedHeader;
811
  }
823
  if ( 'trovaprezzi' === $this->config['provider'] ) {
824
  $eol = '<endrecord>' . PHP_EOL;
825
  }
826
+ $this->feedBody .= $this->enclosure . implode( "$this->enclosure$this->delimiter$this->enclosure", $productInfo ) . $this->enclosure . $eol;
 
827
 
828
  return $this->feedBody;
829
  }
woo-feed.php CHANGED
@@ -12,7 +12,7 @@
12
  * Description: This plugin generate WooCommerce product feed for Shopping Engines
13
  * like Google Shopping, Facebook Product Feed, eBay, Amazon, Idealo and many more.
14
  *
15
- * Version: 3.3.8
16
  * Author: WebAppick
17
  * Author URI: https://webappick.com/
18
  * License: GPL v2
@@ -40,7 +40,7 @@ if ( ! defined( 'WOO_FEED_FREE_VERSION' ) ) {
40
  * @var string
41
  * @since 3.1.6
42
  */
43
- define( 'WOO_FEED_FREE_VERSION', '3.3.8' );
44
  }
45
 
46
  if ( ! defined( 'WOO_FEED_FREE_FILE' ) ) {
12
  * Description: This plugin generate WooCommerce product feed for Shopping Engines
13
  * like Google Shopping, Facebook Product Feed, eBay, Amazon, Idealo and many more.
14
  *
15
+ * Version: 3.3.9
16
  * Author: WebAppick
17
  * Author URI: https://webappick.com/
18
  * License: GPL v2
40
  * @var string
41
  * @since 3.1.6
42
  */
43
+ define( 'WOO_FEED_FREE_VERSION', '3.3.9' );
44
  }
45
 
46
  if ( ! defined( 'WOO_FEED_FREE_FILE' ) ) {