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 | 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 +5 -1
- admin/js/woo-feed-admin.js +57 -81
- admin/js/woo-feed-admin.min.js +1 -1
- includes/classes/class-woo-feed-products-v3.php +258 -133
- woo-feed.php +2 -2
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.
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
111 |
},
|
112 |
selectize: function( el, config ) {
|
113 |
-
return (
|
114 |
let self = $(this);
|
115 |
-
self.selectize(
|
116 |
create: self.data('create') || false,
|
117 |
-
plugins: self.data('plugins') ? self.data('plugins').split(',').map(
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
272 |
-
var contentSettings = $('[name="'+k+'"]');
|
273 |
if ( contentSettings.length ) {
|
274 |
contentSettings.each( function() {
|
275 |
-
|
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 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
|
|
|
|
|
|
|
|
|
|
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
|
344 |
itemWrapper.hide();
|
345 |
wf_csv_txt.hide();
|
346 |
}
|
347 |
-
|
348 |
-
itemWrapper.hide();
|
349 |
-
}
|
350 |
}).trigger( 'change' );
|
|
|
351 |
// Tooltip only Text
|
352 |
-
{
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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,
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
//
|
297 |
-
$
|
298 |
-
//
|
299 |
-
|
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.
|
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.
|
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' ) ) {
|