Enhanced Ecommerce Google Analytics Plugin for WooCommerce - Version 3.0.0

Version Description

Download this release

Release Info

Developer Tatvic
Plugin Icon 128x128 Enhanced Ecommerce Google Analytics Plugin for WooCommerce
Version 3.0.0
Comparing to
See all releases

Code changes from version 2.3.6.1 to 3.0.0

Files changed (74) hide show
  1. admin/class-enhanced-ecommerce-google-analytics-admin.php +0 -0
  2. admin/class-enhanced-ecommerce-google-analytics-settings.php +0 -0
  3. admin/css/enhanced-ecommerce-google-analytics-admin.css +0 -0
  4. admin/css/style.css +11 -0
  5. admin/images/config-success.svg +1 -0
  6. admin/images/exclaimation.png +0 -0
  7. admin/images/no-config-success.svg +1 -0
  8. admin/js/sweetalert.min.js +1 -0
  9. admin/partials/about-plugin.php +0 -0
  10. admin/partials/enhanced-ecommerce-google-analytics-admin-display.php +0 -0
  11. admin/partials/general-fields.php +0 -0
  12. admin/partials/sidebar.php +0 -0
  13. css/tvc_admin-page.css +548 -0
  14. css/tvc_admin-page.min.css +496 -0
  15. css/tvc_setting-page.css +58 -0
  16. css/tvc_setting-page.min.css +41 -0
  17. enhanced-ecommerce-google-analytics.php +0 -0
  18. google_ads_php.ini +14 -0
  19. images/ajax-loader.gif +0 -0
  20. includes/application/class-feed-master.php +676 -0
  21. includes/application/class-tvc-email.php +68 -0
  22. includes/application/class-tvc-feed-controller.php +208 -0
  23. includes/application/class-tvc-feed-processor.php +341 -0
  24. includes/application/class-tvc-feed-queries.php +243 -0
  25. includes/application/class-tvc-feed-support.php +301 -0
  26. includes/application/class-tvc-feed-value-editors.php +240 -0
  27. includes/application/class-tvc-schedules.php +147 -0
  28. includes/application/google/class-feed.php +213 -0
  29. includes/application/google/gmc.txt +23 -0
  30. includes/application/google/gmc_attrbutes.json +118 -0
  31. includes/application/google/google.txt +84 -0
  32. includes/application/google/taxonomy.en-US.txt +5583 -0
  33. includes/application/google/tvc_google-source.js +292 -0
  34. includes/application/js/tvc_channel-functions.js +707 -0
  35. includes/application/js/tvc_channel-functions.min.js +498 -0
  36. includes/application/js/tvc_feedhandling.js +144 -0
  37. includes/application/js/tvc_feedhandling.min.js +85 -0
  38. includes/application/js/tvc_general-functions.js +102 -0
  39. includes/application/js/tvc_general-functions.min.js +1 -0
  40. includes/application/js/tvc_logic.js +454 -0
  41. includes/application/js/tvc_logic.min.js +343 -0
  42. includes/application/js/tvc_object-attribute-meta.js +66 -0
  43. includes/application/js/tvc_object-attribute-meta.min.js +1 -0
  44. includes/application/js/tvc_object-feed.js +849 -0
  45. includes/application/js/tvc_object-feed.min.js +1 -0
  46. includes/application/tvc-cron-functions.php +54 -0
  47. includes/application/tvc-feed-processing-support.php +1583 -0
  48. includes/application/tvc-feed-processor-functions.php +107 -0
  49. includes/application/tvc-support-fields.php +118 -0
  50. includes/class-enhanced-ecommerce-google-analytics.php +0 -0
  51. includes/class-tvc-register-scripts.php +200 -0
  52. includes/data/class-tvc-ajax-calls.php +41 -0
  53. includes/data/class-tvc-ajax-data.php +448 -0
  54. includes/data/class-tvc-ajax-file.php +1081 -0
  55. includes/data/class-tvc-backup.php +181 -0
  56. includes/data/class-tvc-channel-ftp.php +37 -0
  57. includes/data/class-tvc-channel.php +342 -0
  58. includes/data/class-tvc-data.php +713 -0
  59. includes/data/class-tvc-db-management.php +325 -0
  60. includes/data/class-tvc-feed-crud-handler.php +88 -0
  61. includes/data/class-tvc-file.php +246 -0
  62. includes/data/class-tvc-queries.php +970 -0
  63. includes/data/class-tvc-tab.php +126 -0
  64. includes/data/class-tvc-taxonomies.php +153 -0
  65. includes/data/class-tvc-variations.php +85 -0
  66. includes/data/js/tvc_ajaxdatahandling.js +718 -0
  67. includes/data/js/tvc_ajaxdatahandling.min.js +364 -0
  68. includes/data/js/tvc_data.js +105 -0
  69. includes/data/js/tvc_data.min.js +1 -0
  70. includes/data/js/tvc_feed-queue-string.js +30 -0
  71. includes/data/js/tvc_feed-queue-string.min.js +1 -0
  72. includes/data/js/tvc_metadatahandling.js +596 -0
  73. includes/data/js/tvc_metadatahandling.min.js +1 -0
  74. includes/data/tvc-admin-functions.php +91 -0
admin/class-enhanced-ecommerce-google-analytics-admin.php CHANGED
File without changes
admin/class-enhanced-ecommerce-google-analytics-settings.php CHANGED
File without changes
admin/css/enhanced-ecommerce-google-analytics-admin.css CHANGED
File without changes
admin/css/style.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ *{
2
+ box-sizing: border-box;
3
+ margin:0px;
4
+ padding:0px;
5
+ }
6
+ body{
7
+ background-image: url('../images/plugin_bk.png') !important;
8
+ }
9
+ .swal{
10
+ background-color:#2c3e50;
11
+ }
admin/images/config-success.svg ADDED
@@ -0,0 +1 @@
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="41" height="41" viewBox="0 0 41 41"><defs><style>.a{fill:#66bb6a;}.b{fill:#fff;stroke:#fff;}</style></defs><g transform="translate(-1199 -247)"><circle class="a" cx="20.5" cy="20.5" r="20.5" transform="translate(1199 247)"/><g transform="translate(1205.572 257.288)"><g transform="translate(0 0)"><path class="b" d="M26.263,68.388a1.333,1.333,0,0,0-1.885,0L8.412,84.355,2.275,78.217A1.333,1.333,0,1,0,.39,80.1l7.08,7.08a1.333,1.333,0,0,0,1.885,0L26.263,70.273A1.333,1.333,0,0,0,26.263,68.388Z" transform="translate(0 -67.997)"/></g></g></g></svg>
admin/images/exclaimation.png ADDED
Binary file
admin/images/no-config-success.svg ADDED
@@ -0,0 +1 @@
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="31.266" height="31.266" viewBox="0 0 31.266 31.266"><defs><style>.a{fill:#25283d;stroke:#25283d;stroke-width:0.5px;}</style></defs><g transform="translate(0.25 0.25)"><g transform="translate(6.41 6.41)"><path class="a" d="M15.9,29.357H12.051a2.081,2.081,0,0,1-1.923-2.307V24.357a4.452,4.452,0,0,0-1.666-3.333A8.861,8.861,0,0,1,5,13.845,9.123,9.123,0,0,1,13.845,5a9.009,9.009,0,0,1,6.41,2.564,9.126,9.126,0,0,1,2.692,6.41A8.621,8.621,0,0,1,19.614,20.9a4.681,4.681,0,0,0-1.795,3.589v2.948A1.972,1.972,0,0,1,15.9,29.357ZM13.973,6.282a7.862,7.862,0,0,0-7.692,7.563A7.535,7.535,0,0,0,9.23,20a5.586,5.586,0,0,1,2.179,4.359v2.692c0,.256,0,1.026.641,1.026H15.9a.606.606,0,0,0,.641-.641V24.485a6.23,6.23,0,0,1,2.307-4.615,7.475,7.475,0,0,0,2.82-5.9,7.663,7.663,0,0,0-2.307-5.512,7.556,7.556,0,0,0-5.384-2.179Z" transform="translate(-5 -5)"/></g><g transform="translate(11.537 25.638)"><path class="a" d="M16.051,21.282H9.641a.641.641,0,1,1,0-1.282h6.41a.641.641,0,1,1,0,1.282Z" transform="translate(-9 -20)"/></g><g transform="translate(14.742)"><path class="a" d="M12.141,3.846A.606.606,0,0,1,11.5,3.2V.641a.641.641,0,0,1,1.282,0V3.2A.606.606,0,0,1,12.141,3.846Z" transform="translate(-11.5)"/></g><g transform="translate(23.267 4.423)"><path class="a" d="M18.855,6.463a.771.771,0,0,1-.513-.128.62.62,0,0,1,0-.9l1.795-1.795a.635.635,0,0,1,.9.9L19.24,6.334A1.291,1.291,0,0,1,18.855,6.463Z" transform="translate(-18.15 -3.45)"/></g><g transform="translate(26.92 14.742)"><path class="a" d="M24.2,12.782H21.641a.641.641,0,0,1,0-1.282H24.2a.641.641,0,1,1,0,1.282Z" transform="translate(-21 -11.5)"/></g><g transform="translate(23.267 23.395)"><path class="a" d="M20.65,21.263a.771.771,0,0,1-.513-.128L18.342,19.34a.635.635,0,0,1,.9-.9l1.795,1.795a.62.62,0,0,1,0,.9c0,.128-.128.128-.385.128Z" transform="translate(-18.15 -18.25)"/></g><g transform="translate(4.294 23.395)"><path class="a" d="M4.055,21.263a.771.771,0,0,1-.513-.128.62.62,0,0,1,0-.9l1.795-1.795a.635.635,0,1,1,.9.9L4.44,21.134a.471.471,0,0,1-.385.128Z" transform="translate(-3.35 -18.25)"/></g><g transform="translate(0 14.742)"><path class="a" d="M3.2,12.782H.641a.641.641,0,0,1,0-1.282H3.2a.641.641,0,0,1,0,1.282Z" transform="translate(0 -11.5)"/></g><g transform="translate(4.294 4.294)"><path class="a" d="M5.85,6.491a.771.771,0,0,1-.513-.128L3.542,4.44a.635.635,0,0,1,.9-.9L6.234,5.337a.62.62,0,0,1,0,.9c-.128.128-.256.256-.385.256Z" transform="translate(-3.35 -3.35)"/></g><g transform="translate(14.742 9.614)"><path class="a" d="M17.269,13.91a.606.606,0,0,1-.641-.641,4.542,4.542,0,0,0-4.487-4.487.641.641,0,0,1,0-1.282,5.745,5.745,0,0,1,5.769,5.769A.606.606,0,0,1,17.269,13.91Z" transform="translate(-11.5 -7.5)"/></g></g></svg>
admin/js/sweetalert.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.swal=e():t.swal=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=8)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o="swal-button";e.CLASS_NAMES={MODAL:"swal-modal",OVERLAY:"swal-overlay",SHOW_MODAL:"swal-overlay--show-modal",MODAL_TITLE:"swal-title",MODAL_TEXT:"swal-text",ICON:"swal-icon",ICON_CUSTOM:"swal-icon--custom",CONTENT:"swal-content",FOOTER:"swal-footer",BUTTON_CONTAINER:"swal-button-container",BUTTON:o,CONFIRM_BUTTON:o+"--confirm",CANCEL_BUTTON:o+"--cancel",DANGER_BUTTON:o+"--danger",BUTTON_LOADING:o+"--loading",BUTTON_LOADER:o+"__loader"},e.default=e.CLASS_NAMES},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.getNode=function(t){var e="."+t;return document.querySelector(e)},e.stringToNode=function(t){var e=document.createElement("div");return e.innerHTML=t.trim(),e.firstChild},e.insertAfter=function(t,e){var n=e.nextSibling;e.parentNode.insertBefore(t,n)},e.removeNode=function(t){t.parentElement.removeChild(t)},e.throwErr=function(t){throw t=t.replace(/ +(?= )/g,""),"SweetAlert: "+(t=t.trim())},e.isPlainObject=function(t){if("[object Object]"!==Object.prototype.toString.call(t))return!1;var e=Object.getPrototypeOf(t);return null===e||e===Object.prototype},e.ordinalSuffixOf=function(t){var e=t%10,n=t%100;return 1===e&&11!==n?t+"st":2===e&&12!==n?t+"nd":3===e&&13!==n?t+"rd":t+"th"}},function(t,e,n){"use strict";function o(t){for(var n in t)e.hasOwnProperty(n)||(e[n]=t[n])}Object.defineProperty(e,"__esModule",{value:!0}),o(n(25));var r=n(26);e.overlayMarkup=r.default,o(n(27)),o(n(28)),o(n(29));var i=n(0),a=i.default.MODAL_TITLE,s=i.default.MODAL_TEXT,c=i.default.ICON,l=i.default.FOOTER;e.iconMarkup='\n <div class="'+c+'"></div>',e.titleMarkup='\n <div class="'+a+'"></div>\n',e.textMarkup='\n <div class="'+s+'"></div>',e.footerMarkup='\n <div class="'+l+'"></div>\n'},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1);e.CONFIRM_KEY="confirm",e.CANCEL_KEY="cancel";var r={visible:!0,text:null,value:null,className:"",closeModal:!0},i=Object.assign({},r,{visible:!1,text:"Cancel",value:null}),a=Object.assign({},r,{text:"OK",value:!0});e.defaultButtonList={cancel:i,confirm:a};var s=function(t){switch(t){case e.CONFIRM_KEY:return a;case e.CANCEL_KEY:return i;default:var n=t.charAt(0).toUpperCase()+t.slice(1);return Object.assign({},r,{text:n,value:t})}},c=function(t,e){var n=s(t);return!0===e?Object.assign({},n,{visible:!0}):"string"==typeof e?Object.assign({},n,{visible:!0,text:e}):o.isPlainObject(e)?Object.assign({visible:!0},n,e):Object.assign({},n,{visible:!1})},l=function(t){for(var e={},n=0,o=Object.keys(t);n<o.length;n++){var r=o[n],a=t[r],s=c(r,a);e[r]=s}return e.cancel||(e.cancel=i),e},u=function(t){var n={};switch(t.length){case 1:n[e.CANCEL_KEY]=Object.assign({},i,{visible:!1});break;case 2:n[e.CANCEL_KEY]=c(e.CANCEL_KEY,t[0]),n[e.CONFIRM_KEY]=c(e.CONFIRM_KEY,t[1]);break;default:o.throwErr("Invalid number of 'buttons' in array ("+t.length+").\n If you want more than 2 buttons, you need to use an object!")}return n};e.getButtonListOpts=function(t){var n=e.defaultButtonList;return"string"==typeof t?n[e.CONFIRM_KEY]=c(e.CONFIRM_KEY,t):Array.isArray(t)?n=u(t):o.isPlainObject(t)?n=l(t):!0===t?n=u([!0,!0]):!1===t?n=u([!1,!1]):void 0===t&&(n=e.defaultButtonList),n}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r=n(2),i=n(0),a=i.default.MODAL,s=i.default.OVERLAY,c=n(30),l=n(31),u=n(32),f=n(33);e.injectElIntoModal=function(t){var e=o.getNode(a),n=o.stringToNode(t);return e.appendChild(n),n};var d=function(t){t.className=a,t.textContent=""},p=function(t,e){d(t);var n=e.className;n&&t.classList.add(n)};e.initModalContent=function(t){var e=o.getNode(a);p(e,t),c.default(t.icon),l.initTitle(t.title),l.initText(t.text),f.default(t.content),u.default(t.buttons,t.dangerMode)};var m=function(){var t=o.getNode(s),e=o.stringToNode(r.modalMarkup);t.appendChild(e)};e.default=m},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(3),r={isOpen:!1,promise:null,actions:{},timer:null},i=Object.assign({},r);e.resetState=function(){i=Object.assign({},r)},e.setActionValue=function(t){if("string"==typeof t)return a(o.CONFIRM_KEY,t);for(var e in t)a(e,t[e])};var a=function(t,e){i.actions[t]||(i.actions[t]={}),Object.assign(i.actions[t],{value:e})};e.setActionOptionsFor=function(t,e){var n=(void 0===e?{}:e).closeModal,o=void 0===n||n;Object.assign(i.actions[t],{closeModal:o})},e.default=i},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r=n(3),i=n(0),a=i.default.OVERLAY,s=i.default.SHOW_MODAL,c=i.default.BUTTON,l=i.default.BUTTON_LOADING,u=n(5);e.openModal=function(){o.getNode(a).classList.add(s),u.default.isOpen=!0};var f=function(){o.getNode(a).classList.remove(s),u.default.isOpen=!1};e.onAction=function(t){void 0===t&&(t=r.CANCEL_KEY);var e=u.default.actions[t],n=e.value;if(!1===e.closeModal){var i=c+"--"+t;o.getNode(i).classList.add(l)}else f();u.default.promise.resolve(n)},e.getState=function(){var t=Object.assign({},u.default);return delete t.promise,delete t.timer,t},e.stopLoading=function(){for(var t=document.querySelectorAll("."+c),e=0;e<t.length;e++){t[e].classList.remove(l)}}},function(t,e){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){(function(e){t.exports=e.sweetAlert=n(9)}).call(e,n(7))},function(t,e,n){(function(e){t.exports=e.swal=n(10)}).call(e,n(7))},function(t,e,n){"undefined"!=typeof window&&n(11),n(16);var o=n(23).default;t.exports=o},function(t,e,n){var o=n(12);"string"==typeof o&&(o=[[t.i,o,""]]);var r={insertAt:"top"};r.transform=void 0;n(14)(o,r);o.locals&&(t.exports=o.locals)},function(t,e,n){e=t.exports=n(13)(void 0),e.push([t.i,'.swal-icon--error{border-color:#f27474;-webkit-animation:animateErrorIcon .5s;animation:animateErrorIcon .5s}.swal-icon--error__x-mark{position:relative;display:block;-webkit-animation:animateXMark .5s;animation:animateXMark .5s}.swal-icon--error__line{position:absolute;height:5px;width:47px;background-color:#f27474;display:block;top:37px;border-radius:2px}.swal-icon--error__line--left{-webkit-transform:rotate(45deg);transform:rotate(45deg);left:17px}.swal-icon--error__line--right{-webkit-transform:rotate(-45deg);transform:rotate(-45deg);right:16px}@-webkit-keyframes animateErrorIcon{0%{-webkit-transform:rotateX(100deg);transform:rotateX(100deg);opacity:0}to{-webkit-transform:rotateX(0deg);transform:rotateX(0deg);opacity:1}}@keyframes animateErrorIcon{0%{-webkit-transform:rotateX(100deg);transform:rotateX(100deg);opacity:0}to{-webkit-transform:rotateX(0deg);transform:rotateX(0deg);opacity:1}}@-webkit-keyframes animateXMark{0%{-webkit-transform:scale(.4);transform:scale(.4);margin-top:26px;opacity:0}50%{-webkit-transform:scale(.4);transform:scale(.4);margin-top:26px;opacity:0}80%{-webkit-transform:scale(1.15);transform:scale(1.15);margin-top:-6px}to{-webkit-transform:scale(1);transform:scale(1);margin-top:0;opacity:1}}@keyframes animateXMark{0%{-webkit-transform:scale(.4);transform:scale(.4);margin-top:26px;opacity:0}50%{-webkit-transform:scale(.4);transform:scale(.4);margin-top:26px;opacity:0}80%{-webkit-transform:scale(1.15);transform:scale(1.15);margin-top:-6px}to{-webkit-transform:scale(1);transform:scale(1);margin-top:0;opacity:1}}.swal-icon--warning{border-color:#f8bb86;-webkit-animation:pulseWarning .75s infinite alternate;animation:pulseWarning .75s infinite alternate}.swal-icon--warning__body{width:5px;height:47px;top:10px;border-radius:2px;margin-left:-2px}.swal-icon--warning__body,.swal-icon--warning__dot{position:absolute;left:50%;background-color:#f8bb86}.swal-icon--warning__dot{width:7px;height:7px;border-radius:50%;margin-left:-4px;bottom:-11px}@-webkit-keyframes pulseWarning{0%{border-color:#f8d486}to{border-color:#f8bb86}}@keyframes pulseWarning{0%{border-color:#f8d486}to{border-color:#f8bb86}}.swal-icon--success{border-color:#a5dc86}.swal-icon--success:after,.swal-icon--success:before{content:"";border-radius:50%;position:absolute;width:60px;height:120px;background:#fff;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swal-icon--success:before{border-radius:120px 0 0 120px;top:-7px;left:-33px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:60px 60px;transform-origin:60px 60px}.swal-icon--success:after{border-radius:0 120px 120px 0;top:-11px;left:30px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:0 60px;transform-origin:0 60px;-webkit-animation:rotatePlaceholder 4.25s ease-in;animation:rotatePlaceholder 4.25s ease-in}.swal-icon--success__ring{width:80px;height:80px;border:4px solid hsla(98,55%,69%,.2);border-radius:50%;box-sizing:content-box;position:absolute;left:-4px;top:-4px;z-index:2}.swal-icon--success__hide-corners{width:5px;height:90px;background-color:#fff;padding:1px;position:absolute;left:28px;top:8px;z-index:1;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.swal-icon--success__line{height:5px;background-color:#a5dc86;display:block;border-radius:2px;position:absolute;z-index:2}.swal-icon--success__line--tip{width:25px;left:14px;top:46px;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-animation:animateSuccessTip .75s;animation:animateSuccessTip .75s}.swal-icon--success__line--long{width:47px;right:8px;top:38px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-animation:animateSuccessLong .75s;animation:animateSuccessLong .75s}@-webkit-keyframes rotatePlaceholder{0%{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}5%{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}12%{-webkit-transform:rotate(-405deg);transform:rotate(-405deg)}to{-webkit-transform:rotate(-405deg);transform:rotate(-405deg)}}@keyframes rotatePlaceholder{0%{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}5%{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}12%{-webkit-transform:rotate(-405deg);transform:rotate(-405deg)}to{-webkit-transform:rotate(-405deg);transform:rotate(-405deg)}}@-webkit-keyframes animateSuccessTip{0%{width:0;left:1px;top:19px}54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}to{width:25px;left:14px;top:45px}}@keyframes animateSuccessTip{0%{width:0;left:1px;top:19px}54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}to{width:25px;left:14px;top:45px}}@-webkit-keyframes animateSuccessLong{0%{width:0;right:46px;top:54px}65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}to{width:47px;right:8px;top:38px}}@keyframes animateSuccessLong{0%{width:0;right:46px;top:54px}65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}to{width:47px;right:8px;top:38px}}.swal-icon--info{border-color:#c9dae1}.swal-icon--info:before{width:5px;height:29px;bottom:17px;border-radius:2px;margin-left:-2px}.swal-icon--info:after,.swal-icon--info:before{content:"";position:absolute;left:50%;background-color:#c9dae1}.swal-icon--info:after{width:7px;height:7px;border-radius:50%;margin-left:-3px;top:19px}.swal-icon{width:80px;height:80px;border-width:4px;border-style:solid;border-radius:50%;padding:0;position:relative;box-sizing:content-box;margin:20px auto}.swal-icon:first-child{margin-top:32px}.swal-icon--custom{width:auto;height:auto;max-width:100%;border:none;border-radius:0}.swal-icon img{max-width:100%;max-height:100%}.swal-title{color:rgba(0,0,0,.65);font-weight:600;text-transform:none;position:relative;display:block;padding:13px 16px;font-size:27px;line-height:normal;text-align:center;margin-bottom:0}.swal-title:first-child{margin-top:26px}.swal-title:not(:first-child){padding-bottom:0}.swal-title:not(:last-child){margin-bottom:13px}.swal-text{font-size:16px;position:relative;float:none;line-height:normal;vertical-align:top;text-align:left;display:inline-block;margin:0;padding:0 10px;font-weight:400;color:rgba(0,0,0,.64);max-width:calc(100% - 20px);overflow-wrap:break-word;box-sizing:border-box}.swal-text:first-child{margin-top:45px}.swal-text:last-child{margin-bottom:45px}.swal-footer{text-align:right;padding-top:13px;margin-top:13px;padding:13px 16px;border-radius:inherit;border-top-left-radius:0;border-top-right-radius:0}.swal-button-container{margin:5px;display:inline-block;position:relative}.swal-button{background-color:#7cd1f9;color:#fff;border:none;box-shadow:none;border-radius:5px;font-weight:600;font-size:14px;padding:10px 24px;margin:0;cursor:pointer}.swal-button[not:disabled]:hover{background-color:#78cbf2}.swal-button:active{background-color:#70bce0}.swal-button:focus{outline:none;box-shadow:0 0 0 1px #fff,0 0 0 3px rgba(43,114,165,.29)}.swal-button[disabled]{opacity:.5;cursor:default}.swal-button::-moz-focus-inner{border:0}.swal-button--cancel{color:#555;background-color:#efefef}.swal-button--cancel[not:disabled]:hover{background-color:#e8e8e8}.swal-button--cancel:active{background-color:#d7d7d7}.swal-button--cancel:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px rgba(116,136,150,.29)}.swal-button--danger{background-color:#e64942}.swal-button--danger[not:disabled]:hover{background-color:#df4740}.swal-button--danger:active{background-color:#cf423b}.swal-button--danger:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px rgba(165,43,43,.29)}.swal-content{padding:0 20px;margin-top:20px;font-size:medium}.swal-content:last-child{margin-bottom:20px}.swal-content__input,.swal-content__textarea{-webkit-appearance:none;background-color:#fff;border:none;font-size:14px;display:block;box-sizing:border-box;width:100%;border:1px solid rgba(0,0,0,.14);padding:10px 13px;border-radius:2px;transition:border-color .2s}.swal-content__input:focus,.swal-content__textarea:focus{outline:none;border-color:#6db8ff}.swal-content__textarea{resize:vertical}.swal-button--loading{color:transparent}.swal-button--loading~.swal-button__loader{opacity:1}.swal-button__loader{position:absolute;height:auto;width:43px;z-index:2;left:50%;top:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);text-align:center;pointer-events:none;opacity:0}.swal-button__loader div{display:inline-block;float:none;vertical-align:baseline;width:9px;height:9px;padding:0;border:none;margin:2px;opacity:.4;border-radius:7px;background-color:hsla(0,0%,100%,.9);transition:background .2s;-webkit-animation:swal-loading-anim 1s infinite;animation:swal-loading-anim 1s infinite}.swal-button__loader div:nth-child(3n+2){-webkit-animation-delay:.15s;animation-delay:.15s}.swal-button__loader div:nth-child(3n+3){-webkit-animation-delay:.3s;animation-delay:.3s}@-webkit-keyframes swal-loading-anim{0%{opacity:.4}20%{opacity:.4}50%{opacity:1}to{opacity:.4}}@keyframes swal-loading-anim{0%{opacity:.4}20%{opacity:.4}50%{opacity:1}to{opacity:.4}}.swal-overlay{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center;font-size:0;overflow-y:auto;background-color:rgba(0,0,0,.4);z-index:10000;pointer-events:none;opacity:0;transition:opacity .3s}.swal-overlay:before{content:" ";display:inline-block;vertical-align:middle;height:100%}.swal-overlay--show-modal{opacity:1;pointer-events:auto}.swal-overlay--show-modal .swal-modal{opacity:1;pointer-events:auto;box-sizing:border-box;-webkit-animation:showSweetAlert .3s;animation:showSweetAlert .3s;will-change:transform}.swal-modal{width:478px;opacity:0;pointer-events:none;background-color:#fff;text-align:center;border-radius:5px;position:static;margin:20px auto;display:inline-block;vertical-align:middle;-webkit-transform:scale(1);transform:scale(1);-webkit-transform-origin:50% 50%;transform-origin:50% 50%;z-index:10001;transition:opacity .2s,-webkit-transform .3s;transition:transform .3s,opacity .2s;transition:transform .3s,opacity .2s,-webkit-transform .3s}@media (max-width:500px){.swal-modal{width:calc(100% - 20px)}}@-webkit-keyframes showSweetAlert{0%{-webkit-transform:scale(1);transform:scale(1)}1%{-webkit-transform:scale(.5);transform:scale(.5)}45%{-webkit-transform:scale(1.05);transform:scale(1.05)}80%{-webkit-transform:scale(.95);transform:scale(.95)}to{-webkit-transform:scale(1);transform:scale(1)}}@keyframes showSweetAlert{0%{-webkit-transform:scale(1);transform:scale(1)}1%{-webkit-transform:scale(.5);transform:scale(.5)}45%{-webkit-transform:scale(1.05);transform:scale(1.05)}80%{-webkit-transform:scale(.95);transform:scale(.95)}to{-webkit-transform:scale(1);transform:scale(1)}}',""])},function(t,e){function n(t,e){var n=t[1]||"",r=t[3];if(!r)return n;if(e&&"function"==typeof btoa){var i=o(r);return[n].concat(r.sources.map(function(t){return"/*# sourceURL="+r.sourceRoot+t+" */"})).concat([i]).join("\n")}return[n].join("\n")}function o(t){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(t))))+" */"}t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var o=n(e,t);return e[2]?"@media "+e[2]+"{"+o+"}":o}).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var o={},r=0;r<this.length;r++){var i=this[r][0];"number"==typeof i&&(o[i]=!0)}for(r=0;r<t.length;r++){var a=t[r];"number"==typeof a[0]&&o[a[0]]||(n&&!a[2]?a[2]=n:n&&(a[2]="("+a[2]+") and ("+n+")"),e.push(a))}},e}},function(t,e,n){function o(t,e){for(var n=0;n<t.length;n++){var o=t[n],r=m[o.id];if(r){r.refs++;for(var i=0;i<r.parts.length;i++)r.parts[i](o.parts[i]);for(;i<o.parts.length;i++)r.parts.push(u(o.parts[i],e))}else{for(var a=[],i=0;i<o.parts.length;i++)a.push(u(o.parts[i],e));m[o.id]={id:o.id,refs:1,parts:a}}}}function r(t,e){for(var n=[],o={},r=0;r<t.length;r++){var i=t[r],a=e.base?i[0]+e.base:i[0],s=i[1],c=i[2],l=i[3],u={css:s,media:c,sourceMap:l};o[a]?o[a].parts.push(u):n.push(o[a]={id:a,parts:[u]})}return n}function i(t,e){var n=v(t.insertInto);if(!n)throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");var o=w[w.length-1];if("top"===t.insertAt)o?o.nextSibling?n.insertBefore(e,o.nextSibling):n.appendChild(e):n.insertBefore(e,n.firstChild),w.push(e);else{if("bottom"!==t.insertAt)throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");n.appendChild(e)}}function a(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t);var e=w.indexOf(t);e>=0&&w.splice(e,1)}function s(t){var e=document.createElement("style");return t.attrs.type="text/css",l(e,t.attrs),i(t,e),e}function c(t){var e=document.createElement("link");return t.attrs.type="text/css",t.attrs.rel="stylesheet",l(e,t.attrs),i(t,e),e}function l(t,e){Object.keys(e).forEach(function(n){t.setAttribute(n,e[n])})}function u(t,e){var n,o,r,i;if(e.transform&&t.css){if(!(i=e.transform(t.css)))return function(){};t.css=i}if(e.singleton){var l=h++;n=g||(g=s(e)),o=f.bind(null,n,l,!1),r=f.bind(null,n,l,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=c(e),o=p.bind(null,n,e),r=function(){a(n),n.href&&URL.revokeObjectURL(n.href)}):(n=s(e),o=d.bind(null,n),r=function(){a(n)});return o(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;o(t=e)}else r()}}function f(t,e,n,o){var r=n?"":o.css;if(t.styleSheet)t.styleSheet.cssText=x(e,r);else{var i=document.createTextNode(r),a=t.childNodes;a[e]&&t.removeChild(a[e]),a.length?t.insertBefore(i,a[e]):t.appendChild(i)}}function d(t,e){var n=e.css,o=e.media;if(o&&t.setAttribute("media",o),t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}function p(t,e,n){var o=n.css,r=n.sourceMap,i=void 0===e.convertToAbsoluteUrls&&r;(e.convertToAbsoluteUrls||i)&&(o=y(o)),r&&(o+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */");var a=new Blob([o],{type:"text/css"}),s=t.href;t.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}var m={},b=function(t){var e;return function(){return void 0===e&&(e=t.apply(this,arguments)),e}}(function(){return window&&document&&document.all&&!window.atob}),v=function(t){var e={};return function(n){return void 0===e[n]&&(e[n]=t.call(this,n)),e[n]}}(function(t){return document.querySelector(t)}),g=null,h=0,w=[],y=n(15);t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");e=e||{},e.attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||(e.singleton=b()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var n=r(t,e);return o(n,e),function(t){for(var i=[],a=0;a<n.length;a++){var s=n[a],c=m[s.id];c.refs--,i.push(c)}if(t){o(r(t,e),e)}for(var a=0;a<i.length;a++){var c=i[a];if(0===c.refs){for(var l=0;l<c.parts.length;l++)c.parts[l]();delete m[c.id]}}}};var x=function(){var t=[];return function(e,n){return t[e]=n,t.filter(Boolean).join("\n")}}()},function(t,e){t.exports=function(t){var e="undefined"!=typeof window&&window.location;if(!e)throw new Error("fixUrls requires window.location");if(!t||"string"!=typeof t)return t;var n=e.protocol+"//"+e.host,o=n+e.pathname.replace(/\/[^\/]*$/,"/");return t.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi,function(t,e){var r=e.trim().replace(/^"(.*)"$/,function(t,e){return e}).replace(/^'(.*)'$/,function(t,e){return e});if(/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/)/i.test(r))return t;var i;return i=0===r.indexOf("//")?r:0===r.indexOf("/")?n+r:o+r.replace(/^\.\//,""),"url("+JSON.stringify(i)+")"})}},function(t,e,n){var o=n(17);"undefined"==typeof window||window.Promise||(window.Promise=o),n(21),String.prototype.includes||(String.prototype.includes=function(t,e){"use strict";return"number"!=typeof e&&(e=0),!(e+t.length>this.length)&&-1!==this.indexOf(t,e)}),Array.prototype.includes||Object.defineProperty(Array.prototype,"includes",{value:function(t,e){if(null==this)throw new TypeError('"this" is null or not defined');var n=Object(this),o=n.length>>>0;if(0===o)return!1;for(var r=0|e,i=Math.max(r>=0?r:o-Math.abs(r),0);i<o;){if(function(t,e){return t===e||"number"==typeof t&&"number"==typeof e&&isNaN(t)&&isNaN(e)}(n[i],t))return!0;i++}return!1}}),"undefined"!=typeof window&&function(t){t.forEach(function(t){t.hasOwnProperty("remove")||Object.defineProperty(t,"remove",{configurable:!0,enumerable:!0,writable:!0,value:function(){this.parentNode.removeChild(this)}})})}([Element.prototype,CharacterData.prototype,DocumentType.prototype])},function(t,e,n){(function(e){!function(n){function o(){}function r(t,e){return function(){t.apply(e,arguments)}}function i(t){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof t)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],f(t,this)}function a(t,e){for(;3===t._state;)t=t._value;if(0===t._state)return void t._deferreds.push(e);t._handled=!0,i._immediateFn(function(){var n=1===t._state?e.onFulfilled:e.onRejected;if(null===n)return void(1===t._state?s:c)(e.promise,t._value);var o;try{o=n(t._value)}catch(t){return void c(e.promise,t)}s(e.promise,o)})}function s(t,e){try{if(e===t)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"==typeof e||"function"==typeof e)){var n=e.then;if(e instanceof i)return t._state=3,t._value=e,void l(t);if("function"==typeof n)return void f(r(n,e),t)}t._state=1,t._value=e,l(t)}catch(e){c(t,e)}}function c(t,e){t._state=2,t._value=e,l(t)}function l(t){2===t._state&&0===t._deferreds.length&&i._immediateFn(function(){t._handled||i._unhandledRejectionFn(t._value)});for(var e=0,n=t._deferreds.length;e<n;e++)a(t,t._deferreds[e]);t._deferreds=null}function u(t,e,n){this.onFulfilled="function"==typeof t?t:null,this.onRejected="function"==typeof e?e:null,this.promise=n}function f(t,e){var n=!1;try{t(function(t){n||(n=!0,s(e,t))},function(t){n||(n=!0,c(e,t))})}catch(t){if(n)return;n=!0,c(e,t)}}var d=setTimeout;i.prototype.catch=function(t){return this.then(null,t)},i.prototype.then=function(t,e){var n=new this.constructor(o);return a(this,new u(t,e,n)),n},i.all=function(t){var e=Array.prototype.slice.call(t);return new i(function(t,n){function o(i,a){try{if(a&&("object"==typeof a||"function"==typeof a)){var s=a.then;if("function"==typeof s)return void s.call(a,function(t){o(i,t)},n)}e[i]=a,0==--r&&t(e)}catch(t){n(t)}}if(0===e.length)return t([]);for(var r=e.length,i=0;i<e.length;i++)o(i,e[i])})},i.resolve=function(t){return t&&"object"==typeof t&&t.constructor===i?t:new i(function(e){e(t)})},i.reject=function(t){return new i(function(e,n){n(t)})},i.race=function(t){return new i(function(e,n){for(var o=0,r=t.length;o<r;o++)t[o].then(e,n)})},i._immediateFn="function"==typeof e&&function(t){e(t)}||function(t){d(t,0)},i._unhandledRejectionFn=function(t){"undefined"!=typeof console&&console&&console.warn("Possible Unhandled Promise Rejection:",t)},i._setImmediateFn=function(t){i._immediateFn=t},i._setUnhandledRejectionFn=function(t){i._unhandledRejectionFn=t},void 0!==t&&t.exports?t.exports=i:n.Promise||(n.Promise=i)}(this)}).call(e,n(18).setImmediate)},function(t,e,n){function o(t,e){this._id=t,this._clearFn=e}var r=Function.prototype.apply;e.setTimeout=function(){return new o(r.call(setTimeout,window,arguments),clearTimeout)},e.setInterval=function(){return new o(r.call(setInterval,window,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t&&t.close()},o.prototype.unref=o.prototype.ref=function(){},o.prototype.close=function(){this._clearFn.call(window,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},n(19),e.setImmediate=setImmediate,e.clearImmediate=clearImmediate},function(t,e,n){(function(t,e){!function(t,n){"use strict";function o(t){"function"!=typeof t&&(t=new Function(""+t));for(var e=new Array(arguments.length-1),n=0;n<e.length;n++)e[n]=arguments[n+1];var o={callback:t,args:e};return l[c]=o,s(c),c++}function r(t){delete l[t]}function i(t){var e=t.callback,o=t.args;switch(o.length){case 0:e();break;case 1:e(o[0]);break;case 2:e(o[0],o[1]);break;case 3:e(o[0],o[1],o[2]);break;default:e.apply(n,o)}}function a(t){if(u)setTimeout(a,0,t);else{var e=l[t];if(e){u=!0;try{i(e)}finally{r(t),u=!1}}}}if(!t.setImmediate){var s,c=1,l={},u=!1,f=t.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(t);d=d&&d.setTimeout?d:t,"[object process]"==={}.toString.call(t.process)?function(){s=function(t){e.nextTick(function(){a(t)})}}():function(){if(t.postMessage&&!t.importScripts){var e=!0,n=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=n,e}}()?function(){var e="setImmediate$"+Math.random()+"$",n=function(n){n.source===t&&"string"==typeof n.data&&0===n.data.indexOf(e)&&a(+n.data.slice(e.length))};t.addEventListener?t.addEventListener("message",n,!1):t.attachEvent("onmessage",n),s=function(n){t.postMessage(e+n,"*")}}():t.MessageChannel?function(){var t=new MessageChannel;t.port1.onmessage=function(t){a(t.data)},s=function(e){t.port2.postMessage(e)}}():f&&"onreadystatechange"in f.createElement("script")?function(){var t=f.documentElement;s=function(e){var n=f.createElement("script");n.onreadystatechange=function(){a(e),n.onreadystatechange=null,t.removeChild(n),n=null},t.appendChild(n)}}():function(){s=function(t){setTimeout(a,0,t)}}(),d.setImmediate=o,d.clearImmediate=r}}("undefined"==typeof self?void 0===t?this:t:self)}).call(e,n(7),n(20))},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function o(){throw new Error("clearTimeout has not been defined")}function r(t){if(u===setTimeout)return setTimeout(t,0);if((u===n||!u)&&setTimeout)return u=setTimeout,setTimeout(t,0);try{return u(t,0)}catch(e){try{return u.call(null,t,0)}catch(e){return u.call(this,t,0)}}}function i(t){if(f===clearTimeout)return clearTimeout(t);if((f===o||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(t);try{return f(t)}catch(e){try{return f.call(null,t)}catch(e){return f.call(this,t)}}}function a(){b&&p&&(b=!1,p.length?m=p.concat(m):v=-1,m.length&&s())}function s(){if(!b){var t=r(a);b=!0;for(var e=m.length;e;){for(p=m,m=[];++v<e;)p&&p[v].run();v=-1,e=m.length}p=null,b=!1,i(t)}}function c(t,e){this.fun=t,this.array=e}function l(){}var u,f,d=t.exports={};!function(){try{u="function"==typeof setTimeout?setTimeout:n}catch(t){u=n}try{f="function"==typeof clearTimeout?clearTimeout:o}catch(t){f=o}}();var p,m=[],b=!1,v=-1;d.nextTick=function(t){var e=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)e[n-1]=arguments[n];m.push(new c(t,e)),1!==m.length||b||r(s)},c.prototype.run=function(){this.fun.apply(null,this.array)},d.title="browser",d.browser=!0,d.env={},d.argv=[],d.version="",d.versions={},d.on=l,d.addListener=l,d.once=l,d.off=l,d.removeListener=l,d.removeAllListeners=l,d.emit=l,d.prependListener=l,d.prependOnceListener=l,d.listeners=function(t){return[]},d.binding=function(t){throw new Error("process.binding is not supported")},d.cwd=function(){return"/"},d.chdir=function(t){throw new Error("process.chdir is not supported")},d.umask=function(){return 0}},function(t,e,n){"use strict";n(22).polyfill()},function(t,e,n){"use strict";function o(t,e){if(void 0===t||null===t)throw new TypeError("Cannot convert first argument to object");for(var n=Object(t),o=1;o<arguments.length;o++){var r=arguments[o];if(void 0!==r&&null!==r)for(var i=Object.keys(Object(r)),a=0,s=i.length;a<s;a++){var c=i[a],l=Object.getOwnPropertyDescriptor(r,c);void 0!==l&&l.enumerable&&(n[c]=r[c])}}return n}function r(){Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:o})}t.exports={assign:o,polyfill:r}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(24),r=n(6),i=n(5),a=n(36),s=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if("undefined"!=typeof window){var n=a.getOpts.apply(void 0,t);return new Promise(function(t,e){i.default.promise={resolve:t,reject:e},o.default(n),setTimeout(function(){r.openModal()})})}};s.close=r.onAction,s.getState=r.getState,s.setActionValue=i.setActionValue,s.stopLoading=r.stopLoading,s.setDefaults=a.setDefaults,e.default=s},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r=n(0),i=r.default.MODAL,a=n(4),s=n(34),c=n(35),l=n(1);e.init=function(t){o.getNode(i)||(document.body||l.throwErr("You can only use SweetAlert AFTER the DOM has loaded!"),s.default(),a.default()),a.initModalContent(t),c.default(t)},e.default=e.init},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),r=o.default.MODAL;e.modalMarkup='\n <div class="'+r+'" role="dialog" aria-modal="true"></div>',e.default=e.modalMarkup},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),r=o.default.OVERLAY,i='<div \n class="'+r+'"\n tabIndex="-1">\n </div>';e.default=i},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),r=o.default.ICON;e.errorIconMarkup=function(){var t=r+"--error",e=t+"__line";return'\n <div class="'+t+'__x-mark">\n <span class="'+e+" "+e+'--left"></span>\n <span class="'+e+" "+e+'--right"></span>\n </div>\n '},e.warningIconMarkup=function(){var t=r+"--warning";return'\n <span class="'+t+'__body">\n <span class="'+t+'__dot"></span>\n </span>\n '},e.successIconMarkup=function(){var t=r+"--success";return'\n <span class="'+t+"__line "+t+'__line--long"></span>\n <span class="'+t+"__line "+t+'__line--tip"></span>\n\n <div class="'+t+'__ring"></div>\n <div class="'+t+'__hide-corners"></div>\n '}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),r=o.default.CONTENT;e.contentMarkup='\n <div class="'+r+'">\n\n </div>\n'},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),r=o.default.BUTTON_CONTAINER,i=o.default.BUTTON,a=o.default.BUTTON_LOADER;e.buttonMarkup='\n <div class="'+r+'">\n\n <button\n class="'+i+'"\n ></button>\n\n <div class="'+a+'">\n <div></div>\n <div></div>\n <div></div>\n </div>\n\n </div>\n'},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(4),r=n(2),i=n(0),a=i.default.ICON,s=i.default.ICON_CUSTOM,c=["error","warning","success","info"],l={error:r.errorIconMarkup(),warning:r.warningIconMarkup(),success:r.successIconMarkup()},u=function(t,e){var n=a+"--"+t;e.classList.add(n);var o=l[t];o&&(e.innerHTML=o)},f=function(t,e){e.classList.add(s);var n=document.createElement("img");n.src=t,e.appendChild(n)},d=function(t){if(t){var e=o.injectElIntoModal(r.iconMarkup);c.includes(t)?u(t,e):f(t,e)}};e.default=d},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(2),r=n(4),i=function(t){navigator.userAgent.includes("AppleWebKit")&&(t.style.display="none",t.offsetHeight,t.style.display="")};e.initTitle=function(t){if(t){var e=r.injectElIntoModal(o.titleMarkup);e.textContent=t,i(e)}},e.initText=function(t){if(t){var e=document.createDocumentFragment();t.split("\n").forEach(function(t,n,o){e.appendChild(document.createTextNode(t)),n<o.length-1&&e.appendChild(document.createElement("br"))});var n=r.injectElIntoModal(o.textMarkup);n.appendChild(e),i(n)}}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r=n(4),i=n(0),a=i.default.BUTTON,s=i.default.DANGER_BUTTON,c=n(3),l=n(2),u=n(6),f=n(5),d=function(t,e,n){var r=e.text,i=e.value,d=e.className,p=e.closeModal,m=o.stringToNode(l.buttonMarkup),b=m.querySelector("."+a),v=a+"--"+t;if(b.classList.add(v),d){(Array.isArray(d)?d:d.split(" ")).filter(function(t){return t.length>0}).forEach(function(t){b.classList.add(t)})}n&&t===c.CONFIRM_KEY&&b.classList.add(s),b.textContent=r;var g={};return g[t]=i,f.setActionValue(g),f.setActionOptionsFor(t,{closeModal:p}),b.addEventListener("click",function(){return u.onAction(t)}),m},p=function(t,e){var n=r.injectElIntoModal(l.footerMarkup);for(var o in t){var i=t[o],a=d(o,i,e);i.visible&&n.appendChild(a)}0===n.children.length&&n.remove()};e.default=p},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(3),r=n(4),i=n(2),a=n(5),s=n(6),c=n(0),l=c.default.CONTENT,u=function(t){t.addEventListener("input",function(t){var e=t.target,n=e.value;a.setActionValue(n)}),t.addEventListener("keyup",function(t){if("Enter"===t.key)return s.onAction(o.CONFIRM_KEY)}),setTimeout(function(){t.focus(),a.setActionValue("")},0)},f=function(t,e,n){var o=document.createElement(e),r=l+"__"+e;o.classList.add(r);for(var i in n){var a=n[i];o[i]=a}"input"===e&&u(o),t.appendChild(o)},d=function(t){if(t){var e=r.injectElIntoModal(i.contentMarkup),n=t.element,o=t.attributes;"string"==typeof n?f(e,n,o):e.appendChild(n)}};e.default=d},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r=n(2),i=function(){var t=o.stringToNode(r.overlayMarkup);document.body.appendChild(t)};e.default=i},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(5),r=n(6),i=n(1),a=n(3),s=n(0),c=s.default.MODAL,l=s.default.BUTTON,u=s.default.OVERLAY,f=function(t){t.preventDefault(),v()},d=function(t){t.preventDefault(),g()},p=function(t){if(o.default.isOpen)switch(t.key){case"Escape":return r.onAction(a.CANCEL_KEY)}},m=function(t){if(o.default.isOpen)switch(t.key){case"Tab":return f(t)}},b=function(t){if(o.default.isOpen)return"Tab"===t.key&&t.shiftKey?d(t):void 0},v=function(){var t=i.getNode(l);t&&(t.tabIndex=0,t.focus())},g=function(){var t=i.getNode(c),e=t.querySelectorAll("."+l),n=e.length-1,o=e[n];o&&o.focus()},h=function(t){t[t.length-1].addEventListener("keydown",m)},w=function(t){t[0].addEventListener("keydown",b)},y=function(){var t=i.getNode(c),e=t.querySelectorAll("."+l);e.length&&(h(e),w(e))},x=function(t){if(i.getNode(u)===t.target)return r.onAction(a.CANCEL_KEY)},_=function(t){var e=i.getNode(u);e.removeEventListener("click",x),t&&e.addEventListener("click",x)},k=function(t){o.default.timer&&clearTimeout(o.default.timer),t&&(o.default.timer=window.setTimeout(function(){return r.onAction(a.CANCEL_KEY)},t))},O=function(t){t.closeOnEsc?document.addEventListener("keyup",p):document.removeEventListener("keyup",p),t.dangerMode?v():g(),y(),_(t.closeOnClickOutside),k(t.timer)};e.default=O},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r=n(3),i=n(37),a=n(38),s={title:null,text:null,icon:null,buttons:r.defaultButtonList,content:null,className:null,closeOnClickOutside:!0,closeOnEsc:!0,dangerMode:!1,timer:null},c=Object.assign({},s);e.setDefaults=function(t){c=Object.assign({},s,t)};var l=function(t){var e=t&&t.button,n=t&&t.buttons;return void 0!==e&&void 0!==n&&o.throwErr("Cannot set both 'button' and 'buttons' options!"),void 0!==e?{confirm:e}:n},u=function(t){return o.ordinalSuffixOf(t+1)},f=function(t,e){o.throwErr(u(e)+" argument ('"+t+"') is invalid")},d=function(t,e){var n=t+1,r=e[n];o.isPlainObject(r)||void 0===r||o.throwErr("Expected "+u(n)+" argument ('"+r+"') to be a plain object")},p=function(t,e){var n=t+1,r=e[n];void 0!==r&&o.throwErr("Unexpected "+u(n)+" argument ("+r+")")},m=function(t,e,n,r){var i=typeof e,a="string"===i,s=e instanceof Element;if(a){if(0===n)return{text:e};if(1===n)return{text:e,title:r[0]};if(2===n)return d(n,r),{icon:e};f(e,n)}else{if(s&&0===n)return d(n,r),{content:e};if(o.isPlainObject(e))return p(n,r),e;f(e,n)}};e.getOpts=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n={};t.forEach(function(e,o){var r=m(0,e,o,t);Object.assign(n,r)});var o=l(n);n.buttons=r.getButtonListOpts(o),delete n.button,n.content=i.getContentOpts(n.content);var u=Object.assign({},s,c,n);return Object.keys(u).forEach(function(t){a.DEPRECATED_OPTS[t]&&a.logDeprecation(t)}),u}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(1),r={element:"input",attributes:{placeholder:""}};e.getContentOpts=function(t){var e={};return o.isPlainObject(t)?Object.assign(e,t):t instanceof Element?{element:t}:"input"===t?r:null}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.logDeprecation=function(t){var n=e.DEPRECATED_OPTS[t],o=n.onlyRename,r=n.replacement,i=n.subOption,a=n.link,s=o?"renamed":"deprecated",c='SweetAlert warning: "'+t+'" option has been '+s+".";if(r){c+=" Please use"+(i?' "'+i+'" in ':" ")+'"'+r+'" instead.'}var l="https://sweetalert.js.org";c+=a?" More details: "+l+a:" More details: "+l+"/guides/#upgrading-from-1x",console.warn(c)},e.DEPRECATED_OPTS={type:{replacement:"icon",link:"/docs/#icon"},imageUrl:{replacement:"icon",link:"/docs/#icon"},customClass:{replacement:"className",onlyRename:!0,link:"/docs/#classname"},imageSize:{},showCancelButton:{replacement:"buttons",link:"/docs/#buttons"},showConfirmButton:{replacement:"button",link:"/docs/#button"},confirmButtonText:{replacement:"button",link:"/docs/#button"},confirmButtonColor:{},cancelButtonText:{replacement:"buttons",link:"/docs/#buttons"},closeOnConfirm:{replacement:"button",subOption:"closeModal",link:"/docs/#button"},closeOnCancel:{replacement:"buttons",subOption:"closeModal",link:"/docs/#buttons"},showLoaderOnConfirm:{replacement:"buttons"},animation:{},inputType:{replacement:"content",link:"/docs/#content"},inputValue:{replacement:"content",link:"/docs/#content"},inputPlaceholder:{replacement:"content",link:"/docs/#content"},html:{replacement:"content",link:"/docs/#content"},allowEscapeKey:{replacement:"closeOnEsc",onlyRename:!0,link:"/docs/#closeonesc"},allowClickOutside:{replacement:"closeOnClickOutside",onlyRename:!0,link:"/docs/#closeonclickoutside"}}}])});
admin/partials/about-plugin.php CHANGED
File without changes
admin/partials/enhanced-ecommerce-google-analytics-admin-display.php CHANGED
File without changes
admin/partials/general-fields.php CHANGED
File without changes
admin/partials/sidebar.php CHANGED
File without changes
css/tvc_admin-page.css ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ To change this license header, choose License Headers in Project Properties.
3
+ To change this template file, choose Tools | Templates
4
+ and open the template in the editor.
5
+ */
6
+
7
+ #feed-spinner {
8
+ /*height: 200px;*/ /*height of the spinner gif +2px to fix IE8 issue */
9
+ left: 50%;
10
+ margin-left: -25px; /* half width of the spinner gif */
11
+ margin-top: -25px; /* half height of the spinner gif */
12
+ overflow: auto;
13
+ position: fixed;
14
+ text-align: center;
15
+ top: 40%;
16
+ /*width: 200px;*/ /* width of the spinner gif */
17
+ z-index: 1234;
18
+ }
19
+ div.field-table-row-wrapper:nth-child(2n) {
20
+ background-color: #f5f5f5;
21
+ }
22
+
23
+ #footer-left{
24
+ display: none;
25
+ }
26
+
27
+ div.field-table-row-wrapper {
28
+ display: block;
29
+ padding-bottom: 5px;
30
+ }
31
+
32
+ div.filter-wrapper {
33
+ margin-top: 5px;
34
+ }
35
+
36
+ aside.action-btn {
37
+ margin-left: 8px;
38
+ }
39
+
40
+ .small-text {
41
+ width: 15px;
42
+ }
43
+
44
+ .field-level {
45
+ background: #e5e5e5;
46
+ clear: both;
47
+ font-size: 15px;
48
+ line-height: 30px;
49
+ padding-left: 5px;
50
+ }
51
+
52
+ .value-options-condition-selector {
53
+ margin-left: 400px;
54
+ }
55
+
56
+ .value-options-query-selector {
57
+ margin-bottom: 15px;
58
+ margin-left: 37%;
59
+ width: 65%
60
+ }
61
+
62
+ select.tvc-main-input-selector {
63
+ height: 33px;
64
+ max-width: 35rem;
65
+ }
66
+
67
+ select.select-value-options {
68
+ height: 27px;
69
+ vertical-align: initial;
70
+ }
71
+
72
+ select.align-left {
73
+ float: left;
74
+ }
75
+
76
+ .condition-and-value-selector {
77
+ margin-left: 5px;
78
+ }
79
+
80
+ div.condition-wrapper {
81
+ float: left;
82
+ line-height: 26px;
83
+ margin-bottom: 15px;
84
+ width: 100%;
85
+ }
86
+
87
+ div.source-data-column {
88
+ }
89
+
90
+ div.change-source-value-wrapper {
91
+ background-color: #e2e2e2;
92
+ float: left;
93
+ margin-left: 16%;
94
+ padding: 15px;
95
+ width: 81%;
96
+ }
97
+
98
+ th#tvc-main-feed-input-label {
99
+ text-align: left;
100
+ width: 32%;
101
+ }
102
+
103
+ th#tvc-main-feed-input-label label {
104
+ display: inline-block;
105
+ }
106
+
107
+ div.edit-value-control {
108
+ float: right;
109
+ margin: -50px 10px;
110
+ }
111
+
112
+ div.add-to-feed-column {
113
+ margin-top: 4px;
114
+ }
115
+
116
+ div.tvc-header-wrapper {
117
+ padding-bottom: 10px;
118
+ }
119
+
120
+ div.tvc-field-header-wrapper {
121
+ background-color: white;
122
+ height: 30px;
123
+ margin-bottom: 10px;
124
+ }
125
+
126
+ div.field-header {
127
+ float: left;
128
+ margin-bottom: 8px;
129
+ padding: 5px;
130
+ }
131
+
132
+ .col10w {
133
+ width: 10%;
134
+ }
135
+
136
+ .col30w {
137
+ width: 30%;
138
+ }
139
+
140
+ .col20w {
141
+ width: 16%;
142
+ }
143
+
144
+ .col40w {
145
+ width: 40%;
146
+ }
147
+
148
+ .col55w {
149
+ width: 55%;
150
+ }
151
+
152
+ .col80w {
153
+ width: 82%;
154
+ }
155
+
156
+ .condition-selector {
157
+ width: 55%;
158
+ }
159
+
160
+ div#category-mapping-header {
161
+ left: 15px;
162
+ position: relative;
163
+ }
164
+
165
+ div.source-selector {
166
+ margin-right: 6%;
167
+ }
168
+
169
+ div.tvc-feedback {
170
+ background-color: #fff;
171
+ border: 1px solid #e5e5e5;
172
+ border-radius: 6px;
173
+ float: right;
174
+ padding: 6px 10px;
175
+ }
176
+
177
+ div.tvc-feedback a:link {
178
+ color: #4D8C0F;
179
+ text-decoration: none;
180
+ }
181
+
182
+ div.tvc-feedback a:visited {
183
+ color: #555;
184
+ text-decoration: none;
185
+ }
186
+
187
+ div.tvc-feedback a:hover {
188
+ color: #3C3;
189
+ text-decoration: none;
190
+ }
191
+
192
+ table.fm-category-mapping-table th {
193
+ font-weight: 700;
194
+ padding: 9px;
195
+ }
196
+
197
+ table.fm-category-mapping-table {
198
+ clear: none;
199
+ display: table;
200
+ float: right;
201
+ height: 280px;
202
+ overflow-y: scroll;
203
+ width: 59%;
204
+ }
205
+
206
+ table.tvc-feed-main-input-table {
207
+ width: 100%;
208
+ }
209
+
210
+ table.fm-category-mapping-table td#shop-category {
211
+ color: #0073aa;
212
+ cursor: auto;
213
+ font-size: 14px !important;
214
+ font-weight: 600;
215
+ padding-left: 2px;
216
+ }
217
+
218
+ table.fm-category-mapping-table th#shop-category-selector {
219
+ vertical-align: top;
220
+ width: 2.2em;
221
+ }
222
+
223
+ td.channel-tile {
224
+ border: 1px solid #ccc;
225
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
226
+ -moz-box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
227
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
228
+ max-width: 340px;
229
+ min-width: 250px;
230
+ vertical-align: top;
231
+ }
232
+
233
+ img.channel-thumbnail {
234
+ border: none;
235
+ max-width: 300px;
236
+ width: 100%;
237
+ }
238
+
239
+ div.channel-inner {
240
+ margin: 20px;
241
+ }
242
+
243
+ div.channel-version {
244
+ background-color: #eee;
245
+ border: 1px solid #dadada;
246
+ border-radius: 3px;
247
+ -webkit-border-radius: 3px;
248
+ -moz-border-radius: 3px;
249
+ color: #424242;
250
+ display: block;
251
+ font-weight: bold;
252
+ margin-bottom: 12px;
253
+ padding: 6px;
254
+ }
255
+
256
+ div#outdated {
257
+ color: red;
258
+ }
259
+
260
+ div.product-filter-condition-wrapper {
261
+ float: right;
262
+ font-size: 16px;
263
+ margin-top: 20px;
264
+ width: 59%;
265
+ }
266
+
267
+ section.tvc-main-input-wrapper {
268
+ float: left;
269
+ margin-top: 20px;
270
+ width: 40%;
271
+ }
272
+
273
+ tr.tvc-main-feed-input-row {
274
+ height: 47px;
275
+ }
276
+
277
+ table.fm-category-mapping-table thead, table.fm-category-mapping-table tbody {
278
+ float: left;
279
+ width: 100%;
280
+ }
281
+
282
+ table.fm-category-mapping-table tbody {
283
+ height: 280px;
284
+ overflow-y: scroll;
285
+ }
286
+
287
+ table.fm-category-mapping-table tr:nth-child(2n) td, table.fm-category-mapping-table tr:nth-child(2n) th {
288
+ background-color: #fcfcfc;
289
+ }
290
+
291
+ thead.fm-category-mapping-titles th {
292
+ font-weight: 400;
293
+ }
294
+
295
+ thead.fm-category-mapping-titles tr {
296
+ width: 98% !important;
297
+ }
298
+
299
+ table.fm-category-mapping-table td:first-child {
300
+ width: 16%;
301
+ }
302
+
303
+ table.fm-category-mapping-table tr {
304
+ display: table;
305
+ text-align: left;
306
+ width: 100%;
307
+ }
308
+
309
+ table.tvc-feed-main-input-table th {
310
+ padding-right: 0;
311
+ width: 40%;
312
+ }
313
+
314
+ table.tvc-feed-main-input-table input {
315
+ width: 90%;
316
+ }
317
+
318
+ table.tvc-feed-main-input-table input#aggregator, table.tvc-feed-main-input-table input#variations {
319
+ width: 10px;
320
+ }
321
+
322
+ table.tvc-feed-main-input-table select {
323
+ width: 90%;
324
+ }
325
+
326
+ .message-field {
327
+ font-size: 16px;
328
+ margin: 20px 0 3px 0;
329
+ }
330
+
331
+ #disposable-warning-message {
332
+ margin: 20px 0 3px 0;
333
+ }
334
+
335
+ button#disposable-notice-button {
336
+ position: relative;
337
+ }
338
+
339
+ .full-screen-message-field p {
340
+ color: red;
341
+ font-size: 17px;
342
+ margin: 20px 0 3px 0;
343
+ }
344
+
345
+ span.output-field-label {
346
+ background-color: #2ea2cc;
347
+ border-radius: 3px;
348
+ color: white;
349
+ margin-top: 4px;
350
+ padding: 4px 10px;
351
+ }
352
+
353
+ div.colw {
354
+ float: left;
355
+ padding: 5px;
356
+ }
357
+
358
+ div.edit-values-row {
359
+ float: left;
360
+ margin: 20px 10px 10px 30px;
361
+ width: 80%;
362
+ }
363
+
364
+ div.end-row {
365
+ clear: both;
366
+ }
367
+
368
+ div.field-table-row {
369
+ height: 20px;
370
+ }
371
+
372
+ div.field-table-row-edit-source {
373
+ clear: both;
374
+ float: left;
375
+ }
376
+
377
+ div.field-table-row-combined-selection {
378
+ left: -181px;
379
+ line-height: 26px;
380
+ margin: 5px;
381
+ position: relative;
382
+ width: 680px;
383
+ }
384
+
385
+ div.combined-wrapper {
386
+ line-height: 26px;
387
+ width: 100%;
388
+ }
389
+
390
+ div.or-selector {
391
+ line-height: 26px;
392
+ margin-top: 30px;
393
+ width: 120%;
394
+ }
395
+
396
+ div.dotted-top-line {
397
+ border-top-style: dashed;
398
+ border-top-color: #ccc;
399
+ border-top-width: 1px;
400
+ margin-top: 20px;
401
+ }
402
+
403
+ span.combined-field-row {
404
+ clear: left;
405
+ float: left;
406
+ }
407
+
408
+ input.free-category-text-input {
409
+ width: 90%;
410
+ }
411
+
412
+ div.button-wrapper {
413
+ clear: both;
414
+ }
415
+
416
+ .button-primary {
417
+ margin-top: 15px !important;
418
+ margin-right: 5px !important;
419
+ }
420
+
421
+ a.channel-button {
422
+ margin-right: 5px !important;
423
+ }
424
+
425
+ a.tvc-btn-small {
426
+ font-size: 13px;
427
+ }
428
+
429
+ a.tvc-rating-request {
430
+ color: #FFB900;
431
+ }
432
+
433
+ input.feed-list-lower-button {
434
+ position: relative;
435
+ margin-bottom: 10px!important;
436
+ }
437
+
438
+ div.select-control {
439
+ float: left;
440
+ margin: 0;
441
+ vertical-align: top;
442
+ }
443
+
444
+ div.static-value-control {
445
+ float: left;
446
+ }
447
+ #wpcontent{
448
+ height: 100%;
449
+ /*padding-left: 0 !important;*/
450
+ }
451
+
452
+ /*prgress info*/
453
+ .tvc-progressbar-wapper{
454
+ width: 97%;
455
+ margin: 10px auto;
456
+ text-align: center;
457
+ position: relative;
458
+ background-color: #fff;
459
+ padding: 11px;
460
+ }
461
+ .tvc-progressbar {
462
+
463
+ overflow: hidden;
464
+ counter-reset: step;
465
+ }
466
+ .tvc-progressbar .tvc-steps {
467
+ list-style-type: none;
468
+ color: #D2D2D2;
469
+ text-transform: capitalize;
470
+ font-size: 16px;
471
+ width: 33.33%;
472
+ float: left;
473
+ position: relative;
474
+ display: block;
475
+ }
476
+ .tvc-progressbar .tvc-steps .tvc-steps-icon{
477
+ display: inline-block;
478
+ float: left;
479
+ }
480
+ .tvc-progressbar .tvc-steps .tvc-steps-text{
481
+ display: inline-block;
482
+
483
+ float: left;
484
+ }
485
+ .tvc-progressbar .tvc-steps:before {
486
+ border: 2px solid #007bff;
487
+ color: #007bff;
488
+ content: '';
489
+ position: absolute;
490
+ counter-increment: step;
491
+ width: 43px;
492
+ line-height: 40px;
493
+ display: block;
494
+ font-size: 18px;
495
+ float: left;
496
+ background: transparent;
497
+ border-radius: 100%;
498
+ margin: 0 auto 5px auto;
499
+ border: 2px solid #ECECEC;
500
+ }
501
+ .tvc-progressbar .tvc-steps:nth-child(1):before {
502
+ content: "\f129";
503
+ font-family: 'FontAwesome';
504
+ }
505
+ .tvc-progressbar .tvc-steps:nth-child(2):before {
506
+ content: "\f013";
507
+ font-family: 'FontAwesome';
508
+ }
509
+ .tvc-progressbar .tvc-steps:nth-child(3):before {
510
+ content: "\f00c";
511
+ font-family: 'FontAwesome';
512
+ }
513
+ /*.tvc-progressbar .tvc-steps:after {
514
+ content: '';
515
+ width: 73%;
516
+ height: 2px;
517
+ background: #ECECEC;
518
+ position: absolute;
519
+ left: -35%;
520
+ top: 25px;
521
+ z-index: 1;
522
+ }
523
+ .tvc-progressbar .tvc-steps:first-child:after {
524
+ content: none;
525
+ }*/
526
+ .tvc-progressbar .tvc-steps lable{display: block; font-size: 22px;
527
+ color: #007bff; height: 54px; text-align: left;
528
+ margin: 6px 0 0 50px;}
529
+ .tvc-progressbar .tvc-steps span{display: block; text-align: left; font-size: 16px;
530
+ line-height: 24px;}
531
+ .tvc-progressbar .tvc-steps span img{margin-left: 5px; margin-right: 8px;
532
+ height: 10px;}
533
+ @media only screen and (min-width: 1200px){
534
+ .container{
535
+ margin-left: 8% !important;
536
+ width:auto;
537
+ }
538
+ .banner{
539
+ width:100%;
540
+ }
541
+ }
542
+ @media only screen and (min-width: 1920px){
543
+ .container{
544
+ margin-left: 6% !important;
545
+ width:auto;
546
+ }
547
+
548
+ }
css/tvc_admin-page.min.css ADDED
@@ -0,0 +1,496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .wp-core-ui select {
2
+ margin-bottom: 10px;
3
+ }
4
+
5
+ #tvc-attribute-map {
6
+ background: #fff;
7
+ padding: 20px;
8
+ border: 1px solid rgba(0, 0, 0, .125);
9
+ }
10
+
11
+ .bg-wrap {
12
+ background: #fff;
13
+ padding: 20px;
14
+ border: 1px solid rgba(0, 0, 0, .125);
15
+ overflow: auto;
16
+ }
17
+
18
+ .container {
19
+ margin-left: 8% !important;
20
+ width: auto;
21
+ }
22
+
23
+ #feed-spinner {
24
+ /*height: 50px;*/
25
+ left: 50%;
26
+ margin-left: -25px;
27
+ margin-top: -25px;
28
+ overflow: auto;
29
+ position: fixed;
30
+ text-align: center;
31
+ top: 35%;
32
+ /*width: 50px;*/
33
+ z-index: 1234
34
+ }
35
+
36
+ div.field-table-row-wrapper:nth-child(2n) {
37
+ background-color: #f5f5f5
38
+ }
39
+
40
+ div.field-table-row-wrapper {
41
+ display: block;
42
+ padding-bottom: 5px
43
+ }
44
+
45
+ div.filter-wrapper {
46
+ margin-top: 5px
47
+ }
48
+
49
+ aside.action-btn {
50
+ margin-left: 8px
51
+ }
52
+
53
+ .small-text {
54
+ width: 15px
55
+ }
56
+
57
+ .field-level {
58
+ clear: both;
59
+ font-size: 15px;
60
+ line-height: 30px;
61
+ padding-left: 5px
62
+ }
63
+
64
+ .value-options-condition-selector {
65
+ margin-left: 400px
66
+ }
67
+
68
+ .value-options-query-selector {
69
+ margin-bottom: 15px;
70
+ margin-left: 37%;
71
+ width: 65%
72
+ }
73
+
74
+ select.tvc-main-input-selector {
75
+ height: 33px;
76
+ max-width: 35rem
77
+ }
78
+
79
+ select.select-value-options {
80
+ height: 27px;
81
+ vertical-align: initial
82
+ }
83
+
84
+ select.align-left {
85
+ float: left
86
+ }
87
+
88
+ .condition-and-value-selector {
89
+ margin-left: 5px
90
+ }
91
+
92
+ div.condition-wrapper {
93
+ float: left;
94
+ line-height: 26px;
95
+ margin-bottom: 15px;
96
+ width: 100%
97
+ }
98
+
99
+ div.change-source-value-wrapper {
100
+ background-color: #e2e2e2;
101
+ float: left;
102
+ margin-left: 16%;
103
+ padding: 15px;
104
+ width: 81%
105
+ }
106
+
107
+ th#tvc-main-feed-input-label {
108
+ text-align: left;
109
+ width: 25%
110
+ }
111
+
112
+ th#tvc-main-feed-input-label label {
113
+ display: inline-block
114
+ }
115
+
116
+ div.edit-value-control {
117
+ float: right;
118
+ margin: -50px 10px
119
+ }
120
+
121
+ div.add-to-feed-column {
122
+ margin-top: 4px
123
+ }
124
+
125
+ div.tvc-header-wrapper {
126
+ padding-bottom: 10px
127
+ }
128
+
129
+ div.tvc-field-header-wrapper {
130
+ background-color: #e5e5e5;
131
+ height: 30px;
132
+ }
133
+
134
+ div#required-field-table {
135
+ border: 1px solid #e5e5e5;
136
+ border-top: none;
137
+ }
138
+
139
+ div#optional-field-table {
140
+ border: 1px solid #e5e5e5;
141
+ border-top: none;
142
+ }
143
+
144
+ div#new-optional-row {
145
+ border: 1px solid #e5e5e5;
146
+ border-top: none;
147
+ }
148
+
149
+ div.field-header {
150
+ float: left;
151
+ margin-bottom: 8px;
152
+ padding: 5px;
153
+ font-weight: 700;
154
+ }
155
+
156
+ .col10w {
157
+ width: 10%
158
+ }
159
+
160
+ .col30w {
161
+ width: 30%
162
+ }
163
+
164
+ .col20w {
165
+ width: 16%
166
+ }
167
+
168
+ .col40w {
169
+ width: 40%
170
+ }
171
+
172
+ .col55w {
173
+ width: 55%
174
+ }
175
+
176
+ .col80w {
177
+ width: 82%
178
+ }
179
+
180
+ .condition-selector {
181
+ width: 55%
182
+ }
183
+
184
+ div#category-mapping-header {
185
+ left: 15px;
186
+ position: relative
187
+ }
188
+
189
+ div.source-selector {
190
+ margin-right: 6%
191
+ }
192
+
193
+ div.tvc-feedback {
194
+ background-color: #fff;
195
+ border: 1px solid #e5e5e5;
196
+ border-radius: 6px;
197
+ float: right;
198
+ padding: 6px 10px
199
+ }
200
+
201
+ div.tvc-feedback a:link {
202
+ color: #4d8c0f;
203
+ text-decoration: none
204
+ }
205
+
206
+ div.tvc-feedback a:visited {
207
+ color: #555;
208
+ text-decoration: none
209
+ }
210
+
211
+ div.tvc-feedback a:hover {
212
+ color: #3C3;
213
+ text-decoration: none
214
+ }
215
+
216
+ table.fm-category-mapping-table th {
217
+ font-weight: 700;
218
+ padding: 9px
219
+ }
220
+
221
+ table.fm-category-mapping-table {
222
+ clear: none;
223
+ display: table;
224
+ float: right;
225
+ height: 280px;
226
+ overflow-y: scroll;
227
+ width: 50%
228
+ }
229
+
230
+ table.tvc-feed-main-input-table {
231
+ width: 100%
232
+ }
233
+
234
+ table.fm-category-mapping-table td#shop-category {
235
+ color: #0073aa;
236
+ cursor: auto;
237
+ font-size: 14px !important;
238
+ font-weight: 600;
239
+ padding-left: 2px
240
+ }
241
+
242
+ table.fm-category-mapping-table th#shop-category-selector {
243
+ vertical-align: top;
244
+ width: 2.2em
245
+ }
246
+
247
+ td.channel-tile {
248
+ border: 1px solid #ccc;
249
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
250
+ -moz-box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
251
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
252
+ max-width: 340px;
253
+ min-width: 250px;
254
+ vertical-align: top
255
+ }
256
+
257
+ img.channel-thumbnail {
258
+ border: 0;
259
+ max-width: 300px;
260
+ width: 100%
261
+ }
262
+
263
+ div.channel-inner {
264
+ margin: 20px
265
+ }
266
+
267
+ div.channel-version {
268
+ background-color: #eee;
269
+ border: 1px solid #dadada;
270
+ border-radius: 3px;
271
+ -webkit-border-radius: 3px;
272
+ -moz-border-radius: 3px;
273
+ color: #424242;
274
+ display: block;
275
+ font-weight: bold;
276
+ margin-bottom: 12px;
277
+ padding: 6px
278
+ }
279
+
280
+ div#outdated {
281
+ color: red
282
+ }
283
+
284
+ div.product-filter-condition-wrapper {
285
+ float: right;
286
+ font-size: 16px;
287
+ margin-top: 20px;
288
+ width: 59%
289
+ }
290
+
291
+ section.tvc-main-input-wrapper {
292
+ float: left;
293
+ margin-top: 20px;
294
+ width: 50%
295
+ }
296
+
297
+ tr.tvc-main-feed-input-row {
298
+ height: 47px
299
+ }
300
+
301
+ table.fm-category-mapping-table thead {
302
+ background: #e5e5e5;
303
+ }
304
+
305
+ table.fm-category-mapping-table thead, table.fm-category-mapping-table tbody {
306
+ float: left;
307
+ width: 100%
308
+ }
309
+
310
+ table.fm-category-mapping-table tbody {
311
+ height: 280px;
312
+ overflow-y: scroll
313
+ }
314
+
315
+ table.fm-category-mapping-table tr:nth-child(2n) td, table.fm-category-mapping-table tr:nth-child(2n) th {
316
+ background-color: #fcfcfc
317
+ }
318
+
319
+ thead.fm-category-mapping-titles th {
320
+ font-weight: 400
321
+ }
322
+
323
+ thead.fm-category-mapping-titles tr {
324
+ width: 98% !important
325
+ }
326
+
327
+ table.fm-category-mapping-table td:first-child {
328
+ width: 16%
329
+ }
330
+
331
+ table.fm-category-mapping-table tr {
332
+ display: table;
333
+ text-align: left;
334
+ width: 100%
335
+ }
336
+
337
+ table.tvc-feed-main-input-table th {
338
+ padding-right: 0;
339
+ width: 40%
340
+ }
341
+
342
+ table.tvc-feed-main-input-table input {
343
+ width: 90%
344
+ }
345
+
346
+ table.tvc-feed-main-input-table input#aggregator, table.tvc-feed-main-input-table input#variations {
347
+ width: 10px
348
+ }
349
+
350
+ table.tvc-feed-main-input-table select {
351
+ width: 90%;
352
+ margin-bottom: 10px;
353
+ }
354
+
355
+ .message-field {
356
+ font-size: 16px;
357
+ margin: 20px 0 3px 0
358
+ }
359
+
360
+ #disposable-warning-message {
361
+ margin: 20px 0 3px 0
362
+ }
363
+
364
+ button#disposable-notice-button {
365
+ position: relative
366
+ }
367
+
368
+ .full-screen-message-field p {
369
+ color: red;
370
+ font-size: 17px;
371
+ margin: 20px 0 3px 0
372
+ }
373
+
374
+ span.output-field-label {
375
+ border-radius: 3px;
376
+ color: #000;
377
+ margin-top: 4px;
378
+ padding: 4px 10px
379
+ }
380
+
381
+ div.colw {
382
+ float: left;
383
+ padding: 5px
384
+ }
385
+
386
+ div.edit-values-row {
387
+ float: left;
388
+ margin: 20px 10px 10px 30px;
389
+ width: 80%
390
+ }
391
+
392
+ div.end-row {
393
+ clear: both
394
+ }
395
+
396
+ div.field-table-row {
397
+ height: 20px
398
+ }
399
+
400
+ div.field-table-row-edit-source {
401
+ clear: both;
402
+ float: left
403
+ }
404
+
405
+ div.field-table-row-combined-selection {
406
+ left: -181px;
407
+ line-height: 26px;
408
+ margin: 5px;
409
+ position: relative;
410
+ width: 680px
411
+ }
412
+
413
+ div.combined-wrapper {
414
+ line-height: 26px;
415
+ width: 100%
416
+ }
417
+
418
+ div.or-selector {
419
+ line-height: 26px;
420
+ margin-top: 30px;
421
+ width: 120%
422
+ }
423
+
424
+ div.dotted-top-line {
425
+ border-top-style: dashed;
426
+ border-top-color: #ccc;
427
+ border-top-width: 1px;
428
+ margin-top: 20px
429
+ }
430
+
431
+ span.combined-field-row {
432
+ clear: left;
433
+ float: left
434
+ }
435
+
436
+ input.free-category-text-input {
437
+ width: 90%
438
+ }
439
+
440
+ div.button-wrapper {
441
+ clear: both
442
+ }
443
+
444
+ .button-primary {
445
+ margin-top: 25px !important;
446
+ margin-right: 5px !important
447
+ }
448
+
449
+ a.channel-button {
450
+ margin-right: 5px !important
451
+ }
452
+
453
+ a.tvc-btn-small {
454
+ font-size: 13px
455
+ }
456
+
457
+ a.tvc-rating-request {
458
+ color: #ffb900
459
+ }
460
+
461
+ input.feed-list-lower-button {
462
+ position: relative;
463
+ margin-bottom: 10px !important
464
+ }
465
+
466
+ div.select-control {
467
+ float: left;
468
+ margin: 0;
469
+ vertical-align: top
470
+ }
471
+
472
+ div.static-value-control {
473
+ float: left
474
+ }
475
+
476
+ #wpcontent{
477
+ height: 100%;
478
+ /*padding-left: 0 !important;*/
479
+ }
480
+
481
+ @media only screen and (min-width: 1200px){
482
+ .container{
483
+ margin-left: 8% !important;
484
+ width:auto;
485
+ }
486
+ .banner{
487
+ width:100%;
488
+ }
489
+ }
490
+ @media only screen and (min-width: 1920px){
491
+ .container{
492
+ margin-left: 6% !important;
493
+ width:auto;
494
+ }
495
+
496
+ }
css/tvc_setting-page.css ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .container{
2
+ margin-left: 8% !important;
3
+ width:auto;
4
+ }
5
+ .banner{
6
+ width:100%;
7
+ }
8
+
9
+ @media only screen and (min-width: 1920px){
10
+ .container{
11
+ margin-left: 6% !important;
12
+ width:auto;
13
+ }
14
+ }
15
+ #feed-spinner {
16
+ /*height: 200px;*/ /*height of the spinner gif +2px to fix IE8 issue */
17
+ left: 50%;
18
+ margin-left: -25px; /* half width of the spinner gif */
19
+ margin-top: -25px; /* half height of the spinner gif */
20
+ overflow: auto;
21
+ position: fixed;
22
+ text-align: center;
23
+ top: 40%;
24
+ /*width: 200px;*/ /* width of the spinner gif */
25
+ z-index: 1234;
26
+ }
27
+ #footer-left{
28
+ display: none;
29
+ }
30
+
31
+ #tvc-backups th {
32
+ padding: 15px 10px;
33
+ }
34
+
35
+ #tvc-backups .tvc-backup-filename {
36
+ width: 180px;
37
+ }
38
+
39
+ #tvc-backups .tvc-backup-file_date {
40
+ width: 100px;
41
+ }
42
+
43
+ table.smallfat {
44
+ background: #fff;
45
+ border: 1px solid #e5e5e5;
46
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
47
+ border-spacing: 0;
48
+ clear: both;
49
+ margin: 0;
50
+ }
51
+
52
+ #tvc_third_party_attr_keys {
53
+ width: 800px;
54
+ }
55
+
56
+ #tvc_notice_mailaddress {
57
+ width: 300px;
58
+ }
css/tvc_setting-page.min.css ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #feed-spinner {
2
+ /*height: 50px;*/
3
+ left: 50%;
4
+ margin-left: -25px;
5
+ margin-top: -25px;
6
+ overflow: auto;
7
+ position: fixed;
8
+ text-align: center;
9
+ top: 35%;
10
+ /*width: 50px;*/
11
+ z-index: 1234
12
+ }
13
+
14
+ #tvc-backups th {
15
+ padding: 15px 10px
16
+ }
17
+
18
+ #tvc-backups .tvc-backup-filename {
19
+ width: 180px
20
+ }
21
+
22
+ #tvc-backups .tvc-backup-file_date {
23
+ width: 100px
24
+ }
25
+
26
+ table.smallfat {
27
+ background: #fff;
28
+ border: 1px solid #e5e5e5;
29
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
30
+ border-spacing: 0;
31
+ clear: both;
32
+ margin: 0
33
+ }
34
+
35
+ #tvc_third_party_attr_keys {
36
+ width: 800px
37
+ }
38
+
39
+ #tvc_notice_mailaddress {
40
+ width: 300px
41
+ }
enhanced-ecommerce-google-analytics.php CHANGED
File without changes
google_ads_php.ini ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [GOOGLE_ADS]
2
+ name = "Google Ads"
3
+ developerToken = "R0IEth5fQ1Ac59qB2Wf8Aw"
4
+ loginCustomerId = "9704619790"
5
+
6
+ [LOGGING]
7
+ logFilePath = ""
8
+
9
+ [OAUTH2]
10
+ clientId = "854883711805-4bm7ik0lq2jcdvdk0qu8sgtd4jdc1k7o.apps.googleusercontent.com"
11
+ clientSecret = "mwgFJ25-FMPEyeNtI-TIMJIZ"
12
+ refreshToken = "1//0glkEtsa8PNuwCgYIARAAGBASNwF-L9IrBZQjIINEw2MMO_M_mRdKwoNCBwJtHXtahh5Bj4oQR01ErmhaBB2TqE68rkP8JaELISU"
13
+ developerToken = "R0IEth5fQ1Ac59qB2Wf8Aw"
14
+
images/ajax-loader.gif ADDED
Binary file
includes/application/class-feed-master.php ADDED
@@ -0,0 +1,676 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * Defines the plugin name, version, and two examples hooks for how to
6
+ * enqueue the admin-specific stylesheet and JavaScript.
7
+ *
8
+ * @package Google Product Feed Manager
9
+ * @subpackage Google Product Feed Manager/Application/Classes
10
+ * @author Chetan Rode <chetan@tatvic.com>
11
+ */
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+ if ( ! class_exists( 'TVC_Feed_Master_Class' ) ) :
17
+
18
+ /**
19
+ * Feed Master Class
20
+ *
21
+ * @since 2.0.0
22
+ */
23
+ class TVC_Feed_Master_Class {
24
+
25
+ use TVC_Processing_Support;
26
+
27
+ /**
28
+ * Contains the general feed data
29
+ *
30
+ * @var object
31
+ */
32
+ protected $_feed = null;
33
+
34
+ /**
35
+ * Contains the feed is
36
+ *
37
+ * @var string
38
+ */
39
+ protected $_feed_id;
40
+
41
+ /**
42
+ * Instantiation of global background process class
43
+ *
44
+ * @var stdClass
45
+ */
46
+ protected $_background_process;
47
+
48
+ /**
49
+ * Placeholder for the correct channel class
50
+ *
51
+ * @var stdClass
52
+ */
53
+ protected $_channel_class;
54
+
55
+ /**
56
+ * Placeholder for the TVC_Data_Class
57
+ *
58
+ * @var stdClass
59
+ */
60
+ protected $_data_class;
61
+
62
+ /**
63
+ * Path and name of the feed file
64
+ *
65
+ * @var string
66
+ */
67
+ protected $_feed_file_path;
68
+
69
+ /**
70
+ * Initiate new Feed Master class.
71
+ *
72
+ * @param string $feed_id The id of the feed. Default 0
73
+ *
74
+ * @global stdClass $background_process
75
+ *
76
+ */
77
+ public function __construct( $feed_id = '0' ) {
78
+ $query_class = new TVC_Queries();
79
+
80
+ /**
81
+ * when this construct is called from a channel class, it will not specify the feed_id so the default 0 is used
82
+ * in that case the feed_type_id will always be 1
83
+ */
84
+
85
+ $feed_type_id = $feed_id > 0 ? $query_class->get_feed_type_id( $feed_id ) : '1';
86
+
87
+ $background_class = apply_filters( 'tvc_background_class', 'TVC_Feed_Processor', $feed_type_id );
88
+
89
+ $this->_background_process = new $background_class();
90
+ $this->_data_class = new TVC_Data();
91
+ }
92
+
93
+ /**
94
+ * The update feed file function that starts the update process
95
+ *
96
+ * @param bool $silent (default true)
97
+ *
98
+ * @return string|void or false
99
+ */
100
+ public function update_feed_file( $silent = true ) {
101
+
102
+ $feed_id = TVC_Feed_Controller::get_next_id_from_feed_queue();
103
+
104
+ do_action( 'tvc_feed_process_prepared', $feed_id, $silent );
105
+
106
+ if ( false === $feed_id ) {
107
+ return false;
108
+ }
109
+
110
+ if ( $silent ) {
111
+ set_transient( 'tvc_running_silent', true, TVC_TRANSIENT_LIVE );
112
+ }
113
+
114
+ $feed_data = $this->_data_class->get_feed_data( $feed_id );
115
+
116
+ if ( ! $feed_data ) {
117
+ do_action( 'tvc_feed_generation_message', $feed_id, 'The update_feed_file function failed to get the feed data', 'ERROR' );
118
+ if ( ! $silent ) {
119
+ _e( '1428 - Failed to load the feed data, please to generate a feed in the foreground mode (see Settings page) and then try the background mode again.', 'tvc-product-feed-manager' );
120
+ }
121
+
122
+ return false;
123
+ }
124
+
125
+ /**
126
+ * store the feed data in a property
127
+ */
128
+ $this->_feed = $feed_data;
129
+
130
+ /**
131
+ * only one feed can be processing so if other feeds than the current feed are on a processing
132
+ * status, set these to an error status
133
+ */
134
+ $this->_data_class->check_for_failed_feeds( $this->_feed->feedId );
135
+
136
+ $prepare_update = $this->prepare_feed_file_update( $silent );
137
+
138
+ if ( true !== $prepare_update ) {
139
+ if ( ! $silent ) {
140
+ echo $prepare_update;
141
+ }
142
+
143
+ return false;
144
+ }
145
+
146
+ TVC_Feed_Controller::set_feed_processing_flag( true );
147
+
148
+ $this->prepare_background_process();
149
+
150
+ $this->fill_the_background_queue();
151
+
152
+ $this->activate_feed_file_update( $this->_feed->feedId );
153
+
154
+ delete_transient( 'tvc_running_silent' );
155
+
156
+ if ( ! $silent ) {
157
+ echo 'started_processing';
158
+ }
159
+ }
160
+
161
+ public function feed_status_check( $feed_id ) {
162
+ $queries_class = new TVC_Queries();
163
+
164
+ $current_feed_status = $queries_class->get_feed_status_data( $feed_id );
165
+
166
+ $current_feed_status['feed_type_name'] = tvc_list_feed_type_text()[ $current_feed_status['feed_type_id'] ];
167
+
168
+ if ( '3' === $current_feed_status['status_id'] ) { // status still processing
169
+ // get file name, including path
170
+ $file_extension = function_exists( 'get_file_type' ) ? get_file_type( $current_feed_status['channel_id'] ) : 'xml';
171
+ $feed_file = tvc_get_file_path( $current_feed_status['title'] . '.' . $file_extension );
172
+
173
+ // if it is, set the feed status to fail and change the $current_feed_status['status_id'] to 6
174
+ if ( TVC_Feed_Controller::feed_processing_failed( $feed_file ) ) {
175
+ // change the status of the feed to failed processing
176
+ $this->_data_class->update_feed_status( $feed_id, 6 ); // feed status to failed
177
+
178
+ // update the current_feed_status variable before returning
179
+ $current_feed_status['status_id'] = '6';
180
+
181
+ // clear this feed from the feed queue
182
+ TVC_Feed_Controller::remove_id_from_feed_queue( $feed_id );
183
+ TVC_Feed_Controller::set_feed_processing_flag( false );
184
+
185
+ // if running silent (automatic feed update) inform the user about the failed feed
186
+ if ( get_transient( 'tvc_running_silent' ) ) {
187
+ TVC_Email::send_feed_failed_message();
188
+ }
189
+
190
+ if ( ! TVC_Feed_Controller::feed_queue_is_empty() ) {
191
+ $next_feed_id = TVC_Feed_Controller::get_next_id_from_feed_queue();
192
+
193
+ if ( $next_feed_id ) {
194
+ // so there is another feed in the queue
195
+ $feed_master_class = new TVC_Feed_Master_Class( $next_feed_id );
196
+ $feed_master_class->update_feed_file();
197
+ }
198
+ }
199
+
200
+ do_action( 'tvc_feed_processing_failed_file_size_stopped_increasing', $feed_id, TVC_Feed_Controller::nr_ids_remaining_in_queue() );
201
+ do_action( 'tvc_register_feed_url', $feed_id, $feed_file );
202
+ }
203
+
204
+ return $current_feed_status;
205
+ } else {
206
+ return $current_feed_status;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Perform all preparations for the feed update starts
212
+ *
213
+ * @param bool $silent (default true)
214
+ *
215
+ * @return bool true if feed file has been updated successfully
216
+ */
217
+ private function prepare_feed_file_update( $silent ) {
218
+ // prepare the folder structure to support saving feed files
219
+ if ( ! file_exists( TVC_FEEDS_DIR ) ) {
220
+ TVC_Folders::make_feed_support_folder();
221
+ }
222
+
223
+ if ( ! is_writable( TVC_FEEDS_DIR ) ) {
224
+ /* translators: %s: Folder where the feeds are stored */
225
+ return sprintf( esc_html__( '1430 - %s is not a writable folder. Make sure you have admin rights to this folder.', 'tvc-product-feed-manager' ), TVC_FEEDS_DIR );
226
+ }
227
+
228
+ $initial_feed_status = $this->_feed->status;
229
+
230
+ if ( ! $this->set_properties() ) {
231
+ $message = sprintf( 'Failed to set the properties of feed %s.', $this->_feed->feedId );
232
+ do_action( 'tvc_feed_generation_message', $this->_feed->feedId, $message, 'ERROR' );
233
+
234
+ return false;
235
+ }
236
+
237
+ $this->_data_class->set_nr_of_feed_products( $this->_feed->feedId, '0' ); // 0 products
238
+ $this->_data_class->update_feed_status( $this->_feed->feedId, 3 ); // set status to "Processing"
239
+
240
+ $file_extension = function_exists( 'get_file_type' ) ? get_file_type( $this->_feed->channel ) : 'xml';
241
+
242
+ $this->_feed_file_path = tvc_get_file_path( $this->_feed->title . '.' . $file_extension );
243
+
244
+ // clear the existing feed
245
+ file_put_contents( $this->_feed_file_path, '' );
246
+
247
+ // clear the file size checker
248
+ delete_transient( 'tvc_feed_file_size' );
249
+
250
+ // clear the list of processed products @since 2.10.0.
251
+ delete_option( 'tvc_processed_products' );
252
+
253
+ $channel_class = new TVC_Channel();
254
+ $channel_name = $channel_class->get_channel_short_name( $this->_feed->channel );
255
+
256
+ $logger_message = sprintf( 'Feed %s is a %s feed stored as %s, with an original feed status %s.', $this->_feed->feedId, $channel_name, $this->_feed_file_path, $initial_feed_status );
257
+ do_action( 'tvc_feed_generation_message', $this->_feed->feedId, $logger_message );
258
+
259
+ return true;
260
+ }
261
+
262
+ /**
263
+ * Store common product metadata in the Background Process properties
264
+ */
265
+ private function prepare_background_process() {
266
+ // start counting from zero
267
+ delete_option( 'tvc_processed_products' );
268
+
269
+ $this->_background_process->set_feed_data( $this->_feed );
270
+ $this->_background_process->set_file_path( $this->_feed_file_path );
271
+ $this->_background_process->set_pre_data( $this->get_required_pre_data() );
272
+ $this->_background_process->set_channel_details( $this->get_channel_details() );
273
+ $this->_background_process->set_relations_table( $this->get_channel_to_woocommerce_field_relations() );
274
+ }
275
+
276
+ /**
277
+ * Fills the background queue
278
+ */
279
+ private function fill_the_background_queue() {
280
+ // start with an empty queue
281
+ $this->_background_process->clear_the_queue();
282
+ $sw_status_control = 30000 * 3.3;
283
+ $product_counter = 0;
284
+
285
+ // add the header to the queue
286
+ $header_string = $this->get_feed_header();
287
+ $this->_background_process->push_to_queue( array( 'file_format_line' => $header_string ) );
288
+
289
+ do {
290
+ $product_ids = $this->get_product_ids_for_feed();
291
+
292
+ // add the product ids to the queue
293
+ foreach ( $product_ids as $product_id ) {
294
+ $this->_background_process->push_to_queue( $product_id );
295
+
296
+ $product_counter++;
297
+
298
+ if ( $product_counter > $sw_status_control ) { // HWOTBERH
299
+ break;
300
+ }
301
+ }
302
+ } while ( ! empty( $product_ids ) && $sw_status_control > $product_counter );
303
+
304
+ delete_transient( 'tvc_start_product_id' );
305
+
306
+ // implement the tvc_feed_ids_in_queue filter on the queue.
307
+ $this->_background_process->apply_filter_to_queue( $this->_feed->feedId );
308
+
309
+ do_action( 'tvc_feed_queue_filled', $this->_feed->feedId, $product_counter );
310
+
311
+ $product_ids = null;
312
+
313
+ $file_extension = function_exists( 'get_file_type' ) ? get_file_type( $this->_feed->channel ) : 'xml';
314
+
315
+ // add the xml footer to the queue
316
+ if ( 'xml' === $file_extension ) {
317
+ $this->_background_process->push_to_queue(
318
+ array(
319
+ 'file_format_line' => apply_filters(
320
+ 'tvc_footer_string',
321
+ $this->_channel_class->footer(),
322
+ $this->_feed->feedId,
323
+ $this->_feed->feedTypeId
324
+ ),
325
+ )
326
+ );
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Start the feed update process in the background
332
+ *
333
+ * @param string $feed_id
334
+ */
335
+ private function activate_feed_file_update( $feed_id ) {
336
+ // save the queue data and then run the tvc-background-process dispatch function
337
+ $this->_background_process->save( $this->_feed->feedId )->dispatch( $feed_id );
338
+ }
339
+
340
+ /**
341
+ * Set all class properties
342
+ *
343
+ * @return bool
344
+ */
345
+ private function set_properties() {
346
+ // some channels do not use channels and leave the main category empty which causes issues
347
+ if ( function_exists( 'channel_uses_category' ) && ! channel_uses_category( $this->_feed->channel ) ) {
348
+ $this->_feed->mainCategory = 'No Category Required';
349
+ }
350
+
351
+ // some channels only accept category id numbers, for these channels retrieve the category numbers
352
+ if ( stripos( strrev( $this->_feed->mainCategory ), ')' ) === 0 ) {
353
+ $start = stripos( $this->_feed->mainCategory, '(' ) + 1;
354
+ $end = stripos( $this->_feed->mainCategory, '(' ) - $start;
355
+ $this->_feed->mainCategory = substr( $this->_feed->mainCategory, $start, $end );
356
+ }
357
+
358
+ // instantiate the correct channel class
359
+ $this->_channel_class = new TVC_Google_Feed_Class();
360
+ return true;
361
+ }
362
+
363
+ /**
364
+ * Returns the header that is correct for the selected feed type
365
+ *
366
+ * @return string
367
+ */
368
+ private function get_feed_header() {
369
+ $header_string = '';
370
+
371
+ if ( $this->_feed->channel ) {
372
+ $file_extension = function_exists( 'get_file_type' ) ? get_file_type( $this->_feed->channel ) : 'xml';
373
+ if ( '1' === $this->_feed->channel && ! empty( $this->_feed->feedTitle ) ) {
374
+ $header_string = $this->_channel_class->header( $this->_feed->feedTitle, $this->_feed->feedDescription );
375
+ } elseif ( 'xml' === $file_extension ) {
376
+ $header_string = $this->_channel_class->header( $this->_feed->title );
377
+ } elseif ( 'txt' === $file_extension ) {
378
+ $header_string = $this->make_tab_delimited_string_from_data_array( $this->get_active_fields() );
379
+ } elseif ( 'csv' === $file_extension ) {
380
+ $csv_sep = apply_filters( 'tvc_csv_separator', get_correct_csv_header_separator( $this->_feed->channel ) );
381
+ $string = $this->make_csv_header_string( $this->get_active_fields(), $csv_sep );
382
+ $header_string = $this->_channel_class->header( $string );
383
+ }
384
+ }
385
+
386
+ return apply_filters( 'tvc_header_string', $header_string, $this->_feed->feedId, $this->_feed->feedTypeId );
387
+ }
388
+
389
+ /**
390
+ * ALERT! has a javascript equivalent in channel-functions.js called setAttributeStatus();
391
+ */
392
+
393
+ /**
394
+ * sets the activity status of a specific attribute to true or false depending on its level
395
+ *
396
+ * @param int $field_level
397
+ * @param string $field_value
398
+ *
399
+ * @return boolean
400
+ */
401
+ protected function set_attribute_status( $field_level, $field_value ) {
402
+ if ( $field_level > 0 && $field_level < 3 ) {
403
+ return true;
404
+ }
405
+ $clean_field_value = trim( $field_value );
406
+ if ( ! empty( $clean_field_value ) ) {
407
+ return true;
408
+ }
409
+
410
+ return false;
411
+ }
412
+
413
+ /**
414
+ * Produces an array with the ids of all products that should be added into the feed
415
+ *
416
+ * @return array with ids
417
+ */
418
+ private function get_product_ids_for_feed() {
419
+ $queries_class = new TVC_Queries();
420
+
421
+ $selected_categories = apply_filters( 'tvc_selected_categories', $this->make_category_selection_string(), $this->_feed->feedId );
422
+
423
+ $include_variations = '1' === $this->_feed->includeVariations ? true : false;
424
+
425
+ $products = $queries_class->get_post_ids( $selected_categories, $include_variations );
426
+
427
+ array_filter( $products ); // just to make sure, remove all empty elements
428
+
429
+ return $products;
430
+ }
431
+
432
+ /**
433
+ * Returns a comma separated string with selected category numbers to be used as part of a query
434
+ *
435
+ * @return string
436
+ */
437
+ private function make_category_selection_string() {
438
+ $category_selection_string = '';
439
+ $category_mapping = json_decode( $this->_feed->categoryMapping );
440
+
441
+ if ( ! empty( $category_mapping ) ) {
442
+ foreach ( $category_mapping as $category ) {
443
+ $category_selection_string .= $category->shopCategoryId . ', '; // phpcs:ignore
444
+ }
445
+ }
446
+
447
+ return $category_selection_string ? substr( $category_selection_string, 0, - 2 ) : '';
448
+ }
449
+
450
+ /**
451
+ * Get all general data required to make a feed
452
+ *
453
+ * @return array
454
+ */
455
+ private function get_required_pre_data() {
456
+ // get the feed query string if the user has added to filter out specific products from the feed (Paid version only)
457
+ $feed_filter = $this->_data_class->get_filter_query( $this->_feed->feedId );
458
+
459
+ // should the feed include product variations?
460
+ $include_variations = '1' === $this->_feed->includeVariations ? true : false;
461
+
462
+ // get an array with all the field names that are required to make the feed (including the source fields, fields for the queries and fields for static data)
463
+ $required_column_names = $this->get_column_names_required_for_feed( $feed_filter );
464
+
465
+ // get the fields that are active and have to go into the feed
466
+ $active_fields = $this->get_active_fields();
467
+
468
+ $database_fields = $this->get_database_fields( $required_column_names );
469
+
470
+ return array(
471
+ 'filters' => $feed_filter,
472
+ 'include_vars' => $include_variations,
473
+ 'column_names' => $required_column_names,
474
+ 'active_fields' => $active_fields,
475
+ 'database_fields' => $database_fields,
476
+ );
477
+ }
478
+
479
+ /**
480
+ * Get category name and description name from the active channel
481
+ *
482
+ * @return array
483
+ */
484
+ private function get_channel_details() {
485
+ return function_exists( 'channel_file_text_data' ) ? channel_file_text_data( $this->_feed->channel ) :
486
+ array(
487
+ 'channel_id' => $this->_feed->channel,
488
+ 'category_name' => 'google_product_category',
489
+ 'description_name' => 'description',
490
+ );
491
+ }
492
+
493
+ /**
494
+ * returns the column names from the database that are required to get the data necessary to make the feed
495
+ *
496
+ * @param object $feed_filter_object
497
+ *
498
+ * @return array
499
+ */
500
+ private function get_column_names_required_for_feed( $feed_filter_object ) {
501
+ $support_class = new TVC_Feed_Support();
502
+
503
+ $fields = array();
504
+ $filter_columns = $support_class->get_column_names_from_feed_filter_array( $feed_filter_object );
505
+
506
+ foreach ( $this->_feed->attributes as $attribute ) {
507
+ if ( 'category_mapping' !== $attribute->fieldName ) {
508
+ $column_names = $this->get_db_column_name_from_attribute( $attribute );
509
+ foreach ( $column_names as $name ) {
510
+ if ( ! empty( $name ) ) {
511
+ array_push( $fields, $name );
512
+ }
513
+ }
514
+ }
515
+ }
516
+
517
+ $result = array_unique( array_merge( $fields, $filter_columns ) ); // remove doubles
518
+
519
+ if ( empty( $result ) ) {
520
+ tvc_write_log_file( 'Function get_column_names_required_for_feed returned zero columns' );
521
+ }
522
+
523
+ return array_merge( $result ); // and resort the result before returning
524
+ }
525
+
526
+ /**
527
+ * returns all active column names that are stored in the feed attributes
528
+ *
529
+ * @param array $attribute
530
+ *
531
+ * @return array
532
+ */
533
+ public function get_db_column_name_from_attribute( $attribute ) {
534
+ $column_names = array();
535
+
536
+ if ( property_exists( $attribute, 'isActive' ) && $attribute->isActive ) { // only select the active attributes
537
+ // source columns
538
+ if ( ! empty( $attribute->value ) ) {
539
+ $source_columns = $this->get_source_columns_from_attribute_value( $attribute->value );
540
+ $condition_columns = $this->get_condition_columns_from_attribute_value( $attribute->value );
541
+ $query_columns = $this->get_queries_columns_from_attribute_value( $attribute->value );
542
+
543
+ // TODO: I think the first $column_names array can be removed from the array_merge
544
+ $column_names = array_merge( $column_names, $source_columns, $condition_columns, $query_columns );
545
+ }
546
+
547
+ // advised sources
548
+ if ( ! empty( $attribute->advisedSource )
549
+ && strpos( $attribute->advisedSource, esc_html__( 'Fill with a static value', 'tvc-product-feed-manager' ) ) === false
550
+ && strpos( $attribute->advisedSource, esc_html__( 'Use the settings in the Merchant Center', 'tvc-product-feed-manager' ) ) === false ) {
551
+
552
+ // add the relevant advised sources
553
+ array_push( $column_names, $attribute->advisedSource );
554
+ } elseif ( property_exists( $attribute, 'advisedSource' )
555
+ && strpos( $attribute->advisedSource, esc_html__( 'Use the settings in the Merchant Center', 'tvc-product-feed-manager' ) ) !== false ) {
556
+
557
+ array_push( $column_names, 'woo_shipping' );
558
+ }
559
+ }
560
+ return $column_names;
561
+ }
562
+
563
+ /**
564
+ * extract the active fields from the attributes
565
+ *
566
+ * @return array
567
+ */
568
+ private function get_active_fields() {
569
+ $active_fields = array();
570
+
571
+ foreach ( $this->_feed->attributes as $attribute ) {
572
+ if ( $attribute->isActive && 'category_mapping' !== $attribute->fieldName ) {
573
+ $push = false;
574
+
575
+ if ( '1' === $attribute->fieldLevel ) {
576
+ $push = true;
577
+ } else {
578
+ $value_object = property_exists( $attribute, 'value' ) ? json_decode( $attribute->value ) : new stdClass();
579
+
580
+ if ( ! empty( $attribute->value ) && property_exists( $value_object, 'm' ) && property_exists( $value_object->m[0], 's' ) ) {
581
+ $push = true;
582
+ } elseif ( ! empty( $attribute->advisedSource ) ) {
583
+ $push = true;
584
+ } elseif ( ! empty( $attribute->value ) && property_exists( $value_object, 't' ) ) {
585
+ $push = true;
586
+ } elseif ( ! empty( $attribute->value ) && property_exists( $value_object, 'v' ) ) {
587
+ $push = true;
588
+ }
589
+ }
590
+
591
+ if ( true === $push ) {
592
+ array_push( $active_fields, $attribute->fieldName );
593
+ }
594
+ }
595
+ }
596
+
597
+ if ( empty( $active_fields ) ) {
598
+ tvc_write_log_file( 'Function get_active_fields returned zero fields.' );
599
+ }
600
+
601
+ return $active_fields;
602
+ }
603
+
604
+ /**
605
+ * gather all required column names from the database
606
+ *
607
+ * @param array $active_field_names
608
+ *
609
+ * @return array
610
+ */
611
+ private function get_database_fields( $active_field_names ) {
612
+ $queries_class = new TVC_Queries();
613
+
614
+ $post_fields = array();
615
+ $meta_fields = array();
616
+ $custom_fields = array();
617
+ $active_custom_fields = array();
618
+ $active_third_party_custom_fields = array();
619
+ $post_columns_string = '';
620
+
621
+ $columns_in_post_table = $queries_class->get_columns_from_post_table(); // get all post table column names
622
+ $all_custom_columns = $queries_class->get_custom_product_attributes(); // get all custom name labels
623
+ $third_party_custom_fields = $this->_data_class->get_third_party_custom_fields();
624
+
625
+ // convert the query results to an array with only the name labels
626
+ foreach ( $columns_in_post_table as $column ) {
627
+ array_push( $post_fields, $column->Field );
628
+ } // $post_fields containing the required names from the post table
629
+ foreach ( $all_custom_columns as $custom ) {
630
+ array_push( $custom_fields, $custom->attribute_name );
631
+ }
632
+ // $custom_fields containing the custom names
633
+ // filter the post columns, the meta columns and the custom columns to only those that are actually in use
634
+
635
+ foreach ( $active_field_names as $column ) {
636
+ if ( in_array( $column, $post_fields ) && 'ID' !== $column ) { // because ID is always required, it's excluded here and hard coded in the query
637
+ $post_columns_string .= $column . ', '; // here a string is required to push in the query
638
+ } elseif ( in_array( $column, $custom_fields ) ) {
639
+ array_push( $active_custom_fields, $column );
640
+ } elseif ( in_array( $column, $third_party_custom_fields ) ) {
641
+ array_push( $active_third_party_custom_fields, $column );
642
+ } else {
643
+ array_push( $meta_fields, $column );
644
+ }
645
+ }
646
+
647
+ return array(
648
+ 'post_column_string' => $post_columns_string,
649
+ 'meta_fields' => $meta_fields,
650
+ 'active_custom_fields' => $active_custom_fields,
651
+ 'third_party_custom_fields' => $third_party_custom_fields,
652
+ );
653
+ }
654
+
655
+ /**
656
+ * header text, override this function in the class-feed.php if required for a channel specific header
657
+ *
658
+ * @param string $title
659
+ *
660
+ * @return string
661
+ */
662
+ protected function header( $title ) {
663
+ return apply_filters( 'tvc_xml_header', $title );
664
+ }
665
+
666
+ /**
667
+ * footer text, override if required for a channel specific footer
668
+ *
669
+ * @return string
670
+ */
671
+ protected function footer() {
672
+ return apply_filters( 'tvc_xml_footer', '</products></rss>' );
673
+ }
674
+ }
675
+ // end of TVC_Feed_Master_Class
676
+ endif;
includes/application/class-tvc-email.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Email Class.
5
+ *
6
+ * @package Google Product Feed Manager/Application/Classes
7
+ * @version 1.2.0
8
+ * @since 2.3.0
9
+ */
10
+
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit;
13
+ }
14
+
15
+ if ( ! class_exists( 'TVC_Email' ) ) :
16
+
17
+ /**
18
+ * Email Class
19
+ */
20
+ class TVC_Email {
21
+
22
+ public static function send_feed_failed_message() {
23
+ $to = get_option( 'tvc_notice_mailaddress' ) ? get_option( 'tvc_notice_mailaddress' ) : get_bloginfo( 'admin_email' );
24
+
25
+ if ( ! $to ) {
26
+ return false;
27
+ }
28
+ $header = self::feed_failed_header();
29
+ $message = self::feed_failed_message();
30
+
31
+ return self::send( $to, $header, $message );
32
+ }
33
+
34
+ private static function feed_failed_header() {
35
+ return sprintf( 'Feed generation failure on your %s shop', get_bloginfo( 'name' ) );
36
+ }
37
+
38
+ private static function feed_failed_message() {
39
+ $message = sprintf(
40
+ 'This is an automatic message from your %s plugin. One or more product feeds on your %s shop failed to generate. Please check the status of your feeds and try to manually regenerate them again.
41
+
42
+ Should this problem persist, please open a support ticket.',
43
+ TVC_EDD_SL_ITEM_NAME,
44
+ get_bloginfo( 'name' )
45
+ );
46
+
47
+ return $message;
48
+ }
49
+
50
+ /**
51
+ * Sends the email
52
+ *
53
+ * @param string $to to address
54
+ * @param string $subject the subject
55
+ * @param string $message the message
56
+ *
57
+ * @return bool whether the mail contents was send successfully
58
+ */
59
+ private static function send( $to, $subject, $message ) {
60
+ if ( is_email( $to ) ) {
61
+ return (bool) wp_mail( $to, $subject, $message );
62
+ } else {
63
+ return false;
64
+ }
65
+ }
66
+ }
67
+ // end of TVC_Email class
68
+ endif;
includes/application/class-tvc-feed-controller.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Google Product Feed Controller Class.
5
+ *
6
+ * @package Google Product Feed Manager/Application/Classes
7
+ * @version 1.3.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Feed_Controller' ) ) :
15
+
16
+ /**
17
+ * Feed Controller Class
18
+ *
19
+ * @since 1.10.0
20
+ */
21
+ class TVC_Feed_Controller {
22
+
23
+ /**
24
+ * Removes a feed id from the feed queue
25
+ *
26
+ * @param string $feed_id
27
+ */
28
+ public static function remove_id_from_feed_queue( $feed_id ) {
29
+ $feed_queue = self::get_feed_queue();
30
+ $key = array_search( $feed_id, $feed_queue );
31
+
32
+ if ( false !== $key ) {
33
+ unset( $feed_queue[ $key ] );
34
+ $feed_queue = array_values( $feed_queue ); // resort after unset
35
+ update_site_option( 'tvc_feed_queue', $feed_queue );
36
+
37
+ if ( self::feed_queue_is_empty() ) {
38
+ tvc_clear_feed_process_data();
39
+ }
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Adds an feed id to the feed queue
45
+ *
46
+ * @param string $feed_id
47
+ */
48
+ public static function add_id_to_feed_queue( $feed_id ) {
49
+ $feed_queue = self::get_feed_queue();
50
+
51
+ if ( ! in_array( $feed_id, $feed_queue ) ) {
52
+ array_push( $feed_queue, $feed_id );
53
+ update_site_option( 'tvc_feed_queue', $feed_queue );
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Gets the next feed id from the feed queue
59
+ */
60
+ public static function get_next_id_from_feed_queue() {
61
+ $feed_queue = self::get_feed_queue();
62
+
63
+ return count( $feed_queue ) > 0 ? $feed_queue[0] : false;
64
+ }
65
+
66
+ /**
67
+ * Empties the feed queue
68
+ */
69
+ public static function clear_feed_queue() {
70
+ update_site_option( 'tvc_feed_queue', array() );
71
+ }
72
+
73
+ /**
74
+ * Checks if the feed queue is empty
75
+ *
76
+ * @return bool
77
+ */
78
+ public static function feed_queue_is_empty() {
79
+ $queue = self::get_feed_queue();
80
+
81
+ return ( count( $queue ) < 1 ) ? true : false;
82
+ }
83
+
84
+ /**
85
+ * Returns the number of product ids that are still in the queue
86
+ *
87
+ * @since 2.3.0
88
+ * @return int number of product ids still in the queue
89
+ */
90
+ public static function nr_ids_remaining_in_queue() {
91
+ $queue = self::get_feed_queue();
92
+
93
+ return count( $queue );
94
+ }
95
+
96
+ /**
97
+ * Sets the background_process_is_running option
98
+ *
99
+ * @param bool $set (default false)
100
+ */
101
+ public static function set_feed_processing_flag( $set = false ) {
102
+ $status = false !== $set ? 'true' : 'false';
103
+ update_site_option( 'tvc_background_process_is_running', $status );
104
+ }
105
+
106
+ /**
107
+ * Get the background_process_is_running status
108
+ *
109
+ * @return bool
110
+ */
111
+ public static function feed_is_processing() {
112
+ $status = get_option( 'tvc_background_process_is_running', 'false' );
113
+
114
+ return 'true' === $status ? true : false;
115
+ }
116
+
117
+ /**
118
+ * Checks if a running feed size is still growing, in order to identify a failing feed process.
119
+ *
120
+ * @since 2.2.0
121
+ *
122
+ * @param string $feed_file String with the full path and name of the feed file.
123
+ *
124
+ * @return boolean False if the feed still grows, true if it stopped growing for a certain time.
125
+ */
126
+ public static function feed_processing_failed( $feed_file ) {
127
+
128
+ if ( '' === $feed_file ) {
129
+ return null;
130
+ }
131
+
132
+ $trans = get_transient( 'tvc_feed_file_size' );
133
+
134
+ /**
135
+ * Get the feed file name that's stored in the transient or take the $feed_file parameter.
136
+ */
137
+ $trans_feed_file = $trans ? substr( $trans, strrpos( $trans, '|' ) + 1 ) : $feed_file;
138
+
139
+ /**
140
+ * if the transient was empty or the feed file in the transient is not the currently active file, reset the transient
141
+ */
142
+ if ( false === $trans || $feed_file !== $trans_feed_file ) {
143
+ $trans = '0|0|' . $feed_file;
144
+ set_transient( 'tvc_feed_file_size', $trans, TVC_TRANSIENT_LIVE );
145
+ }
146
+
147
+ /**
148
+ * Get the last data.
149
+ */
150
+ $stored = explode( '|', $trans );
151
+ $prev_feed_size = $stored[0];
152
+ $prev_feed_time_stamp = $stored[1];
153
+ $feed_file = $trans_feed_file;
154
+ $curr_feed_size = file_exists( $feed_file ) ? filesize( $feed_file ) : false;
155
+
156
+ /**
157
+ * If file does not exist, return true.
158
+ */
159
+ if ( false === $curr_feed_size ) {
160
+ delete_transient( 'tvc_feed_file_size' ); // reset the counter
161
+ return true;
162
+ }
163
+
164
+ // If the size of the feed has not grown.
165
+ if ( $curr_feed_size <= $prev_feed_size ) {
166
+ // And the delay time has passed.
167
+ if ( $prev_feed_time_stamp + apply_filters( 'tvc_delay_failed_label', TVC_DELAY_FAILED_LABEL, $feed_file ) < time() ) {
168
+ delete_transient( 'tvc_feed_file_size' ); // reset the counter
169
+ return true;
170
+ } else {
171
+ return false;
172
+ }
173
+ } else { // If the file size has increased, reset the timer and return false.
174
+ set_transient( 'tvc_feed_file_size', $curr_feed_size . '|' . time() . '|' . $feed_file, TVC_TRANSIENT_LIVE );
175
+ return false;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Updates the timer that is used as reference to monitor if a file is growing during the feed production process.
181
+ *
182
+ * @since 2.11.0
183
+ */
184
+ public static function update_file_grow_monitoring_timer() {
185
+ // Get the current monitor data.
186
+ $grow_monitor_array = get_transient( 'tvc_feed_file_size' );
187
+
188
+ if ( ! $grow_monitor_array ) { // The tvc_feed_file_size is not set in the non-background mode.
189
+ return;
190
+ }
191
+
192
+ $grow_monitor_data = explode( '|', $grow_monitor_array );
193
+
194
+ // Reset the timer part of the monitor.
195
+ set_transient( 'tvc_feed_file_size', $grow_monitor_data[0] . '|' . time() . '|' . $grow_monitor_data[2], TVC_TRANSIENT_LIVE );
196
+ }
197
+
198
+ /**
199
+ * Returns the current feed queue
200
+ *
201
+ * @return array with feed ids in the queue or an empty array
202
+ */
203
+ protected static function get_feed_queue() {
204
+ return get_site_option( 'tvc_feed_queue', array() );
205
+ }
206
+ }
207
+
208
+ endif;
includes/application/class-tvc-feed-processor.php ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Google Product Feed Controller Class.
5
+ *
6
+ * @package Google Product Feed Manager/Application/Classes
7
+ * @version 1.5.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Feed_Processor' ) ) :
15
+
16
+
17
+ /**
18
+ * Feed Processor Class
19
+ *
20
+ * @since 1.10.0
21
+ */
22
+ class TVC_Feed_Processor extends TVC_Background_Process {
23
+
24
+ use TVC_Processing_Support;
25
+ use TVC_Feed_Processor_Functions;
26
+
27
+ /**
28
+ * Action identifier
29
+ *
30
+ * @var string
31
+ */
32
+ protected $action = 'feed_generation_process';
33
+
34
+ /**
35
+ * Path to the feed file
36
+ *
37
+ * @var string
38
+ */
39
+ private $_feed_file_path;
40
+
41
+ /**
42
+ * General feed data
43
+ *
44
+ * @var stdClass
45
+ */
46
+ private $_feed_data;
47
+
48
+ /**
49
+ * Required pre feed generation data
50
+ *
51
+ * @var array
52
+ */
53
+ private $_pre_data;
54
+
55
+ /**
56
+ * Contains the channel specific main category title and description title
57
+ *
58
+ * @var array
59
+ */
60
+ private $_channel_details;
61
+
62
+ /**
63
+ * Contains the relations between WooCommerce and channel fields
64
+ *
65
+ * @var array
66
+ */
67
+ private $_relation_table;
68
+
69
+ /**
70
+ * Placeholder for the correct channel class
71
+ *
72
+ * @var string
73
+ */
74
+ private $_channel_class;
75
+
76
+ /**
77
+ * Task
78
+ *
79
+ * Starts a single feed update task
80
+ *
81
+ * @param array product
82
+ * @param stdClass feed_data
83
+ * @param string feed_file_path
84
+ * @param array pre_data
85
+ * @param array channel_details
86
+ * @param array relation_table
87
+ *
88
+ * @return boolean
89
+ */
90
+ protected function task( $task_data, $feed_data, $feed_file_path, $pre_data, $channel_details, $relation_table ) {
91
+ if ( ! $task_data ) {
92
+ return false;
93
+ }
94
+
95
+ $this->_feed_data = $feed_data;
96
+ $this->_feed_file_path = $feed_file_path;
97
+ $this->_pre_data = $pre_data;
98
+ $this->_channel_details = $channel_details;
99
+ $this->_relation_table = $relation_table;
100
+
101
+ if ( ! $this->_channel_details['channel_id'] ) {
102
+ return false;
103
+ }
104
+
105
+ // instantiate the correct channel class
106
+ $this->_channel_class = new TVC_Google_Feed_Class();
107
+
108
+ return $this->do_task( $task_data );
109
+ }
110
+
111
+ /**
112
+ * Complete
113
+ */
114
+ public function complete() {
115
+ parent::complete();
116
+
117
+ // remove the properties from the options table
118
+ $properties_key = get_site_option( 'tvc_background_process_key' );
119
+ delete_site_option( 'tvc_background_process_key' );
120
+ delete_site_option( 'file_path_' . $properties_key );
121
+ delete_site_option( 'feed_data_' . $properties_key );
122
+ delete_site_option( 'pre_data_' . $properties_key );
123
+ delete_site_option( 'channel_details_' . $properties_key );
124
+ delete_site_option( 'relations_table_' . $properties_key );
125
+
126
+ $feed_status = '0' !== $this->_feed_data->status && '3' !== $this->_feed_data->status && '4' !== $this->_feed_data->status ? $this->_feed_data->status : $this->_feed_data->baseStatusId;
127
+ $feed_title = $this->_feed_data->title . '.' . pathinfo( $this->_feed_file_path, PATHINFO_EXTENSION );
128
+ $this->register_feed_update( $this->_feed_data->feedId, $feed_title, count( $this->processed_products ), $feed_status );
129
+ $this->clear_the_queue();
130
+
131
+ // now the feed is ready to go, remove the feed id from the feed queue
132
+ TVC_Feed_Controller::remove_id_from_feed_queue( $this->_feed_data->feedId );
133
+ TVC_Feed_Controller::set_feed_processing_flag( false );
134
+
135
+ $message = sprintf( 'Completed feed %s. The feed should contain %d products and its status has been set to %s.', $this->_feed_data->feedId, count( $this->processed_products ), $feed_status );
136
+ do_action( 'tvc_feed_generation_message', $this->_feed_data->feedId, $message );
137
+ do_action( 'tvc_register_feed_url', $this->_feed_data->feedId, $this->_feed_data->url );
138
+
139
+ if ( ! TVC_Feed_Controller::feed_queue_is_empty() ) {
140
+ do_action( 'tvc_next_in_queue_feed_update_activated', $this->_feed_data->feedId );
141
+
142
+ // so there is another feed in the queue
143
+ $feed_master_class = new TVC_Feed_Master_Class( $this->_feed_data->feedId );
144
+ $feed_master_class->update_feed_file();
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Task action
150
+ * Selects the required action
151
+ *
152
+ * @param array $task_data
153
+ *
154
+ * @return boolean
155
+ */
156
+ private function do_task( $task_data ) {
157
+
158
+ if ( array_key_exists( 'product_id', $task_data ) ) {
159
+ return $this->add_product_to_feed( $task_data['product_id'] );
160
+ } elseif ( array_key_exists( 'file_format_line', $task_data ) ) {
161
+ $task_data['file_format_line'] = str_replace( '<wf-connection-string>', '<link>', $task_data['file_format_line'] );
162
+
163
+ return $this->add_file_format_line_to_feed( $task_data );
164
+ } elseif ( array_key_exists( 'error_message', $task_data ) ) {
165
+ return $this->add_error_message_to_feed( $task_data );
166
+ } else {
167
+ return false;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Ads a single product based on a product id to the feed file
173
+ *
174
+ * @param string $product_id
175
+ *
176
+ * @return boolean
177
+ */
178
+ private function add_product_to_feed( $product_id ) {
179
+ if ( ! $product_id ) {
180
+ $message = 'Add product to feed process started without product id';
181
+ do_action( 'tvc_feed_generation_message', $this->_feed_data->feedId, $message );
182
+
183
+ return false;
184
+ }
185
+
186
+ $wc_product = wc_get_product( $product_id );
187
+
188
+ if ( false === $wc_product ) {
189
+ $message = sprintf( 'Failed to get the WooCommerce product data from product with id %s.', $product_id );
190
+ do_action( 'tvc_feed_generation_message', $this->_feed_data->feedId, $message );
191
+
192
+ return false;
193
+ }
194
+
195
+ do_action( 'tvc_started_product_processing', $this->_feed_data->feedId, $product_id );
196
+
197
+ $class_data = new TVC_Data();
198
+
199
+ $product_placeholder = array();
200
+ $post_columns_query_string = $this->_pre_data['database_fields']['post_column_string'] ? substr( $this->_pre_data['database_fields']['post_column_string'], 0, - 2 ) : '';
201
+ $product_parent_id = $product_id;
202
+ $product_data = (array) $this->get_products_main_data( $product_id, $wc_product->get_parent_id(), $post_columns_query_string );
203
+
204
+ /**
205
+ * Users can use the tvc_leave_links_in_descriptions filter if they want to keep links in the product descriptions by changing the
206
+ * filter output to true. They can also target specific feeds.
207
+ *
208
+ * @since 2.6.0
209
+ */
210
+ if ( ! apply_filters( 'tvc_leave_links_in_descriptions', false, $this->_feed_data->feedId ) ) {
211
+ $this->remove_links_from_product_data_description( $product_data );
212
+ }
213
+
214
+ if ( ( $wc_product instanceof WC_Product_Variation && $this->_pre_data['include_vars'] )
215
+ || ( $wc_product instanceof WC_Product_Variable ) && $this->_pre_data['include_vars'] ) {
216
+
217
+ $product_parent_id = $wc_product->get_parent_id();
218
+
219
+ // add parent data when this item is not available in the variation
220
+ if ( $post_columns_query_string ) {
221
+ $class_data->add_parent_data( $product_data, $product_parent_id, $post_columns_query_string );
222
+ }
223
+
224
+ $wpmr_variation_data = $class_data->get_own_variation_data( $product_id );
225
+
226
+ // get correct variation data
227
+ TVC_Variations::fill_product_data_with_variation_data( $product_data, $wc_product, $wpmr_variation_data, $this->_feed_data->language );
228
+ }
229
+
230
+ $row_category = $this->get_mapped_category( $product_parent_id, $this->_feed_data->mainCategory, json_decode( $this->_feed_data->categoryMapping ) );
231
+
232
+ if ( ! $row_category ) {
233
+ $message = sprintf( 'Could not identify the correct category map for product %s', $product_id );
234
+ do_action( 'tvc_feed_generation_message', $this->_feed_data->feedId, $message );
235
+
236
+ return false;
237
+ }
238
+
239
+ $row_filtered = $this->is_product_filtered( $this->_pre_data['filters'], $product_data );
240
+
241
+ // only process the product if its not filtered out
242
+ if ( ! $row_filtered ) {
243
+ // for each row loop through each field
244
+ foreach ( $this->_pre_data['active_fields'] as $field ) {
245
+ $field_meta_data = $this->get_meta_data_from_specific_field( $field, $this->_feed_data->attributes );
246
+
247
+ // get the field data based on the user settings
248
+ $feed_object = $this->process_product_field(
249
+ $product_data,
250
+ $field_meta_data,
251
+ $this->_channel_details['category_name'],
252
+ $row_category,
253
+ $this->_feed_data->language,
254
+ $this->_relation_table
255
+ );
256
+
257
+ $key = key( $feed_object );
258
+
259
+ // for an xml file only add fields that contain data
260
+ if ( ( ! empty( $feed_object[ $key ] ) || '0' === $feed_object[ $key ] ) || 'xml' !== pathinfo( $this->_feed_file_path, PATHINFO_EXTENSION ) ) {
261
+
262
+ // catch the DraftImages key for the Ricardo.ch channel
263
+ if ( 'DraftImages' !== $key ) {
264
+ $product_placeholder[ $key ] = $feed_object[ $key ];
265
+ } else {
266
+ $support_class = new TVC_Feed_Support();
267
+ $support_class->process_ricardo_draftimages( $product_placeholder, $feed_object[ $key ] );
268
+ }
269
+ }
270
+ }
271
+ } else {
272
+ $message = sprintf( 'Product %s is filtered out', $product_id );
273
+ do_action( 'tvc_feed_generation_message', $this->_feed_data->feedId, $message );
274
+
275
+ return 'filtered';
276
+ }
277
+
278
+ if ( $product_placeholder ) {
279
+ // The tvc_feed_item_value filter allows users to modify the data that goes into the feed. The $data variable contains an array
280
+ // with all the data that goes into the feed, with the items name as key
281
+ $product_placeholder = apply_filters( 'tvc_feed_item_value', $product_placeholder, $this->_feed_data->feedId, $product_id );
282
+
283
+ return $this->write_product_object( $product_placeholder, $this->_feed_data->feedId, $product_id );
284
+ } else {
285
+ return false;
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Appends a product to the feed
291
+ *
292
+ * @param array $feed_product_object
293
+ * @param string $feed_id
294
+ * @param string $product_id
295
+ *
296
+ * @return string product added or boolean false
297
+ */
298
+ private function write_product_object( $feed_product_object, $feed_id, $product_id ) {
299
+ /**
300
+ * @since 2.3.0
301
+ */
302
+ do_action( 'tvc_add_product_to_feed', $feed_id, $product_id );
303
+
304
+ $product_text = $this->generate_feed_text( $feed_product_object );
305
+
306
+ if ( false === file_put_contents( $this->_feed_file_path, $product_text, FILE_APPEND ) ) {
307
+ tvc_write_log_file( sprintf( 'Could not write product %s to the feed', $product_id ) );
308
+
309
+ return false;
310
+ } else {
311
+ return 'product added';
312
+ }
313
+ }
314
+
315
+ /**
316
+ * convert the feed data of a single product into xml or csv text depending on the channel
317
+ *
318
+ * @param array $data
319
+ *
320
+ * @return string
321
+ */
322
+ protected function generate_feed_text( $data ) {
323
+ switch ( pathinfo( $this->_feed_file_path, PATHINFO_EXTENSION ) ) {
324
+ case 'xml':
325
+ return $this->convert_data_to_xml( $data, $this->_channel_details['category_name'], $this->_channel_details['description_name'], $this->_channel_details['channel_id'] );
326
+
327
+ case 'txt':
328
+ return $this->convert_data_to_txt( $data );
329
+
330
+ case 'csv':
331
+ $csv_sep = apply_filters( 'tvc_csv_separator', get_correct_csv_separator( $this->_channel_details['channel_id'] ) );
332
+
333
+ return $this->convert_data_to_csv( $data, $this->_pre_data['active_fields'], $csv_sep );
334
+
335
+ case 'tsv':
336
+ return $this->convert_data_to_tsv( $data );
337
+ }
338
+ return '';
339
+ }
340
+ }
341
+ endif;
includes/application/class-tvc-feed-queries.php ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Google Feed Queries Class.
5
+ *
6
+ * @package Google Product Feed Manager/Application/Classes
7
+ * @version 2.1.1
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Feed_Queries' ) ) :
15
+
16
+ /**
17
+ * Feed Queries Class
18
+ */
19
+ class TVC_Feed_Queries {
20
+
21
+ /**
22
+ * @param $query
23
+ * @param $value
24
+ * @return bool
25
+ */
26
+ public function includes_query( $query, $value ) {
27
+ return $query[3] && strpos( strtolower( $value ), strtolower( trim( $query[3] ) ) ) !== false ? false : true;
28
+ }
29
+
30
+ /**
31
+ * @param $query
32
+ * @param $value
33
+ * @return bool
34
+ */
35
+ public function does_not_include_query( $query, $value ) {
36
+ return $query[3] && strpos( strtolower( $value ), strtolower( trim( $query[3] ) ) ) === false ? false : true;
37
+ }
38
+
39
+ /**
40
+ * @param $query
41
+ * @param $value
42
+ * @return bool
43
+ */
44
+ public function is_equal_to_query( $query, $value ) {
45
+ return strtolower( $value ) === strtolower( trim( $query[3] ) ) ? false : true;
46
+ }
47
+
48
+ /**
49
+ * @param $query
50
+ * @param $value
51
+ * @return bool
52
+ */
53
+ public function is_not_equal_to_query( $query, $value ) {
54
+ return strtolower( $value ) !== strtolower( trim( $query[3] ) ) ? false : true;
55
+ }
56
+
57
+ /**
58
+ * @param $value
59
+ * @return bool
60
+ */
61
+ public function is_empty( $value ) {
62
+ if ( ! is_array( $value ) ) {
63
+ $value = trim( $value );
64
+ }
65
+
66
+ return empty( $value ) ? false : true;
67
+ }
68
+
69
+ /**
70
+ * @param $value
71
+ * @return bool
72
+ */
73
+ public function is_not_empty_query( $value ) {
74
+ if ( ! is_array( $value ) ) {
75
+ $value = trim( $value );
76
+ }
77
+
78
+ return ! empty( $value ) ? false : true;
79
+ }
80
+
81
+ /**
82
+ * @param $query
83
+ * @param $value
84
+ * @return bool
85
+ */
86
+ public function starts_with_query( $query, $value ) {
87
+ if ( ! empty( $value ) && strrpos( strtolower( $value ), strtolower( trim( $query[3] ) ), - strlen( $value ) ) !== false ) {
88
+ return false;
89
+ } else {
90
+ return true;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * @param $query
96
+ * @param $value
97
+ * @return bool
98
+ */
99
+ public function does_not_start_with_query( $query, $value ) {
100
+ if ( empty( $value ) || strrpos( strtolower( $value ), strtolower( trim( $query[3] ) ), - strlen( $value ) ) === false ) {
101
+ return false;
102
+ } else {
103
+ return true;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * @param $query
109
+ * @param $value
110
+ * @return bool
111
+ */
112
+ public function ends_with_query( $query, $value ) {
113
+ $search_string = trim( $query[3] );
114
+ $value_length = strlen( $value );
115
+
116
+ if ( ! empty( $value ) && ( $value_length - strlen( $search_string ) ) >= 0 && strpos( $value, $search_string, $value_length ) !== false ) {
117
+ return false;
118
+ } else {
119
+ return true;
120
+ }
121
+ }
122
+
123
+ /**
124
+ * @param $query
125
+ * @param $value
126
+ * @return bool
127
+ */
128
+ public function does_not_end_with_query( $query, $value ) {
129
+ $search_string = trim( $query[3] );
130
+ $value_length = strlen( $value );
131
+
132
+ if ( ! empty( $value ) && ( $value_length - strlen( $search_string ) ) >= 0 && strpos( $value, $search_string, $value_length ) !== false ) {
133
+ return true;
134
+ } else {
135
+ return false;
136
+ }
137
+ }
138
+
139
+ /**
140
+ * @param $query
141
+ * @param $value
142
+ * @return bool
143
+ */
144
+ public function is_greater_than_query( $query, $value ) {
145
+ $data_nr = $this->convert_to_us_notation( trim( $value ) );
146
+ $condition_nr = $this->convert_to_us_notation( trim( $query[3] ) );
147
+
148
+ if ( is_numeric( $data_nr ) && is_numeric( $condition_nr ) ) {
149
+ return (float) $data_nr > (float) $condition_nr ? false : true;
150
+ } else {
151
+ return false;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * @param $query
157
+ * @param $value
158
+ * @return bool
159
+ */
160
+ public function is_greater_or_equal_to_query( $query, $value ) {
161
+ $data_nr = $this->convert_to_us_notation( trim( $value ) );
162
+ $condition_nr = $this->convert_to_us_notation( trim( $query[3] ) );
163
+
164
+ if ( is_numeric( $data_nr ) && is_numeric( trim( $condition_nr ) ) ) {
165
+ return (float) $data_nr >= (float) $condition_nr ? false : true;
166
+ } else {
167
+ return false;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * @param $query
173
+ * @param $value
174
+ * @return bool
175
+ */
176
+ public function is_smaller_than_query( $query, $value ) {
177
+ $data_nr = $this->convert_to_us_notation( trim( $value ) );
178
+ $condition_nr = $this->convert_to_us_notation( trim( $query[3] ) );
179
+
180
+ if ( is_numeric( $data_nr ) && is_numeric( $condition_nr ) ) {
181
+ return (float) $data_nr < (float) $condition_nr ? false : true;
182
+ } else {
183
+ return false;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * @param $query
189
+ * @param $value
190
+ * @return bool
191
+ */
192
+ public function is_smaller_or_equal_to_query( $query, $value ) {
193
+ $data_nr = $this->convert_to_us_notation( trim( $value ) );
194
+ $condition_nr = $this->convert_to_us_notation( trim( $query[3] ) );
195
+
196
+ if ( is_numeric( $data_nr ) && is_numeric( $condition_nr ) ) {
197
+ return (float) $data_nr <= (float) $condition_nr ? false : true;
198
+ } else {
199
+ return false;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * @param $query
205
+ * @param $value
206
+ * @return bool
207
+ */
208
+ public function is_between_query( $query, $value ) {
209
+ $data_nr = $this->convert_to_us_notation( trim( $value ) );
210
+ $condition_nr_low = $this->convert_to_us_notation( trim( $query[3] ) );
211
+ $condition_nr_high = $this->convert_to_us_notation( trim( $query[5] ) );
212
+
213
+ if ( is_numeric( $data_nr ) && is_numeric( $condition_nr_low ) && is_numeric( $condition_nr_high ) ) {
214
+ if ( (float) $data_nr > (float) $condition_nr_low && (float) $data_nr < (float) $condition_nr_high ) {
215
+ return false;
216
+ } else {
217
+ return true;
218
+ }
219
+ } else {
220
+ return false;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * @param $current_value
226
+ * @return mixed
227
+ */
228
+ private function convert_to_us_notation( $current_value ) {
229
+ $decimal_sep = get_option( 'woocommerce_price_decimal_sep' );
230
+ $thousands_sep = get_option( 'woocommerce_price_thousand_sep' );
231
+
232
+ if ( ! preg_match( '/[a-zA-Z]/', $current_value ) ) { // only remove the commas if the current value has no letters
233
+ $no_thousands_sep = str_replace( $thousands_sep, '', $current_value );
234
+
235
+ return ',' === $decimal_sep ? str_replace( ',', '.', $no_thousands_sep ) : $no_thousands_sep;
236
+ } else {
237
+ return $current_value;
238
+ }
239
+ }
240
+ }
241
+ // end of TVC_Feed_Queries_Class
242
+
243
+ endif;
includes/application/class-tvc-feed-support.php ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Product Feed Support Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Application/Classes
7
+ * @version 1.1.2
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Feed_Support' ) ) :
15
+
16
+ /**
17
+ * Feed Support Class
18
+ */
19
+ class TVC_Feed_Support {
20
+
21
+ /**
22
+ * @param $query_object
23
+ * @return bool|mixed
24
+ */
25
+ public function get_query_string_from_query_object( $query_object ) {
26
+ // TODO: There's probably a better way to do this!
27
+ foreach ( $query_object as $value ) {
28
+ return $value;
29
+ }
30
+
31
+ return false;
32
+ }
33
+
34
+ /**
35
+ * @param $feed_name
36
+ * @param $relations_table
37
+ * @return mixed|string
38
+ */
39
+ public function find_relation( $feed_name, $relations_table ) {
40
+ $result = '';
41
+
42
+ foreach ( $relations_table as $relation ) {
43
+ if ( $relation['field'] === $feed_name ) {
44
+ $result = $relation['db'];
45
+ break;
46
+ }
47
+ }
48
+
49
+ $relations_table = null;
50
+
51
+ return $result;
52
+ }
53
+
54
+ /**
55
+ * @param $term_id
56
+ * @param $category_mapping
57
+ * @return bool|int
58
+ */
59
+ public function category_is_selected( $term_id, $category_mapping ) {
60
+ for ( $i = 0; $i < count( $category_mapping ); $i ++ ) {
61
+ if ( (string) $term_id === $category_mapping[ $i ]->shopCategoryId ) {
62
+ return $i;
63
+ }
64
+ }
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * @param $query_split
70
+ * @param $product_data
71
+ * @return bool
72
+ */
73
+ public function check_query_result_on_specific_row( $query_split, $product_data ) {
74
+ $queries_class = new TVC_Feed_Queries;
75
+ $current_data = key_exists( $query_split[1], $product_data ) ? $product_data[ $query_split[1] ] : '';
76
+
77
+ // the following attributes can or will contain an array so surpress the type warning for these attributes
78
+ $suppress_type_warning_attributes = apply_filters(
79
+ 'tvc_suppress_type_warning_attributes',
80
+ array(
81
+ '_wp_attachement_metadata',
82
+ )
83
+ );
84
+
85
+ if ( is_array( $current_data ) && ! in_array( $query_split[1], $suppress_type_warning_attributes ) ) { // A user had this once where he had an attribute that only showed "Array()" as value
86
+ $product_id = key_exists( 'ID', $product_data ) ? $product_data['ID'] : 'unknown';
87
+ $product_title = key_exists( 'post_title', $product_data ) ? $product_data['post_title'] : 'unknown';
88
+
89
+ $error_message = "There is something wrong with the '" . $query_split[1] . "' attribute of product '$product_title' with id $product_id. It seems to be of a wrong type.";
90
+
91
+ tvc_write_log_file( $error_message, 'debug' );
92
+
93
+ $current_data = $current_data[0];
94
+ }
95
+
96
+ $result = true;
97
+
98
+ switch ( $query_split[2] ) {
99
+ case 0: // includes
100
+ $result = $queries_class->includes_query( $query_split, $current_data );
101
+ break;
102
+
103
+ case 1: // does not include
104
+ $result = $queries_class->does_not_include_query( $query_split, $current_data );
105
+ break;
106
+
107
+ case 2: // is equal to
108
+ $result = $queries_class->is_equal_to_query( $query_split, $current_data );
109
+ break;
110
+
111
+ case 3: // is not equal to
112
+ $result = $queries_class->is_not_equal_to_query( $query_split, $current_data );
113
+ break;
114
+
115
+ case 4: // is empty
116
+ $result = $queries_class->is_empty( $current_data );
117
+ break;
118
+
119
+ case 5: // is not empty
120
+ $result = $queries_class->is_not_empty_query( $current_data );
121
+ break;
122
+
123
+ case 6: // starts with
124
+ $result = $queries_class->starts_with_query( $query_split, $current_data );
125
+ break;
126
+
127
+ case 7: // does not start with
128
+ $result = $queries_class->does_not_start_with_query( $query_split, $current_data );
129
+ break;
130
+
131
+ case 8: // ends with
132
+ $result = $queries_class->ends_with_query( $query_split, $current_data );
133
+ break;
134
+
135
+ case 9: // does not end with
136
+ $result = $queries_class->does_not_end_with_query( $query_split, $current_data );
137
+ break;
138
+
139
+ case 10: // is greater than
140
+ $result = $queries_class->is_greater_than_query( $query_split, $current_data );
141
+ break;
142
+
143
+ case 11: // is greater or equal to
144
+ $result = $queries_class->is_greater_or_equal_to_query( $query_split, $current_data );
145
+ break;
146
+
147
+ case 12: // is smaller than
148
+ $result = $queries_class->is_smaller_than_query( $query_split, $current_data );
149
+ break;
150
+
151
+ case 13: // is smaller or equal to
152
+ $result = $queries_class->is_smaller_or_equal_to_query( $query_split, $current_data );
153
+ break;
154
+
155
+ case 14: // is between
156
+ $result = $queries_class->is_between_query( $query_split, $current_data );
157
+ break;
158
+
159
+ default:
160
+ break;
161
+ }
162
+
163
+ return $result;
164
+ }
165
+
166
+ /**
167
+ * @param $current_value
168
+ * @param $edit_string
169
+ * @param $combination_string
170
+ * @param $combined_data_elements
171
+ * @param $feed_language
172
+ * @return float|int|mixed|string
173
+ */
174
+ public function edit_value( $current_value, $edit_string, $combination_string, $combined_data_elements, $feed_language ) {
175
+ $value_editors = new TVC_Feed_Value_Editors;
176
+
177
+ $query_split = explode( '#', $edit_string );
178
+
179
+ switch ( $query_split[1] ) {
180
+ case 'change nothing':
181
+ $result = $current_value;
182
+ break;
183
+
184
+ case 'overwrite':
185
+ $result = $value_editors->overwrite_value( $query_split );
186
+ break;
187
+
188
+ case 'replace':
189
+ $result = $value_editors->replace_value( $query_split, $current_value );
190
+ break;
191
+
192
+ case 'remove':
193
+ $result = $value_editors->remove_value( $query_split, $current_value );
194
+ break;
195
+
196
+ case 'add prefix':
197
+ $result = $value_editors->add_prefix_value( $query_split, $current_value );
198
+ break;
199
+
200
+ case 'add suffix':
201
+ $result = $value_editors->add_suffix_value( $query_split, $current_value );
202
+ break;
203
+
204
+ case 'recalculate':
205
+ $result = $value_editors->recalculate_value( $query_split, $current_value, $combination_string, $combined_data_elements, $feed_language );
206
+ break;
207
+
208
+ case 'convert to child-element':
209
+ $result = $value_editors->convert_to_element( $query_split, $current_value );
210
+ break;
211
+
212
+ default:
213
+ $result = false;
214
+ break;
215
+ }
216
+
217
+ return $result;
218
+ }
219
+
220
+ /**
221
+ * @param $feed_filter_array
222
+ * @return array
223
+ */
224
+ public function get_column_names_from_feed_filter_array( $feed_filter_array ) {
225
+ $empty_array = array();
226
+ $filters = $feed_filter_array ? json_decode( $feed_filter_array[0]['meta_value'] ) : $empty_array;
227
+ $column_names = array();
228
+
229
+ foreach ( $filters as $filter ) {
230
+ $query_string = $this->get_query_string_from_query_object( $filter );
231
+ $query_parts = explode( '#', $query_string );
232
+
233
+ array_push( $column_names, $query_parts[1] );
234
+ }
235
+
236
+ return $column_names;
237
+ }
238
+
239
+ /**
240
+ * makes a unique feed for a copy of an existing feed
241
+ *
242
+ * @param string $current_feed_name
243
+ *
244
+ * @return string
245
+ */
246
+ public function next_unique_feed_name( $current_feed_name ) {
247
+ $queries_class = new TVC_Queries();
248
+
249
+ $title_end = explode( '_', $current_feed_name );
250
+ $end_nr = end( $title_end );
251
+
252
+ if ( count( $title_end ) > 1 && is_numeric( $end_nr ) ) {
253
+ $new_title = substr_replace( $current_feed_name, ( $end_nr + 1 ), - strlen( $end_nr ) );
254
+ } else {
255
+ $new_title = $current_feed_name . '_1';
256
+ $end_nr = '1';
257
+ }
258
+
259
+ // increase the end number of the title already exists
260
+ while ( $queries_class->title_exists( $new_title ) ) {
261
+ $new_title = substr_replace( $new_title, ( $end_nr + 1 ), - strlen( $end_nr ) );
262
+ $end_nr ++;
263
+ }
264
+
265
+ return $new_title;
266
+ }
267
+
268
+ /**
269
+ * Adds multiple single draft image urls to the product, specific for the Ricardo.ch channel
270
+ *
271
+ * @since 1.9.0
272
+ *
273
+ * @param array $product
274
+ * @param array $images
275
+ */
276
+ public function process_ricardo_draftimages( &$product, $images ) {
277
+ for ( $i = 0; $i < 10; $i ++ ) {
278
+ $product["DraftImages[$i]"] = isset( $images[ $i ] ) ? $images[ $i ] : '';
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Corrects issues where the active list is not the same as the data keys
284
+ *
285
+ * @since 1.9.0
286
+ *
287
+ * @param array $active_fields
288
+ */
289
+ public function correct_active_fields_list( &$active_fields ) {
290
+ // correct for draft images in Ricardo.ch feed
291
+ if ( ( $key = array_search( 'DraftImages', $active_fields ) ) !== false ) {
292
+ unset( $active_fields[ $key ] );
293
+ for ( $i = 0; $i < 10; $i ++ ) {
294
+ array_push( $active_fields, "DraftImages[$i]" );
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ // end of TVC_Feed_Support
301
+ endif;
includes/application/class-tvc-feed-value-editors.php ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Product Feed Value Editors Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Application/Classes
7
+ * @version 1.6.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+
15
+ if ( ! class_exists( 'TVC_Feed_Value_Editors' ) ) :
16
+
17
+ /**
18
+ * Feed Value Editors Class
19
+ */
20
+ class TVC_Feed_Value_Editors {
21
+
22
+ /**
23
+ * @param $condition
24
+ * @return mixed
25
+ */
26
+ public function overwrite_value( $condition ) {
27
+ return $condition[2];
28
+ }
29
+
30
+ /**
31
+ * @param $condition
32
+ * @param $current_value
33
+ * @return mixed
34
+ */
35
+ public function replace_value( $condition, $current_value ) {
36
+ return str_replace( $condition[2], $condition[3], $current_value );
37
+ }
38
+
39
+ /**
40
+ * @param $element_name
41
+ * @param $current_value
42
+ * @return string
43
+ */
44
+ public function convert_to_element( $element_name, $current_value ) {
45
+ return "!sub:$element_name[2]|$current_value";
46
+ }
47
+
48
+ /**
49
+ * @param $condition
50
+ * @param $current_value
51
+ * @return mixed
52
+ */
53
+ public function remove_value( $condition, $current_value ) {
54
+ return str_replace( $condition[2], '', $current_value );
55
+ }
56
+
57
+ /**
58
+ * @param $condition
59
+ * @param $current_value
60
+ * @return string
61
+ */
62
+ public function add_prefix_value( $condition, $current_value ) {
63
+ return $condition[2] . $current_value;
64
+ }
65
+
66
+ /**
67
+ * @param $condition
68
+ * @param $current_value
69
+ * @return string
70
+ */
71
+ public function add_suffix_value( $condition, $current_value ) {
72
+ return $current_value . $condition[2];
73
+ }
74
+
75
+ /**
76
+ * @param $condition
77
+ * @param $current_value
78
+ * @param $combination_string
79
+ * @param $combined_data_elements
80
+ * @param $feed_language
81
+ * @return float|int|mixed|string
82
+ */
83
+ public function recalculate_value( $condition, $current_value, $combination_string, $combined_data_elements, $feed_language ) {
84
+ if ( ! $combination_string ) {
85
+ $values = $this->make_recalculate_inputs( $current_value, $condition[3] );
86
+ $calculated_value = $this->recalculate( $condition[2], floatval( $values['main_val'] ), floatval( $values['sub_val'] ) );
87
+
88
+ return $this->is_money_value( $current_value ) ? tvc_prep_money_values( $calculated_value, $feed_language ) : $calculated_value;
89
+
90
+ } else {
91
+ if ( count( $combined_data_elements ) > 1 ) {
92
+ $combined_string_values = array();
93
+
94
+ foreach ( $combined_data_elements as $element ) {
95
+ $values = $this->make_recalculate_inputs( $element, $condition[3] );
96
+
97
+ $reg_match = '/[0-9.,]/'; // only numbers and decimals
98
+
99
+ $calculated_value = preg_match( $reg_match, $values['main_val'] ) && preg_match( $reg_match, $values['sub_val'] ) ?
100
+ $this->recalculate( $condition[2], floatval( $values['main_val'] ), floatval( $values['sub_val'] ) ) : $values['main_val'];
101
+
102
+ $end_value = $this->is_money_value( $element ) ? tvc_prep_money_values( $calculated_value, $feed_language ) : $calculated_value;
103
+
104
+ array_push( $combined_string_values, $end_value );
105
+ }
106
+
107
+ return $this->make_combined_result_string( $combined_string_values, $combination_string );
108
+ } else {
109
+ return '';
110
+ }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * @param $values
116
+ * @param $combination_string
117
+ * @return mixed|string
118
+ */
119
+ private function make_combined_result_string( $values, $combination_string ) {
120
+ $separators = $this->combination_separators();
121
+ $result_string = $values[0];
122
+
123
+ $combinations = explode( '|', $combination_string );
124
+
125
+ for ( $i = 1; $i < count( $combinations ); $i ++ ) {
126
+ $sep = explode( '#', $combinations[ $i ] );
127
+ $result_string .= $separators[ (int) $sep[0] ];
128
+ $result_string .= $values[ $i ];
129
+ }
130
+ return $result_string;
131
+ }
132
+
133
+ public function combination_separators() {
134
+ return array(
135
+ '',
136
+ ' ',
137
+ ', ',
138
+ '.',
139
+ '; ',
140
+ ':',
141
+ '-',
142
+ '/',
143
+ '\\',
144
+ '||',
145
+ '_',
146
+ ); // should correspond with tvc_getCombinedSeparatorList()
147
+ }
148
+
149
+ /**
150
+ * @param $current_value
151
+ * @param $current_sub_value
152
+ * @return array
153
+ */
154
+ private function make_recalculate_inputs( $current_value, $current_sub_value ) {
155
+ if ( ! preg_match( '/[a-zA-Z]/', $current_value ) ) { // only remove the commas if the current value has no letters
156
+ $main_value = tvc_number_format_parse( $current_value );
157
+ } else {
158
+ $main_value = $current_value;
159
+ }
160
+
161
+ $sub_value = tvc_number_format_parse( $current_sub_value );
162
+
163
+ return array(
164
+ 'main_val' => $main_value,
165
+ 'sub_val' => $sub_value,
166
+ );
167
+ }
168
+
169
+ /**
170
+ * @param $meta_data
171
+ * @param $feed_language
172
+ * @return string
173
+ */
174
+ public function prep_meta_values( $meta_data, $feed_language ) {
175
+ $result = $meta_data->meta_value;
176
+
177
+ if ( tvc_meta_key_is_money( $meta_data->meta_key ) ) {
178
+ $result = tvc_prep_money_values( $result, $feed_language );
179
+ }
180
+
181
+ return is_string( $result ) ? trim( $result ) : $result;
182
+ }
183
+
184
+ /**
185
+ * Checks is a certain value could be a money value or not
186
+ *
187
+ * @param int or string $value
188
+ *
189
+ * @return boolean true if it is a money value
190
+ */
191
+ public function is_money_value( $value ) {
192
+ // replace a comma separator with a period so it can be recognized as numeric
193
+ $possible_number = tvc_number_format_parse( $value );
194
+
195
+ // if its not a number it cannot be a money value
196
+ if ( ! is_numeric( $possible_number ) ) {
197
+ return false;
198
+ }
199
+
200
+ $last_pos = strrpos( (string) $value, get_option( 'woocommerce_price_decimal_sep' ) );
201
+ $value_length = strlen( (string) $value );
202
+
203
+ $actual_decimals = $value_length - $last_pos - 1;
204
+
205
+ return absint( get_option( 'woocommerce_price_num_decimals', 2 ) ) === $actual_decimals ? true : false;
206
+ }
207
+
208
+ /**
209
+ * @param $math
210
+ * @param $main_value
211
+ * @param $sub_value
212
+ * @return float|int|string
213
+ */
214
+ private function recalculate( $math, $main_value, $sub_value ) {
215
+ $result = 0;
216
+
217
+ if ( is_numeric( $main_value ) && is_numeric( $sub_value ) ) {
218
+ switch ( $math ) {
219
+ case 'add':
220
+ $result = $main_value + $sub_value;
221
+ break;
222
+
223
+ case 'subtract':
224
+ $result = $main_value - $sub_value;
225
+ break;
226
+
227
+ case 'multiply':
228
+ $result = $main_value * $sub_value;
229
+ break;
230
+
231
+ case 'divide':
232
+ $result = 0 !== $sub_value ? $main_value / $sub_value : 0;
233
+ break;
234
+ }
235
+ }
236
+ return $result;
237
+ }
238
+ }
239
+ // End of TVC_Feed_Value_Editors class
240
+ endif;
includes/application/class-tvc-schedules.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Product Schedules Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Application/Classes
7
+ * @version 1.1.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+
15
+ if ( ! class_exists( 'TVC_Schedules' ) ) :
16
+
17
+ /**
18
+ * Feed Schedules Class
19
+ */
20
+ class TVC_Schedules {
21
+
22
+ /* --------------------------------------------------------------------------------------------------*
23
+ * Public functions
24
+ * -------------------------------------------------------------------------------------------------- */
25
+
26
+ /**
27
+ * Initiates the automatic feed updates
28
+ */
29
+ public function update_active_feeds() {
30
+ $data_class = new TVC_Data();
31
+
32
+ $current_timestamp = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
33
+ $active_feeds_schedules = $data_class->get_schedule_data();
34
+ $failed_feeds = $data_class->get_failed_feeds();
35
+ $active_feed_id = null;
36
+
37
+ // update scheduled feeds
38
+ foreach ( $active_feeds_schedules as $schedule ) {
39
+ $active_feed_id = $schedule['product_feed_id'];
40
+ $update_time = $this->new_activation_time( $schedule['updated'], $schedule['schedule'] );
41
+
42
+ // activate the feed update when the update time is reached
43
+ if ( $update_time < $current_timestamp ) {
44
+ TVC_Feed_Controller::add_id_to_feed_queue( $schedule['product_feed_id'] );
45
+
46
+ $data_class->update_feed_status( $schedule['product_feed_id'], 4 ); // feed status to waiting in queue
47
+ }
48
+ }
49
+
50
+ // if there is no feed processing in progress and the feed queue is not empty, start updating the current feed
51
+ if ( ! TVC_Feed_Controller::feed_queue_is_empty() && ! TVC_Feed_Controller::feed_is_processing() ) {
52
+ do_action( 'tvc_automatic_feed_update_triggered', $active_feed_id );
53
+ $feed_master_class = new TVC_Feed_Master_Class( $active_feed_id );
54
+ $feed_master_class->update_feed_file( true );
55
+ }
56
+
57
+ // update previously failed feeds
58
+ if ( 'true' === get_option( 'tvc_auto_feed_fix' ) ) {
59
+ foreach ( $failed_feeds as $failed_feed ) {
60
+ TVC_Feed_Controller::add_id_to_feed_queue( $failed_feed['product_feed_id'] );
61
+
62
+ // if there is no feed processing in progress, start updating the current feed
63
+ if ( ! TVC_Feed_Controller::feed_is_processing() ) {
64
+ do_action( 'tvc_automatic_feed_prepare_update_triggered', $active_feed_id );
65
+
66
+ $feed_master_class = new TVC_Feed_Master_Class( $active_feed_id );
67
+ $feed_master_class->update_feed_file( true );
68
+ } else {
69
+ $data_class->update_feed_status( $failed_feed['product_feed_id'], 4 ); // feed status to waiting in queue
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ /* --------------------------------------------------------------------------------------------------*
76
+ * Private functions
77
+ * -------------------------------------------------------------------------------------------------- */
78
+
79
+ /**
80
+ * Returns the time at which the feed should be updated
81
+ *
82
+ * @param string $last_update time string with the data and time the feed has been update last
83
+ * @param string $update_frequency registered update frequency
84
+ *
85
+ * @return string Containing the time in Y-m-d H:i:s format
86
+ */
87
+ private function new_activation_time( $last_update, $update_frequency ) {
88
+ $update_split = explode( ':', $update_frequency );
89
+
90
+ $hrs = isset( $update_split[1] ) ? $update_split[1] : '00';
91
+ $min = isset( $update_split[2] ) ? $update_split[2] : '00';
92
+ $freq = isset( $update_split[3] ) ? $update_split[3] : 1;
93
+
94
+ $planned_update_time = $hrs . ':' . $min . ':00';
95
+ $planned_update_time = '00:00:00' !== $planned_update_time ? $planned_update_time : '23:59:00';
96
+ $last_update_time = date( 'H:i:s', strtotime( $last_update ) );
97
+ $days = $update_split[0] <= 1
98
+ && ( ( strtotime( $last_update_time ) <= strtotime( $planned_update_time ) )
99
+ || ( '00' === $hrs && '00' === $min ) )
100
+ ? 0 : $update_split[0];
101
+
102
+ if ( $freq < 2 ) { // update only once a day, every $update_split[0] days
103
+ $update_date = date_add( date_create( date( 'Y-m-d', strtotime( $last_update ) ) ), date_interval_create_from_date_string( $days . ' days' ) );
104
+
105
+ return date_format( $update_date, 'Y-m-d' ) . ' ' . $planned_update_time;
106
+ } else { // update more than once a day
107
+ $update_hrs = $this->get_update_hours( $freq );
108
+ $update_date = date_add( date_create( $last_update ), date_interval_create_from_date_string( $update_hrs . ' hours' ) );
109
+
110
+ return date_format( $update_date, 'Y-m-d H:i' ) . ':00';
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Returns the daily update options
116
+ *
117
+ * @param string $selection selected number of hours
118
+ *
119
+ * @return int Hours difference between updates
120
+ */
121
+ private function get_update_hours( $selection ) {
122
+ switch ( $selection ) {
123
+ case '2':
124
+ return 12;
125
+
126
+ case '4':
127
+ return 6;
128
+
129
+ case '6':
130
+ return 4;
131
+
132
+ case '8':
133
+ return 3;
134
+
135
+ case '12':
136
+ return 2;
137
+
138
+ case '24':
139
+ return 1;
140
+
141
+ default:
142
+ return 24;
143
+ }
144
+ }
145
+ }
146
+ // end of TVC_Schedules class
147
+ endif;
includes/application/google/class-feed.php ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Google Product Feed Manager Google Feed Class.
4
+ *
5
+ * @package Google Product Feed Manager/Channels
6
+ * @version 11.0
7
+ */
8
+
9
+ // Prevent direct access
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Google_Feed_Class' ) ) :
15
+
16
+ /**
17
+ * TVC_Google_Feed_Class class
18
+ */
19
+ class TVC_Google_Feed_Class extends TVC_Feed_Master_Class {
20
+
21
+ private $_version = '11.0';
22
+
23
+ public function __construct() {
24
+ parent::__construct();
25
+ }
26
+
27
+ public function get_version() {
28
+ return $this->_version;
29
+ }
30
+
31
+ public function get_file_text() {
32
+ return $this->generate_file_text( '1', 'google_product_category', 'description', 'xml' );
33
+ }
34
+
35
+ public function woocommerce_to_feed_fields() {
36
+ $fields = new stdClass();
37
+
38
+ // ALERT! Any changes made to this object also need to be done to the woocommerceToGoogleFields() function in the google-source.js file
39
+ $fields->id = 'ID';
40
+ $fields->title = 'post_title';
41
+ $fields->google_product_category = 'category';
42
+ $fields->description = 'post_content';
43
+ $fields->link = 'permalink';
44
+ $fields->image_link = 'attachment_url';
45
+ $fields->additional_image_link = '_wp_attachement_metadata';
46
+ $fields->price = '_regular_price';
47
+ $fields->identifier_exists = 'Fill with a static value';
48
+ $fields->sale_price = '_sale_price';
49
+ $fields->sale_price_effective_date = '_sale_price_dates_from';
50
+ $fields->item_group_id = 'item_group_id';
51
+ $fields->mpn = 'ID';
52
+ $fields->tax = 'Use the settings in the Merchant Center';
53
+ $fields->shipping = 'Use the settings in the Merchant Center';
54
+
55
+ return $fields;
56
+ }
57
+
58
+ // overrides the set_feed_output_attribute_levels function in TVC_Feed_Master_Class
59
+ // ALERT! This function is equivalent for the setGoogleOutputAttributeLevels() function in google-source.js
60
+ public function set_feed_output_attribute_levels( &$main_data ) {
61
+ $country = $main_data->country;
62
+
63
+ for ( $i = 0; $i < count( $main_data->attributes ); $i ++ ) {
64
+ if ( '0' === $main_data->attributes[ $i ]->fieldLevel ) {
65
+ switch ( $main_data->attributes[ $i ]->fieldName ) {
66
+ case 'google_product_category':
67
+ $main_data->attributes[ $i ]->fieldLevel = $this->google_needs_product_cat( $main_data->mainCategory ) === true ? 1 : 4;
68
+ break;
69
+
70
+ case 'is_bundle':
71
+ case 'multipack':
72
+ $main_data->attributes[ $i ]->fieldLevel = in_array( $country, $this->special_product_countries() ) ? 1 : 4;
73
+ break;
74
+
75
+ case 'brand':
76
+ $main_data->attributes[ $i ]->fieldLevel = $this->google_requires_brand( $main_data->mainCategory ) === true ? 1 : 4;
77
+ break;
78
+
79
+ case 'item_group_id':
80
+ $main_data->attributes[ $i ]->fieldLevel = in_array( $country, $this->special_clothing_group_countries() ) ? 1 : 4;
81
+ break;
82
+
83
+ case 'gender':
84
+ case 'age_group':
85
+ case 'color':
86
+ case 'size':
87
+ if ( in_array( $country, $this->special_clothing_group_countries() )
88
+ && $this->google_clothing_and_accessories( $main_data->mainCategory ) === true ) {
89
+ $main_data->attributes[ $i ]->fieldLevel = 1;
90
+ } else {
91
+ $main_data->attributes[ $i ]->fieldLevel = 4;
92
+ }
93
+
94
+ break;
95
+
96
+ case 'tax':
97
+ // In accordance with the Google Feed Specifications update of september 2015
98
+ $main_data->attributes[ $i ]->fieldLevel = 'US' === $country ? 1 : 4;
99
+ break;
100
+
101
+ case 'shipping':
102
+ // In accordance with the Google Feed Specifications update of september 2015
103
+ $main_data->attributes[ $i ]->fieldLevel = in_array( $country, $this->special_shipping_countries() ) ? 1 : 4;
104
+ break;
105
+
106
+ case 'subscription_cost':
107
+ case 'subscription_cost-period':
108
+ case 'subscription_cost-period_length':
109
+ case 'subscription_cost-amount':
110
+ $main_data->attributes[ $i ]->fieldLevel = in_array( $country, $this->special_subscription_countries() ) ? 4 : 0;
111
+ break;
112
+
113
+ default:
114
+ break;
115
+ }
116
+
117
+ $main_data->attributes[ $i ]->isActive =
118
+ $this->set_attribute_status( (int) $main_data->attributes[ $i ]->fieldLevel, $main_data->attributes[ $i ]->value );
119
+ }
120
+ }
121
+ }
122
+
123
+ public function keys_that_have_sub_tags() {
124
+ return array( 'installment', 'loyalty_points', 'shipping', 'tax', 'subscription_cost' );
125
+ }
126
+
127
+ // ALERT! This function is equivalent to the tvc_doublesFieldsAllowed() function in the tvc_google-source.js file
128
+ public function keys_that_can_be_used_more_than_once() {
129
+ return array( 'display_ads_similar_id', 'excluded_destination', 'adwords_labels', 'shipping' );
130
+ }
131
+
132
+ public function sub_keys_for_sub_tags() {
133
+ return array(
134
+ 'installment-months',
135
+ 'installment-amount',
136
+ 'loyalty_points-name',
137
+ 'loyalty_points-pointsValue',
138
+ 'loyalty_points-ratio',
139
+ 'shipping-country',
140
+ 'shipping-region',
141
+ 'shipping-service',
142
+ 'shipping-price',
143
+ 'tax-country',
144
+ 'tax-region',
145
+ 'tax-rate',
146
+ 'tax-tax_ship',
147
+ 'subscription_cost-period',
148
+ 'subscription_cost-period_length',
149
+ 'subscription_cost-amount',
150
+ );
151
+ }
152
+
153
+ // ALERT! This function is equivalent to the googleSpecialClothingGroupCountries() function in google-source.js
154
+ private function special_clothing_group_countries() {
155
+ return array( 'US', 'GB', 'DE', 'FR', 'JP', 'BR' ); // Brazil added based on the new Feed Specifications from september 2015
156
+ }
157
+
158
+ // ALERT! This function is equivalent to the googleSpecialShippingCountries() function in google-source.js
159
+ private function special_shipping_countries() {
160
+ return array( 'US', 'GB', 'DE', 'AU', 'FR', 'CH', 'CZ', 'NL', 'IT', 'ES', 'JP' );
161
+ }
162
+
163
+ // ALERT! This function is equivalent to the googleSpecialProductCountries() function in google-source.js
164
+ private function special_product_countries() {
165
+ return array( 'US', 'GB', 'DE', 'AU', 'FR', 'CH', 'CZ', 'NL', 'IT', 'ES', 'JP', 'BR' );
166
+ }
167
+
168
+ // ALERT! This function is equivalent to the googleSpecialSubscriptionCountries() function in google-source.js
169
+ private function special_subscription_countries() {
170
+ return array( 'DE', 'FR', 'GB' );
171
+ }
172
+
173
+ private function google_clothing_and_accessories( $category ) {
174
+ return stristr( $category, 'Apparel & Accessories' ) !== false ? true : false;
175
+ }
176
+
177
+ private function google_needs_product_cat( $category ) {
178
+ return stristr( $category, 'Apparel & Accessories' ) !== false
179
+ || stristr( $category, 'Media' ) !== false
180
+ || stristr( $category, 'Software' ) !== false ? true : false;
181
+ }
182
+
183
+ private function google_requires_brand( $category ) {
184
+ return false === stristr( $category, 'Media' ) ? true : false;
185
+ }
186
+
187
+ protected function header( $title, $description = '' ) {
188
+ // the check for convert_to_data_string function can be remove when all users have switched to plugin version 1.6 or higher
189
+ $title_string = method_exists( $this, 'data_string' ) ? $this->data_string( $title )
190
+ : $this->convert_to_character_data_string( $title );
191
+ $home_link = method_exists( $this, 'data_string' ) ? $this->data_string( get_option( 'home' ) )
192
+ : $this->convert_to_character_data_string( get_option( 'home' ) );
193
+ $descr = '' !== $description ? $description : $title;
194
+ $description_string = method_exists( $this, 'data_string' ) ? $this->data_string( $descr )
195
+ : $this->convert_to_character_data_string( $descr );
196
+ $title_tag = '<wf-connection-string>';
197
+
198
+ return '<?xml version="1.0"?>
199
+ <rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
200
+ <channel>
201
+ <title>' . $title_string . '</title>'
202
+ . $title_tag . $home_link . '</link>
203
+ <description>' . $description_string . '</description>';
204
+ }
205
+
206
+ protected function footer() {
207
+ return '</channel></rss>';
208
+ }
209
+ }
210
+
211
+ // end of TVC_Google_Feed_Class
212
+
213
+ endif;
includes/application/google/gmc.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ id
2
+ offerId
3
+ title
4
+ description
5
+ item_group_id
6
+ link
7
+ image_link
8
+ content_language
9
+ target_country
10
+ channel
11
+ age_group
12
+ availability
13
+ availability_date
14
+ brand
15
+ color
16
+ condition
17
+ gender
18
+ google_product_category
19
+ gtin
20
+ item_group_id
21
+ mpn
22
+ price
23
+ sizes
includes/application/google/gmc_attrbutes.json ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "field": "id",
4
+ "required": 1,
5
+ "desc": "Your product’s unique identifier",
6
+ "wAttribute": "ID"
7
+ },
8
+ {
9
+ "field": "title",
10
+ "required": 1,
11
+ "desc": "Your product’s name",
12
+ "wAttribute": "post_title"
13
+ },
14
+ {
15
+ "field": "description",
16
+ "required": 1,
17
+ "desc": "Your product’s description",
18
+ "wAttribute": "post_excerpt"
19
+ },
20
+ {
21
+ "field": "link",
22
+ "desc": "Your product’s landing page",
23
+ "required": 1
24
+ },
25
+ {
26
+ "field": "image_link",
27
+ "required": 1,
28
+ "desc": "The URL of your product’s main image",
29
+ "wAttribute": "_wp_attached_file"
30
+ },
31
+ {
32
+ "field": "price",
33
+ "required": 1,
34
+ "desc": "Your product’s price",
35
+ "wAttribute": "_sale_price"
36
+
37
+ },
38
+ {
39
+ "field": "gtin",
40
+ "desc": "Your product’s Global Trade Item Number (GTIN). Required for all new products with an assigned GTIN.",
41
+ "wAttribute": "tvc_product_gtin"
42
+ },
43
+ {
44
+ "field": "mpn",
45
+ "desc": "Your product’s Global Trade Item Number (GTIN). Required for all new products with an assigned GTIN.",
46
+ "wAttribute": "tvc_product_mpn"
47
+ },
48
+ {
49
+ "field": "offer_id",
50
+ "required": 1,
51
+ "desc": "offer id",
52
+ "wAttribute": "ID"
53
+ },
54
+ {
55
+ "field": "brand",
56
+ "desc": "Your product’s brand name",
57
+ "wAttribute": "tvc_product_brand"
58
+ },
59
+ {
60
+ "field": "availability",
61
+ "desc": "Your product's availability",
62
+ "wAttribute": "_stock_status"
63
+ },
64
+ {
65
+ "field": "item_group_id",
66
+ "desc": "ID for a group of products that come in different versions (variants)"
67
+ },
68
+ {
69
+ "field": "sizes",
70
+ "desc": "Your product’s size"
71
+ },
72
+ {
73
+ "field": "color",
74
+ "desc": "Your product’s color(s)"
75
+ },
76
+ {
77
+ "field": "age_group",
78
+ "desc": "The demographic for which your product is intended"
79
+ },
80
+ {
81
+ "field": "gender",
82
+ "desc": "The gender for which your product is intended"
83
+ },
84
+ {
85
+ "field": "condition",
86
+ "desc": "The condition of your product at time of sale"
87
+ },
88
+ {
89
+
90
+ "field": "shipping",
91
+ "desc": "Your product's shipping cost and the locations your product ships to"
92
+ },
93
+ {
94
+
95
+ "field": "tax",
96
+ "desc": "Your product’s sales tax rate in percent"
97
+ },
98
+ {
99
+ "field": "product_type",
100
+ "desc": "Product category that you define for your product"
101
+ },
102
+ {
103
+ "field": "google_product_category",
104
+ "desc": "product category"
105
+ },
106
+ {
107
+ "field": "content_language",
108
+ "desc": "content language"
109
+ },
110
+ {
111
+ "field": "target_country",
112
+ "desc": "Country for Google Shopping Listing"
113
+ },
114
+ {
115
+ "field": "channel",
116
+ "desc": "channel"
117
+ }
118
+ ]
includes/application/google/google.txt ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 1 1 id
2
+ 2 1 title
3
+ 3 1 description
4
+ 4 0 google_product_category
5
+ 5 4 product_type
6
+ 6 1 link
7
+ 7 4 mobile_link
8
+ 8 1 image_link
9
+ 9 1 price
10
+ 10 1 condition
11
+ 11 1 availability
12
+ 12 4 availability_date
13
+ 13 0 brand
14
+ 14 1 gtin
15
+ 15 4 mpn
16
+ 16 0 item_group_id
17
+ 17 4 additional_image_link
18
+ 18 4 sale_price
19
+ 19 4 sale_price_effective_date
20
+ 20 0 gender
21
+ 21 0 age_group
22
+ 22 0 color
23
+ 23 0 size
24
+ 24 4 material
25
+ 25 4 pattern
26
+ 26 4 shipping_weight
27
+ 27 4 expiration_date
28
+ 28 4 adwords_redirect
29
+ 29 1 adult
30
+ 30 0 multipack
31
+ 31 1 identifier_exists
32
+ 32 4 size_type
33
+ 33 4 size_system
34
+ 34 0 shipping
35
+ 35 4 shipping_label
36
+ 36 0 is_bundle
37
+ 37 4 custom_label_0
38
+ 38 4 custom_label_1
39
+ 39 4 custom_label_2
40
+ 40 4 custom_label_3
41
+ 41 4 custom_label_4
42
+ 42 4 unit_pricing_measure
43
+ 43 4 unit_pricing_base_measure
44
+ 44 4 energy_efficiency_class
45
+ 45 4 min_energy_efficiency_class
46
+ 46 4 max_energy_efficiency_class
47
+ 47 0 tax
48
+ 48 4 installment
49
+ 49 4 loyalty_points
50
+ 50 4 promotion_id
51
+ 51 4 shipping_length
52
+ 52 4 shipping_width
53
+ 53 4 shipping_height
54
+ 54 4 installment-months
55
+ 55 4 installment-amount
56
+ 56 4 loyalty_points-name
57
+ 57 4 loyalty_points-pointsValue
58
+ 58 4 loyalty_points-ratio
59
+ 59 4 shipping-country
60
+ 60 4 shipping-region
61
+ 61 4 shipping-service
62
+ 62 4 shipping-price
63
+ 63 4 transit_time_label
64
+ 64 4 tax-country
65
+ 65 4 tax-region
66
+ 66 4 tax-rate
67
+ 67 4 tax-tax_ship
68
+ 68 4 tax_category
69
+ 69 4 display_ads_id
70
+ 70 4 display_ads_similar_id
71
+ 71 4 display_ads_title
72
+ 72 4 display_ads_link
73
+ 73 4 display_ads_value
74
+ 74 4 excluded_destination
75
+ 75 4 included_destination
76
+ 76 4 adwords_grouping
77
+ 77 4 adwords_labels
78
+ 78 4 min_handling_time
79
+ 79 4 max_handling_time
80
+ 80 4 cost_of_goods_sold
81
+ 81 0 subscription_cost
82
+ 82 0 subscription_cost-period
83
+ 83 0 subscription_cost-period_length
84
+ 84 0 subscription_cost-amount
includes/application/google/taxonomy.en-US.txt ADDED
@@ -0,0 +1,5583 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Google_Product_Taxonomy_Version: 2019-07-10
2
+ Animals & Pet Supplies
3
+ Animals & Pet Supplies > Live Animals
4
+ Animals & Pet Supplies > Pet Supplies
5
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies
6
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories
7
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Bird Baths
8
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Food & Water Dishes
9
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cages & Stands
10
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Food
11
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Gyms & Playstands
12
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Ladders & Perches
13
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Toys
14
+ Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Treats
15
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies
16
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Apparel
17
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Beds
18
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food
19
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food > Non-prescription Cat Food
20
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food > Prescription Cat Food
21
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture
22
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture Accessories
23
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter
24
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Liners
25
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Mats
26
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Boxes
27
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Toys
28
+ Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Treats
29
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies
30
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Apparel
31
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Beds
32
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diaper Pads & Liners
33
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diapers
34
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food
35
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food > Non-prescription Dog Food
36
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food > Prescription Dog Food
37
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Houses
38
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennel & Run Accessories
39
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennels & Runs
40
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Toys
41
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treadmills
42
+ Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treats
43
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies
44
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium & Pond Tubing
45
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Air Stones & Diffusers
46
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Cleaning Supplies
47
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Decor
48
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Filters
49
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Fish Nets
50
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Gravel & Substrates
51
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Lighting
52
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Overflow Boxes
53
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Stands
54
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Temperature Controllers
55
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Water Treatments
56
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquariums
57
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquatic Plant Fertilizers
58
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Feeders
59
+ Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Food
60
+ Animals & Pet Supplies > Pet Supplies > Pet Agility Equipment
61
+ Animals & Pet Supplies > Pet Supplies > Pet Apparel Hangers
62
+ Animals & Pet Supplies > Pet Supplies > Pet Bed Accessories
63
+ Animals & Pet Supplies > Pet Supplies > Pet Bells & Charms
64
+ Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors
65
+ Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Glucose Meters
66
+ Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Pedometers
67
+ Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Thermometers
68
+ Animals & Pet Supplies > Pet Supplies > Pet Bowl Mats
69
+ Animals & Pet Supplies > Pet Supplies > Pet Bowl Stands
70
+ Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers
71
+ Animals & Pet Supplies > Pet Supplies > Pet Carrier & Crate Accessories
72
+ Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates
73
+ Animals & Pet Supplies > Pet Supplies > Pet Collars & Harnesses
74
+ Animals & Pet Supplies > Pet Supplies > Pet Containment Systems
75
+ Animals & Pet Supplies > Pet Supplies > Pet Door Accessories
76
+ Animals & Pet Supplies > Pet Supplies > Pet Doors
77
+ Animals & Pet Supplies > Pet Supplies > Pet Eye Drops & Lubricants
78
+ Animals & Pet Supplies > Pet Supplies > Pet First Aid & Emergency Kits
79
+ Animals & Pet Supplies > Pet Supplies > Pet Flea & Tick Control
80
+ Animals & Pet Supplies > Pet Supplies > Pet Food Containers
81
+ Animals & Pet Supplies > Pet Supplies > Pet Food Scoops
82
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies
83
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Combs & Brushes
84
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Fragrances & Deodorizing Sprays
85
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Clippers & Trimmers
86
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Dryers
87
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Polish
88
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Tools
89
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Shampoo & Conditioner
90
+ Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Wipes
91
+ Animals & Pet Supplies > Pet Supplies > Pet Heating Pad Accessories
92
+ Animals & Pet Supplies > Pet Supplies > Pet Heating Pads
93
+ Animals & Pet Supplies > Pet Supplies > Pet ID Tags
94
+ Animals & Pet Supplies > Pet Supplies > Pet Leash Extensions
95
+ Animals & Pet Supplies > Pet Supplies > Pet Leashes
96
+ Animals & Pet Supplies > Pet Supplies > Pet Medical Collars
97
+ Animals & Pet Supplies > Pet Supplies > Pet Medical Tape & Bandages
98
+ Animals & Pet Supplies > Pet Supplies > Pet Medicine
99
+ Animals & Pet Supplies > Pet Supplies > Pet Muzzles
100
+ Animals & Pet Supplies > Pet Supplies > Pet Oral Care Supplies
101
+ Animals & Pet Supplies > Pet Supplies > Pet Playpens
102
+ Animals & Pet Supplies > Pet Supplies > Pet Steps & Ramps
103
+ Animals & Pet Supplies > Pet Supplies > Pet Strollers
104
+ Animals & Pet Supplies > Pet Supplies > Pet Sunscreen
105
+ Animals & Pet Supplies > Pet Supplies > Pet Training Aids
106
+ Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Clickers & Treat Dispensers
107
+ Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Pad Holders
108
+ Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Pads
109
+ Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Sprays & Solutions
110
+ Animals & Pet Supplies > Pet Supplies > Pet Vitamins & Supplements
111
+ Animals & Pet Supplies > Pet Supplies > Pet Waste Bag Dispensers & Holders
112
+ Animals & Pet Supplies > Pet Supplies > Pet Waste Bags
113
+ Animals & Pet Supplies > Pet Supplies > Pet Waste Disposal Systems & Tools
114
+ Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies
115
+ Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Food
116
+ Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Accessories
117
+ Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Heating & Lighting
118
+ Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitats
119
+ Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Substrates
120
+ Animals & Pet Supplies > Pet Supplies > Small Animal Supplies
121
+ Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Bedding
122
+ Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Food
123
+ Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitat Accessories
124
+ Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitats & Cages
125
+ Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Treats
126
+ Animals & Pet Supplies > Pet Supplies > Vehicle Pet Barriers
127
+ Apparel & Accessories
128
+ Apparel & Accessories > Clothing
129
+ Apparel & Accessories > Clothing > Activewear
130
+ Apparel & Accessories > Clothing > Activewear > Bicycle Activewear
131
+ Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Bibs
132
+ Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Jerseys
133
+ Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Shorts & Briefs
134
+ Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Skinsuits
135
+ Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Tights
136
+ Apparel & Accessories > Clothing > Activewear > Boxing Shorts
137
+ Apparel & Accessories > Clothing > Activewear > Dance Dresses, Skirts & Costumes
138
+ Apparel & Accessories > Clothing > Activewear > Football Pants
139
+ Apparel & Accessories > Clothing > Activewear > Hunting Clothing
140
+ Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Ghillie Suits
141
+ Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Fishing Vests
142
+ Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Tactical Pants
143
+ Apparel & Accessories > Clothing > Activewear > Martial Arts Shorts
144
+ Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing
145
+ Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Jackets
146
+ Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Pants
147
+ Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Suits
148
+ Apparel & Accessories > Clothing > Activewear > Paintball Clothing
149
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing
150
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Bottoms
151
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Diaper Covers
152
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Dresses
153
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outerwear
154
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outfits
155
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Sleepwear
156
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Socks & Tights
157
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Swimwear
158
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Tops
159
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby One-Pieces
160
+ Apparel & Accessories > Clothing > Baby & Toddler Clothing > Toddler Underwear
161
+ Apparel & Accessories > Clothing > Dresses
162
+ Apparel & Accessories > Clothing > One-Pieces
163
+ Apparel & Accessories > Clothing > One-Pieces > Jumpsuits & Rompers
164
+ Apparel & Accessories > Clothing > One-Pieces > Leotards & Unitards
165
+ Apparel & Accessories > Clothing > One-Pieces > Overalls
166
+ Apparel & Accessories > Clothing > Outerwear
167
+ Apparel & Accessories > Clothing > Outerwear > Chaps
168
+ Apparel & Accessories > Clothing > Outerwear > Coats & Jackets
169
+ Apparel & Accessories > Clothing > Outerwear > Rain Pants
170
+ Apparel & Accessories > Clothing > Outerwear > Rain Suits
171
+ Apparel & Accessories > Clothing > Outerwear > Snow Pants & Suits
172
+ Apparel & Accessories > Clothing > Outerwear > Vests
173
+ Apparel & Accessories > Clothing > Outfit Sets
174
+ Apparel & Accessories > Clothing > Pants
175
+ Apparel & Accessories > Clothing > Shirts & Tops
176
+ Apparel & Accessories > Clothing > Shorts
177
+ Apparel & Accessories > Clothing > Skirts
178
+ Apparel & Accessories > Clothing > Skorts
179
+ Apparel & Accessories > Clothing > Sleepwear & Loungewear
180
+ Apparel & Accessories > Clothing > Sleepwear & Loungewear > Loungewear
181
+ Apparel & Accessories > Clothing > Sleepwear & Loungewear > Nightgowns
182
+ Apparel & Accessories > Clothing > Sleepwear & Loungewear > Pajamas
183
+ Apparel & Accessories > Clothing > Sleepwear & Loungewear > Robes
184
+ Apparel & Accessories > Clothing > Suits
185
+ Apparel & Accessories > Clothing > Suits > Pant Suits
186
+ Apparel & Accessories > Clothing > Suits > Skirt Suits
187
+ Apparel & Accessories > Clothing > Suits > Tuxedos
188
+ Apparel & Accessories > Clothing > Swimwear
189
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing
190
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Dirndls
191
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Hakama Trousers
192
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Japanese Black Formal Wear
193
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimono Outerwear
194
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos
195
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing
196
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing > Baptism & Communion Dresses
197
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Saris & Lehengas
198
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Traditional Leather Pants
199
+ Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Yukata
200
+ Apparel & Accessories > Clothing > Underwear & Socks
201
+ Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories
202
+ Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Strap Pads
203
+ Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Straps & Extenders
204
+ Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Enhancing Inserts
205
+ Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Petals & Concealers
206
+ Apparel & Accessories > Clothing > Underwear & Socks > Bras
207
+ Apparel & Accessories > Clothing > Underwear & Socks > Hosiery
208
+ Apparel & Accessories > Clothing > Underwear & Socks > Jock Straps
209
+ Apparel & Accessories > Clothing > Underwear & Socks > Lingerie
210
+ Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories
211
+ Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garter Belts
212
+ Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garters
213
+ Apparel & Accessories > Clothing > Underwear & Socks > Long Johns
214
+ Apparel & Accessories > Clothing > Underwear & Socks > Petticoats & Pettipants
215
+ Apparel & Accessories > Clothing > Underwear & Socks > Shapewear
216
+ Apparel & Accessories > Clothing > Underwear & Socks > Socks
217
+ Apparel & Accessories > Clothing > Underwear & Socks > Undershirts
218
+ Apparel & Accessories > Clothing > Underwear & Socks > Underwear
219
+ Apparel & Accessories > Clothing > Underwear & Socks > Underwear Slips
220
+ Apparel & Accessories > Clothing > Uniforms
221
+ Apparel & Accessories > Clothing > Uniforms > Contractor Pants & Coveralls
222
+ Apparel & Accessories > Clothing > Uniforms > Flight Suits
223
+ Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms
224
+ Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Hats
225
+ Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Jackets
226
+ Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Pants
227
+ Apparel & Accessories > Clothing > Uniforms > Military Uniforms
228
+ Apparel & Accessories > Clothing > Uniforms > School Uniforms
229
+ Apparel & Accessories > Clothing > Uniforms > Security Uniforms
230
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms
231
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Baseball Uniforms
232
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Basketball Uniforms
233
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cheerleading Uniforms
234
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cricket Uniforms
235
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Football Uniforms
236
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Hockey Uniforms
237
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Martial Arts Uniforms
238
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Officiating Uniforms
239
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Soccer Uniforms
240
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Softball Uniforms
241
+ Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Wrestling Uniforms
242
+ Apparel & Accessories > Clothing > Uniforms > White Coats
243
+ Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses
244
+ Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Bridal Party Dresses
245
+ Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Wedding Dresses
246
+ Apparel & Accessories > Clothing Accessories
247
+ Apparel & Accessories > Clothing Accessories > Arm Warmers & Sleeves
248
+ Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories
249
+ Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Belts
250
+ Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Gloves & Mittens
251
+ Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Hats
252
+ Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby Protective Wear
253
+ Apparel & Accessories > Clothing Accessories > Balaclavas
254
+ Apparel & Accessories > Clothing Accessories > Bandanas & Headties
255
+ Apparel & Accessories > Clothing Accessories > Bandanas & Headties > Bandanas
256
+ Apparel & Accessories > Clothing Accessories > Bandanas & Headties > Hair Care Wraps
257
+ Apparel & Accessories > Clothing Accessories > Belt Buckles
258
+ Apparel & Accessories > Clothing Accessories > Belts
259
+ Apparel & Accessories > Clothing Accessories > Bridal Accessories
260
+ Apparel & Accessories > Clothing Accessories > Bridal Accessories > Bridal Veils
261
+ Apparel & Accessories > Clothing Accessories > Button Studs
262
+ Apparel & Accessories > Clothing Accessories > Collar Stays
263
+ Apparel & Accessories > Clothing Accessories > Cufflinks
264
+ Apparel & Accessories > Clothing Accessories > Decorative Fans
265
+ Apparel & Accessories > Clothing Accessories > Earmuffs
266
+ Apparel & Accessories > Clothing Accessories > Gloves & Mittens
267
+ Apparel & Accessories > Clothing Accessories > Hair Accessories
268
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Bun & Volume Shapers
269
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Combs
270
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Extensions
271
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Forks & Sticks
272
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Nets
273
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips
274
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips > Barrettes
275
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips > Hair Claws & Clips
276
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips > Hair Pins
277
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Wreaths
278
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Headbands
279
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Ponytail Holders
280
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Tiaras
281
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories
282
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories > Wig Caps
283
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories > Wig Glue & Tape
284
+ Apparel & Accessories > Clothing Accessories > Hair Accessories > Wigs
285
+ Apparel & Accessories > Clothing Accessories > Hand Muffs
286
+ Apparel & Accessories > Clothing Accessories > Handkerchiefs
287
+ Apparel & Accessories > Clothing Accessories > Hats
288
+ Apparel & Accessories > Clothing Accessories > Headwear
289
+ Apparel & Accessories > Clothing Accessories > Headwear > Fascinators
290
+ Apparel & Accessories > Clothing Accessories > Headwear > Headdresses
291
+ Apparel & Accessories > Clothing Accessories > Headwear > Turbans
292
+ Apparel & Accessories > Clothing Accessories > Leg Warmers
293
+ Apparel & Accessories > Clothing Accessories > Leis
294
+ Apparel & Accessories > Clothing Accessories > Maternity Belts & Support Bands
295
+ Apparel & Accessories > Clothing Accessories > Neck Gaiters
296
+ Apparel & Accessories > Clothing Accessories > Neckties
297
+ Apparel & Accessories > Clothing Accessories > Pinback Buttons
298
+ Apparel & Accessories > Clothing Accessories > Sashes
299
+ Apparel & Accessories > Clothing Accessories > Scarves & Shawls
300
+ Apparel & Accessories > Clothing Accessories > Scarves & Shawls > Scarves
301
+ Apparel & Accessories > Clothing Accessories > Scarves & Shawls > Shawls
302
+ Apparel & Accessories > Clothing Accessories > Sunglasses
303
+ Apparel & Accessories > Clothing Accessories > Suspenders
304
+ Apparel & Accessories > Clothing Accessories > Tie Clips
305
+ Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories
306
+ Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Obis
307
+ Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Tabi Socks
308
+ Apparel & Accessories > Clothing Accessories > Wristbands
309
+ Apparel & Accessories > Costumes & Accessories
310
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories
311
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Bald Caps
312
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Accessory Sets
313
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Capes
314
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Gloves
315
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Hats
316
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Special Effects
317
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Tobacco Products
318
+ Apparel & Accessories > Costumes & Accessories > Costume Accessories > Pretend Jewelry
319
+ Apparel & Accessories > Costumes & Accessories > Costume Shoes
320
+ Apparel & Accessories > Costumes & Accessories > Costumes
321
+ Apparel & Accessories > Costumes & Accessories > Masks
322
+ Apparel & Accessories > Handbag & Wallet Accessories
323
+ Apparel & Accessories > Handbag & Wallet Accessories > Checkbook Covers
324
+ Apparel & Accessories > Handbag & Wallet Accessories > Keychains
325
+ Apparel & Accessories > Handbag & Wallet Accessories > Lanyards
326
+ Apparel & Accessories > Handbag & Wallet Accessories > Wallet Chains
327
+ Apparel & Accessories > Handbags, Wallets & Cases
328
+ Apparel & Accessories > Handbags, Wallets & Cases > Badge & Pass Holders
329
+ Apparel & Accessories > Handbags, Wallets & Cases > Business Card Cases
330
+ Apparel & Accessories > Handbags, Wallets & Cases > Handbags
331
+ Apparel & Accessories > Handbags, Wallets & Cases > Wallets & Money Clips
332
+ Apparel & Accessories > Jewelry
333
+ Apparel & Accessories > Jewelry > Anklets
334
+ Apparel & Accessories > Jewelry > Body Jewelry
335
+ Apparel & Accessories > Jewelry > Bracelets
336
+ Apparel & Accessories > Jewelry > Brooches & Lapel Pins
337
+ Apparel & Accessories > Jewelry > Charms & Pendants
338
+ Apparel & Accessories > Jewelry > Earrings
339
+ Apparel & Accessories > Jewelry > Jewelry Sets
340
+ Apparel & Accessories > Jewelry > Necklaces
341
+ Apparel & Accessories > Jewelry > Rings
342
+ Apparel & Accessories > Jewelry > Watch Accessories
343
+ Apparel & Accessories > Jewelry > Watch Accessories > Watch Bands
344
+ Apparel & Accessories > Jewelry > Watch Accessories > Watch Stickers & Decals
345
+ Apparel & Accessories > Jewelry > Watch Accessories > Watch Winders
346
+ Apparel & Accessories > Jewelry > Watches
347
+ Apparel & Accessories > Shoe Accessories
348
+ Apparel & Accessories > Shoe Accessories > Boot Liners
349
+ Apparel & Accessories > Shoe Accessories > Gaiters
350
+ Apparel & Accessories > Shoe Accessories > Shoe Covers
351
+ Apparel & Accessories > Shoe Accessories > Shoelaces
352
+ Apparel & Accessories > Shoe Accessories > Spurs
353
+ Apparel & Accessories > Shoes
354
+ Arts & Entertainment
355
+ Arts & Entertainment > Event Tickets
356
+ Arts & Entertainment > Hobbies & Creative Arts
357
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts
358
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits
359
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Candle Making Kits
360
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Drawing & Painting Kits
361
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Fabric Repair Kits
362
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Incense Making Kits
363
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Jewelry Making Kits
364
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Mosaic Kits
365
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Needlecraft Kits
366
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Scrapbooking & Stamping Kits
367
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Toy Craft Kits
368
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials
369
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper
370
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper
371
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper > Cardstock
372
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper > Scrapbooking Paper
373
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Construction Paper
374
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Craft Foil
375
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Drawing & Painting Paper
376
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Origami Paper
377
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Transfer Paper
378
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Vellum Paper
379
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures
380
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Buttons & Snaps
381
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Clasps & Hooks
382
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Eyelets & Grommets
383
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Hook and Loop Fasteners
384
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Zipper Pulls
385
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Zippers
386
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze
387
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art & Craft Paint
388
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art Fixatives
389
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art Ink
390
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Ceramic & Pottery Glazes
391
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Craft Dyes
392
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Ink Pads
393
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Paint Mediums
394
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases
395
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Craft Foam & Styrofoam
396
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Craft Wood & Shapes
397
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Papier Mache Shapes
398
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Wreath & Floral Frames
399
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets
400
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Craft & Office Glue
401
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Craft Magnets
402
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Decorative Tape
403
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Floral Tape
404
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Fusible Tape
405
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers
406
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Jewelry & Beading Cord
407
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Thread & Floss
408
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Unspun Fiber
409
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Yarn
410
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire
411
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Craft Pipe Cleaners
412
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Floral Wire
413
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Jewelry & Beading Wire
414
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims
415
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Appliques & Patches
416
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Beads
417
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Bows & Yo-Yos
418
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Decorative Stickers
419
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Elastic
420
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Feathers
421
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Jewelry Findings
422
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Loose Stones
423
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Rhinestones & Flatbacks
424
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Ribbons & Trim
425
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Sequins & Glitter
426
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Sew-in Labels
427
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embossing Powder
428
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material
429
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Batting & Stuffing
430
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Filling Pellets
431
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Pillow Forms
432
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Leather & Vinyl
433
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials
434
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough
435
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough > Clay
436
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough > Modeling Dough
437
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Papier Mache Mixes
438
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Plaster Gauze
439
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Pottery Slips
440
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Raw Candle Wax
441
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles
442
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas
443
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Needlecraft Canvas
444
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Painting Canvas
445
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Plastic Canvas
446
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Fabric
447
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Interfacing
448
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Printable Fabric
449
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Wick Tabs
450
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Wicks
451
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories
452
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Craft Knife Blades
453
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Craft Machine Cases & Covers
454
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Extension Tables
455
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Feet
456
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Replacement Parts
457
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Spinning Wheel Accessories
458
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Stamp Blocks
459
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools
460
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Blocking Mats
461
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Blocking Wires
462
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools
463
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools > Palette Knives
464
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools > Palettes
465
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools
466
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft & Office Scissors
467
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Cutters & Embossers
468
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Knives
469
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Scoring Tools
470
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Embossing Heat Tools
471
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Embossing Pens & Styluses
472
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Seam Rippers
473
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Thread & Yarn Cutters
474
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Decoration Makers
475
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools
476
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Art Brushes
477
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Brayer Rollers
478
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Decorative Stamps
479
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Drafting Compasses
480
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Screen Printing Squeegees
481
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stencil Machines
482
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stencils & Die Cuts
483
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stitch Markers & Counters
484
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Textile Art Gauges & Rulers
485
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Wood Burning Tools
486
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Cutting Mats
487
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Dress Forms
488
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Felting Pads & Mats
489
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Frames, Hoops & Stretchers
490
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Glue Guns
491
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Light Boxes
492
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks
493
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Crochet Hooks
494
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Hand-Sewing Needles
495
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Knitting Needles
496
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Latch & Locker Hooks
497
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Sewing Machine Needles
498
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Safety Pins
499
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Straight Pins
500
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines
501
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Felting Needles & Machines
502
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Hand Looms
503
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Mechanical Looms
504
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Sewing Machines
505
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Spinning Wheels
506
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms
507
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms > Sewing Palms
508
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms > Thimbles
509
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools
510
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Fiber Cards & Brushes
511
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Hand Spindles
512
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Needle Threaders
513
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread & Yarn Guides
514
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread & Yarn Spools
515
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread, Yarn & Bobbin Winders
516
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Weaving Beaters
517
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Weaving Shuttles
518
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization
519
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Needle, Pin & Hook Organizers
520
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Sewing Baskets & Kits
521
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Thread & Yarn Organizers
522
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds
523
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Beading Patterns
524
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Craft Molds
525
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Felting Molds
526
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Needlecraft Patterns
527
+ Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Sewing Patterns
528
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles
529
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Autographs
530
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency
531
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency > Collectible Banknotes
532
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency > Collectible Coins
533
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Trading Cards
534
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons
535
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Guns
536
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Knives
537
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Swords
538
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Sword Stands & Displays
539
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Postage Stamps
540
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Rocks & Fossils
541
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Model Accessories
542
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Models
543
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Seal Stamps
544
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles
545
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia
546
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Auto Racing Autographed Paraphernalia
547
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Baseball & Softball Autographed Paraphernalia
548
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Basketball Autographed Paraphernalia
549
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Boxing Autographed Paraphernalia
550
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Football Autographed Paraphernalia
551
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Hockey Autographed Paraphernalia
552
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Soccer Autographed Paraphernalia
553
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Tennis Autographed Sports Paraphernalia
554
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories
555
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Auto Racing Fan Accessories
556
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Baseball & Softball Fan Accessories
557
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Basketball Fan Accessories
558
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Football Fan Accessories
559
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Hockey Fan Accessories
560
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Soccer Fan Accessories
561
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Tennis Fan Accessories
562
+ Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Vintage Advertisements
563
+ Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies
564
+ Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Beer Brewing Grains & Malts
565
+ Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Bottling Bottles
566
+ Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Homebrewing & Winemaking Kits
567
+ Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Wine Making
568
+ Arts & Entertainment > Hobbies & Creative Arts > Juggling
569
+ Arts & Entertainment > Hobbies & Creative Arts > Magic & Novelties
570
+ Arts & Entertainment > Hobbies & Creative Arts > Model Making
571
+ Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Rocketry
572
+ Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Train Accessories
573
+ Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Trains & Train Sets
574
+ Arts & Entertainment > Hobbies & Creative Arts > Model Making > Scale Model Kits
575
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories
576
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories
577
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning
578
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Care Kits
579
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaners & Sanitizers
580
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaning Tools
581
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Guards
582
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Lubricants
583
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Polishing Cloths
584
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Cases & Gigbags
585
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Mouthpieces
586
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Mutes
587
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Replacement Parts
588
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Straps & Stands
589
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Conductor Batons
590
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Electronic Tuners
591
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Metronomes
592
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Benches & Stools
593
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Lyres & Flip Folders
594
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories
595
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Music Stand Bags
596
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Music Stand Lights
597
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Sheet Music Clips
598
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stands
599
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories
600
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Cabinets
601
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Covers & Cases
602
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Footswitches
603
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Knobs
604
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Stands
605
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Tubes
606
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifiers
607
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories
608
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Musical Keyboard Bags & Cases
609
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Musical Keyboard Stands
610
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Sustain Pedals
611
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories
612
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Cymbal & Drum Cases
613
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Cymbal & Drum Mutes
614
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Heads
615
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Keys
616
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware
617
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Bass Drum Beaters
618
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Drum Kit Mounting Hardware
619
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Drum Pedals
620
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Stick & Brush Accessories
621
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Stick & Brush Accessories > Drum Stick & Brush Bags & Holders
622
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Sticks & Brushes
623
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Electronic Drum Modules
624
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories
625
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Bags & Cases
626
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Stands & Mounts
627
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Percussion Mallets
628
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Percussion Stands
629
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories
630
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories
631
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Acoustic Guitar Pickups
632
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Capos
633
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Electric Guitar Pickups
634
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Cases & Gig Bags
635
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Fittings & Parts
636
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Humidifiers
637
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Picks
638
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Slides
639
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Stands
640
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Straps
641
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar String Winders
642
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Strings
643
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Tuning Pegs
644
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories
645
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Bow Cases
646
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Bows
647
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Cases
648
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Fittings & Parts
649
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Mutes
650
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Pickups
651
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Stands
652
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Strings
653
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning
654
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > Bow Rosin
655
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Cleaning Cloths
656
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Polish
657
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories
658
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories
659
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning
660
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning > Bassoon Swabs
661
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Cases & Gigbags
662
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts
663
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Bocals
664
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Small Parts
665
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Reeds
666
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Stands
667
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Straps & Supports
668
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories
669
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning
670
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Care Kits
671
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Pad Savers
672
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Swabs
673
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Cases & Gigbags
674
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Ligatures & Caps
675
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts
676
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Barrels
677
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Bells
678
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Mouthpieces
679
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Small Parts
680
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Pegs & Stands
681
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Reeds
682
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Straps & Supports
683
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories
684
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning
685
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Care Kits
686
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Cleaning Rods
687
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Swabs
688
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Cases & Gigbags
689
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts
690
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Headjoints
691
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Small Parts
692
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Pegs & Stands
693
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories
694
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Cases
695
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Holders
696
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories
697
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning
698
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Care Kits
699
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Swabs
700
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Cases & Gigbags
701
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts
702
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts > Oboe Small Parts
703
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Pegs & Stands
704
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Reeds
705
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Straps & Supports
706
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories
707
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Care & Cleaning
708
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Cases
709
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Parts
710
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories
711
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning
712
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Care Kits
713
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Pad Savers
714
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Swabs
715
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Cases & Gigbags
716
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Ligatures & Caps
717
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts
718
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Mouthpieces
719
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Necks
720
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Small Parts
721
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Pegs & Stands
722
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Reeds
723
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Straps & Supports
724
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Cork Grease
725
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Polishing Cloths
726
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Reed Cases
727
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Reed Knives
728
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments
729
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Accordions & Concertinas
730
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Bagpipes
731
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments
732
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Alto & Baritone Horns
733
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Euphoniums
734
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > French Horns
735
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Trombones
736
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Trumpets & Cornets
737
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Tubas
738
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments
739
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Audio Samplers
740
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > MIDI Controllers
741
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Musical Keyboards
742
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Sound Synthesizers
743
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion
744
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Bass Drums
745
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Cymbals
746
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Drum Kits
747
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Electronic Drums
748
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Glockenspiels & Xylophones
749
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Gongs
750
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion
751
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Claves & Castanets
752
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Finger & Hand Cymbals
753
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Bells & Chimes
754
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums
755
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Bongos
756
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Cajons
757
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Congas
758
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Frame Drums
759
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Goblet Drums
760
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Tablas
761
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Talking Drums
762
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Blocks
763
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Cowbells
764
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Scrapers & Ratchets
765
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Shakers
766
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Triangles
767
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Tambourines
768
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Vibraslaps
769
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hi-Hats
770
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Practice Pads
771
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Snare Drums
772
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Tom-Toms
773
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Pianos
774
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments
775
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Cellos
776
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars
777
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Harps
778
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Upright Basses
779
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violas
780
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violins
781
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds
782
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Bassoons
783
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Clarinets
784
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutes
785
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutophones
786
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Harmonicas
787
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Jew's Harps
788
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Melodicas
789
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Musical Pipes
790
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Oboes & English Horns
791
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Ocarinas
792
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Recorders
793
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Saxophones
794
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Tin Whistles
795
+ Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Train Whistles
796
+ Arts & Entertainment > Party & Celebration
797
+ Arts & Entertainment > Party & Celebration > Gift Giving
798
+ Arts & Entertainment > Party & Celebration > Gift Giving > Corsage & Boutonnière Pins
799
+ Arts & Entertainment > Party & Celebration > Gift Giving > Corsages & Boutonnières
800
+ Arts & Entertainment > Party & Celebration > Gift Giving > Fresh Cut Flowers
801
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Cards & Certificates
802
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping
803
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Bags
804
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Boxes & Tins
805
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Tags & Labels
806
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Tissue Paper
807
+ Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Wrapping Paper
808
+ Arts & Entertainment > Party & Celebration > Gift Giving > Greeting & Note Cards
809
+ Arts & Entertainment > Party & Celebration > Party Supplies
810
+ Arts & Entertainment > Party & Celebration > Party Supplies > Advice Cards
811
+ Arts & Entertainment > Party & Celebration > Party Supplies > Balloon Kits
812
+ Arts & Entertainment > Party & Celebration > Party Supplies > Balloons
813
+ Arts & Entertainment > Party & Celebration > Party Supplies > Banners
814
+ Arts & Entertainment > Party & Celebration > Party Supplies > Birthday Candles
815
+ Arts & Entertainment > Party & Celebration > Party Supplies > Chair Sashes
816
+ Arts & Entertainment > Party & Celebration > Party Supplies > Cocktail Decorations
817
+ Arts & Entertainment > Party & Celebration > Party Supplies > Confetti
818
+ Arts & Entertainment > Party & Celebration > Party Supplies > Decorative Pom-Poms
819
+ Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games
820
+ Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong
821
+ Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong > Beer Pong Tables
822
+ Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Straws & Stirrers
823
+ Arts & Entertainment > Party & Celebration > Party Supplies > Envelope Seals
824
+ Arts & Entertainment > Party & Celebration > Party Supplies > Event Programs
825
+ Arts & Entertainment > Party & Celebration > Party Supplies > Fireworks & Firecrackers
826
+ Arts & Entertainment > Party & Celebration > Party Supplies > Inflatable Party Decorations
827
+ Arts & Entertainment > Party & Celebration > Party Supplies > Invitations
828
+ Arts & Entertainment > Party & Celebration > Party Supplies > Noisemakers & Party Blowers
829
+ Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors
830
+ Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors > Wedding Favors
831
+ Arts & Entertainment > Party & Celebration > Party Supplies > Party Games
832
+ Arts & Entertainment > Party & Celebration > Party Supplies > Party Hats
833
+ Arts & Entertainment > Party & Celebration > Party Supplies > Party Streamers & Curtains
834
+ Arts & Entertainment > Party & Celebration > Party Supplies > Party Supply Kits
835
+ Arts & Entertainment > Party & Celebration > Party Supplies > Piñatas
836
+ Arts & Entertainment > Party & Celebration > Party Supplies > Place Card Holders
837
+ Arts & Entertainment > Party & Celebration > Party Supplies > Place Cards
838
+ Arts & Entertainment > Party & Celebration > Party Supplies > Response Cards
839
+ Arts & Entertainment > Party & Celebration > Party Supplies > Sparklers
840
+ Arts & Entertainment > Party & Celebration > Party Supplies > Special Occasion Card Boxes & Holders
841
+ Arts & Entertainment > Party & Celebration > Party Supplies > Spray String
842
+ Arts & Entertainment > Party & Celebration > Special Effects
843
+ Arts & Entertainment > Party & Celebration > Special Effects > Disco Balls
844
+ Arts & Entertainment > Party & Celebration > Special Effects > Fog Machines
845
+ Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Controllers
846
+ Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Light Stands
847
+ Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Lighting
848
+ Arts & Entertainment > Party & Celebration > Trophies & Awards
849
+ Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Certificates
850
+ Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Pins & Medals
851
+ Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Plaques
852
+ Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Ribbons
853
+ Arts & Entertainment > Party & Celebration > Trophies & Awards > Trophies
854
+ Baby & Toddler
855
+ Baby & Toddler > Baby Bathing
856
+ Baby & Toddler > Baby Bathing > Baby Bathtubs & Bath Seats
857
+ Baby & Toddler > Baby Bathing > Shower Visors
858
+ Baby & Toddler > Baby Gift Sets
859
+ Baby & Toddler > Baby Health
860
+ Baby & Toddler > Baby Health > Baby Health & Grooming Kits
861
+ Baby & Toddler > Baby Health > Nasal Aspirators
862
+ Baby & Toddler > Baby Health > Pacifier Clips & Holders
863
+ Baby & Toddler > Baby Health > Pacifier Wipes
864
+ Baby & Toddler > Baby Health > Pacifiers & Teethers
865
+ Baby & Toddler > Baby Safety
866
+ Baby & Toddler > Baby Safety > Baby & Pet Gate Accessories
867
+ Baby & Toddler > Baby Safety > Baby & Pet Gates
868
+ Baby & Toddler > Baby Safety > Baby Monitors
869
+ Baby & Toddler > Baby Safety > Baby Safety Harnesses & Leashes
870
+ Baby & Toddler > Baby Safety > Baby Safety Locks & Guards
871
+ Baby & Toddler > Baby Safety > Baby Safety Rails
872
+ Baby & Toddler > Baby Toys & Activity Equipment
873
+ Baby & Toddler > Baby Toys & Activity Equipment > Alphabet Toys
874
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Activity Toys
875
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Bouncers & Rockers
876
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Jumpers & Swings
877
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Mobile Accessories
878
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Mobiles
879
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Soothers
880
+ Baby & Toddler > Baby Toys & Activity Equipment > Baby Walkers & Entertainers
881
+ Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms
882
+ Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms > Play Gyms
883
+ Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms > Play Mats
884
+ Baby & Toddler > Baby Toys & Activity Equipment > Play Yards
885
+ Baby & Toddler > Baby Toys & Activity Equipment > Push & Pull Toys
886
+ Baby & Toddler > Baby Toys & Activity Equipment > Rattles
887
+ Baby & Toddler > Baby Toys & Activity Equipment > Sorting & Stacking Toys
888
+ Baby & Toddler > Baby Transport
889
+ Baby & Toddler > Baby Transport > Baby & Toddler Car Seats
890
+ Baby & Toddler > Baby Transport > Baby Carriers
891
+ Baby & Toddler > Baby Transport > Baby Strollers
892
+ Baby & Toddler > Baby Transport Accessories
893
+ Baby & Toddler > Baby Transport Accessories > Baby & Toddler Car Seat Accessories
894
+ Baby & Toddler > Baby Transport Accessories > Baby Carrier Accessories
895
+ Baby & Toddler > Baby Transport Accessories > Baby Stroller Accessories
896
+ Baby & Toddler > Baby Transport Accessories > Baby Transport Liners & Sacks
897
+ Baby & Toddler > Baby Transport Accessories > Shopping Cart & High Chair Covers
898
+ Baby & Toddler > Diapering
899
+ Baby & Toddler > Diapering > Baby Wipe Dispensers & Warmers
900
+ Baby & Toddler > Diapering > Baby Wipes
901
+ Baby & Toddler > Diapering > Changing Mat & Tray Covers
902
+ Baby & Toddler > Diapering > Changing Mats & Trays
903
+ Baby & Toddler > Diapering > Diaper Kits
904
+ Baby & Toddler > Diapering > Diaper Liners
905
+ Baby & Toddler > Diapering > Diaper Organizers
906
+ Baby & Toddler > Diapering > Diaper Pail Accessories
907
+ Baby & Toddler > Diapering > Diaper Pails
908
+ Baby & Toddler > Diapering > Diaper Rash Treatments
909
+ Baby & Toddler > Diapering > Diaper Wet Bags
910
+ Baby & Toddler > Diapering > Diapers
911
+ Baby & Toddler > Nursing & Feeding
912
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food
913
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Cereal
914
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Drinks
915
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Food
916
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Formula
917
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Snacks
918
+ Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Toddler Nutrition Drinks & Shakes
919
+ Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners
920
+ Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners > Baby Bottle Liners
921
+ Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners > Baby Bottle Nipples
922
+ Baby & Toddler > Nursing & Feeding > Baby Bottles
923
+ Baby & Toddler > Nursing & Feeding > Baby Care Timers
924
+ Baby & Toddler > Nursing & Feeding > Bibs
925
+ Baby & Toddler > Nursing & Feeding > Bottle Warmers & Sterilizers
926
+ Baby & Toddler > Nursing & Feeding > Breast Milk Storage Containers
927
+ Baby & Toddler > Nursing & Feeding > Breast Pump Accessories
928
+ Baby & Toddler > Nursing & Feeding > Breast Pumps
929
+ Baby & Toddler > Nursing & Feeding > Burp Cloths
930
+ Baby & Toddler > Nursing & Feeding > Nursing Covers
931
+ Baby & Toddler > Nursing & Feeding > Nursing Pads & Shields
932
+ Baby & Toddler > Nursing & Feeding > Nursing Pillow Covers
933
+ Baby & Toddler > Nursing & Feeding > Nursing Pillows
934
+ Baby & Toddler > Nursing & Feeding > Sippy Cups
935
+ Baby & Toddler > Potty Training
936
+ Baby & Toddler > Potty Training > Potty Seats
937
+ Baby & Toddler > Potty Training > Potty Training Kits
938
+ Baby & Toddler > Swaddling & Receiving Blankets
939
+ Baby & Toddler > Swaddling & Receiving Blankets > Receiving Blankets
940
+ Baby & Toddler > Swaddling & Receiving Blankets > Swaddling Blankets
941
+ Business & Industrial
942
+ Business & Industrial > Advertising & Marketing
943
+ Business & Industrial > Advertising & Marketing > Brochures
944
+ Business & Industrial > Advertising & Marketing > Trade Show Counters
945
+ Business & Industrial > Advertising & Marketing > Trade Show Displays
946
+ Business & Industrial > Agriculture
947
+ Business & Industrial > Agriculture > Animal Husbandry
948
+ Business & Industrial > Agriculture > Animal Husbandry > Egg Incubators
949
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed
950
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Cattle Feed
951
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Chicken Feed
952
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Goat & Sheep Feed
953
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Mixed Herd Feed
954
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Pig Feed
955
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Feeders & Waterers
956
+ Business & Industrial > Agriculture > Animal Husbandry > Livestock Halters
957
+ Business & Industrial > Automation Control Components
958
+ Business & Industrial > Automation Control Components > Programmable Logic Controllers
959
+ Business & Industrial > Automation Control Components > Variable Frequency & Adjustable Speed Drives
960
+ Business & Industrial > Construction
961
+ Business & Industrial > Construction > Surveying
962
+ Business & Industrial > Construction > Traffic Cones & Barrels
963
+ Business & Industrial > Dentistry
964
+ Business & Industrial > Dentistry > Dental Cement
965
+ Business & Industrial > Dentistry > Dental Tools
966
+ Business & Industrial > Dentistry > Dental Tools > Dappen Dishes
967
+ Business & Industrial > Dentistry > Dental Tools > Dental Mirrors
968
+ Business & Industrial > Dentistry > Dental Tools > Dental Tool Sets
969
+ Business & Industrial > Dentistry > Dental Tools > Prophy Cups
970
+ Business & Industrial > Dentistry > Dental Tools > Prophy Heads
971
+ Business & Industrial > Dentistry > Prophy Paste
972
+ Business & Industrial > Film & Television
973
+ Business & Industrial > Finance & Insurance
974
+ Business & Industrial > Finance & Insurance > Bullion
975
+ Business & Industrial > Food Service
976
+ Business & Industrial > Food Service > Bakery Boxes
977
+ Business & Industrial > Food Service > Bus Tubs
978
+ Business & Industrial > Food Service > Check Presenters
979
+ Business & Industrial > Food Service > Concession Food Containers
980
+ Business & Industrial > Food Service > Disposable Lids
981
+ Business & Industrial > Food Service > Disposable Serveware
982
+ Business & Industrial > Food Service > Disposable Serveware > Disposable Serving Trays
983
+ Business & Industrial > Food Service > Disposable Tableware
984
+ Business & Industrial > Food Service > Disposable Tableware > Disposable Bowls
985
+ Business & Industrial > Food Service > Disposable Tableware > Disposable Cups
986
+ Business & Industrial > Food Service > Disposable Tableware > Disposable Cutlery
987
+ Business & Industrial > Food Service > Disposable Tableware > Disposable Plates
988
+ Business & Industrial > Food Service > Food Service Baskets
989
+ Business & Industrial > Food Service > Food Service Carts
990
+ Business & Industrial > Food Service > Food Washers & Dryers
991
+ Business & Industrial > Food Service > Hot Dog Rollers
992
+ Business & Industrial > Food Service > Ice Bins
993
+ Business & Industrial > Food Service > Plate & Dish Warmers
994
+ Business & Industrial > Food Service > Sneeze Guards
995
+ Business & Industrial > Food Service > Take-Out Containers
996
+ Business & Industrial > Food Service > Tilt Skillets
997
+ Business & Industrial > Food Service > Vending Machines
998
+ Business & Industrial > Forestry & Logging
999
+ Business & Industrial > Hairdressing & Cosmetology
1000
+ Business & Industrial > Hairdressing & Cosmetology > Hairdressing Capes & Neck Covers
1001
+ Business & Industrial > Hairdressing & Cosmetology > Pedicure Chairs
1002
+ Business & Industrial > Hairdressing & Cosmetology > Salon Chairs
1003
+ Business & Industrial > Heavy Machinery
1004
+ Business & Industrial > Heavy Machinery > Chippers
1005
+ Business & Industrial > Hotel & Hospitality
1006
+ Business & Industrial > Industrial Storage
1007
+ Business & Industrial > Industrial Storage > Industrial Cabinets
1008
+ Business & Industrial > Industrial Storage > Industrial Shelving
1009
+ Business & Industrial > Industrial Storage > Shipping Containers
1010
+ Business & Industrial > Industrial Storage > Wire Partitions, Enclosures & Doors
1011
+ Business & Industrial > Industrial Storage Accessories
1012
+ Business & Industrial > Janitorial Carts & Caddies
1013
+ Business & Industrial > Law Enforcement
1014
+ Business & Industrial > Law Enforcement > Cuffs
1015
+ Business & Industrial > Law Enforcement > Metal Detectors
1016
+ Business & Industrial > Manufacturing
1017
+ Business & Industrial > Material Handling
1018
+ Business & Industrial > Material Handling > Conveyors
1019
+ Business & Industrial > Material Handling > Lifts & Hoists
1020
+ Business & Industrial > Material Handling > Lifts & Hoists > Hoists, Cranes & Trolleys
1021
+ Business & Industrial > Material Handling > Lifts & Hoists > Jacks & Lift Trucks
1022
+ Business & Industrial > Material Handling > Lifts & Hoists > Personnel Lifts
1023
+ Business & Industrial > Material Handling > Lifts & Hoists > Pulleys, Blocks & Sheaves
1024
+ Business & Industrial > Material Handling > Lifts & Hoists > Winches
1025
+ Business & Industrial > Material Handling > Pallets & Loading Platforms
1026
+ Business & Industrial > Medical
1027
+ Business & Industrial > Medical > Hospital Curtains
1028
+ Business & Industrial > Medical > Hospital Gowns
1029
+ Business & Industrial > Medical > Medical Bedding
1030
+ Business & Industrial > Medical > Medical Equipment
1031
+ Business & Industrial > Medical > Medical Equipment > Automated External Defibrillators
1032
+ Business & Industrial > Medical > Medical Equipment > Gait Belts
1033
+ Business & Industrial > Medical > Medical Equipment > Medical Reflex Hammers & Tuning Forks
1034
+ Business & Industrial > Medical > Medical Equipment > Medical Stretchers & Gurneys
1035
+ Business & Industrial > Medical > Medical Equipment > Otoscopes & Ophthalmoscopes
1036
+ Business & Industrial > Medical > Medical Equipment > Patient Lifts
1037
+ Business & Industrial > Medical > Medical Equipment > Stethoscopes
1038
+ Business & Industrial > Medical > Medical Equipment > Vital Signs Monitor Accessories
1039
+ Business & Industrial > Medical > Medical Equipment > Vital Signs Monitors
1040
+ Business & Industrial > Medical > Medical Furniture
1041
+ Business & Industrial > Medical > Medical Furniture > Chiropractic Tables
1042
+ Business & Industrial > Medical > Medical Furniture > Examination Chairs & Tables
1043
+ Business & Industrial > Medical > Medical Furniture > Homecare & Hospital Beds
1044
+ Business & Industrial > Medical > Medical Furniture > Medical Cabinets
1045
+ Business & Industrial > Medical > Medical Furniture > Medical Carts
1046
+ Business & Industrial > Medical > Medical Furniture > Medical Carts > Crash Carts
1047
+ Business & Industrial > Medical > Medical Furniture > Medical Carts > IV Poles & Carts
1048
+ Business & Industrial > Medical > Medical Furniture > Surgical Tables
1049
+ Business & Industrial > Medical > Medical Instruments
1050
+ Business & Industrial > Medical > Medical Instruments > Medical Forceps
1051
+ Business & Industrial > Medical > Medical Instruments > Scalpel Blades
1052
+ Business & Industrial > Medical > Medical Instruments > Scalpels
1053
+ Business & Industrial > Medical > Medical Instruments > Surgical Needles & Sutures
1054
+ Business & Industrial > Medical > Medical Supplies
1055
+ Business & Industrial > Medical > Medical Supplies > Disposable Gloves
1056
+ Business & Industrial > Medical > Medical Supplies > Finger Cots
1057
+ Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes
1058
+ Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes > Medical Needle & Syringe Sets
1059
+ Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes > Medical Needles
1060
+ Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes > Medical Syringes
1061
+ Business & Industrial > Medical > Medical Supplies > Ostomy Supplies
1062
+ Business & Industrial > Medical > Medical Supplies > Tongue Depressors
1063
+ Business & Industrial > Medical > Medical Teaching Equipment
1064
+ Business & Industrial > Medical > Medical Teaching Equipment > Medical & Emergency Response Training Mannequins
1065
+ Business & Industrial > Medical > Scrub Caps
1066
+ Business & Industrial > Medical > Scrubs
1067
+ Business & Industrial > Medical > Surgical Gowns
1068
+ Business & Industrial > Mining & Quarrying
1069
+ Business & Industrial > Piercing & Tattooing
1070
+ Business & Industrial > Piercing & Tattooing > Piercing Supplies
1071
+ Business & Industrial > Piercing & Tattooing > Piercing Supplies > Piercing Needles
1072
+ Business & Industrial > Piercing & Tattooing > Tattooing Supplies
1073
+ Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattoo Cover-Ups
1074
+ Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Inks
1075
+ Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Machines
1076
+ Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Needles
1077
+ Business & Industrial > Retail
1078
+ Business & Industrial > Retail > Clothing Display Racks
1079
+ Business & Industrial > Retail > Display Mannequins
1080
+ Business & Industrial > Retail > Mannequin Parts
1081
+ Business & Industrial > Retail > Money Handling
1082
+ Business & Industrial > Retail > Money Handling > Banknote Verifiers
1083
+ Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories
1084
+ Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Cash Drawers & Trays
1085
+ Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Credit Card Terminals
1086
+ Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Signature Capture Pads
1087
+ Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals
1088
+ Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals > Cash Registers
1089
+ Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals > POS Terminals
1090
+ Business & Industrial > Retail > Money Handling > Coin & Bill Counters
1091
+ Business & Industrial > Retail > Money Handling > Money Changers
1092
+ Business & Industrial > Retail > Money Handling > Money Deposit Bags
1093
+ Business & Industrial > Retail > Money Handling > Paper Coin Wrappers & Bill Straps
1094
+ Business & Industrial > Retail > Paper & Plastic Shopping Bags
1095
+ Business & Industrial > Retail > Pricing Guns
1096
+ Business & Industrial > Retail > Retail Display Cases
1097
+ Business & Industrial > Retail > Retail Display Props & Models
1098
+ Business & Industrial > Science & Laboratory
1099
+ Business & Industrial > Science & Laboratory > Biochemicals
1100
+ Business & Industrial > Science & Laboratory > Dissection Kits
1101
+ Business & Industrial > Science & Laboratory > Laboratory Chemicals
1102
+ Business & Industrial > Science & Laboratory > Laboratory Equipment
1103
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Autoclaves
1104
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Centrifuges
1105
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Dry Ice Makers
1106
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Freeze-Drying Machines
1107
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Blenders
1108
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Freezers
1109
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Funnels
1110
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Hot Plates
1111
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Ovens
1112
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories
1113
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Cameras
1114
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Eyepieces & Adapters
1115
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Objective Lenses
1116
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Replacement Bulbs
1117
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Slides
1118
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscopes
1119
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Microtomes
1120
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometer Accessories
1121
+ Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometers
1122
+ Business & Industrial > Science & Laboratory > Laboratory Specimens
1123
+ Business & Industrial > Science & Laboratory > Laboratory Supplies
1124
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Beakers
1125
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Graduated Cylinders
1126
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Laboratory Flasks
1127
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Petri Dishes
1128
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Pipettes
1129
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tube Racks
1130
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tubes
1131
+ Business & Industrial > Science & Laboratory > Laboratory Supplies > Wash Bottles
1132
+ Business & Industrial > Signage
1133
+ Business & Industrial > Signage > Business Hour Signs
1134
+ Business & Industrial > Signage > Digital Signs
1135
+ Business & Industrial > Signage > Electric Signs
1136
+ Business & Industrial > Signage > Electric Signs > LED Signs
1137
+ Business & Industrial > Signage > Electric Signs > Neon Signs
1138
+ Business & Industrial > Signage > Emergency & Exit Signs
1139
+ Business & Industrial > Signage > Facility Identification Signs
1140
+ Business & Industrial > Signage > Open & Closed Signs
1141
+ Business & Industrial > Signage > Parking Signs & Permits
1142
+ Business & Industrial > Signage > Policy Signs
1143
+ Business & Industrial > Signage > Retail & Sale Signs
1144
+ Business & Industrial > Signage > Road & Traffic Signs
1145
+ Business & Industrial > Signage > Safety & Warning Signs
1146
+ Business & Industrial > Signage > Security Signs
1147
+ Business & Industrial > Signage > Sidewalk & Yard Signs
1148
+ Business & Industrial > Work Safety Protective Gear
1149
+ Business & Industrial > Work Safety Protective Gear > Bullet Proof Vests
1150
+ Business & Industrial > Work Safety Protective Gear > Gas Mask & Respirator Accessories
1151
+ Business & Industrial > Work Safety Protective Gear > Hardhats
1152
+ Business & Industrial > Work Safety Protective Gear > Hazardous Material Suits
1153
+ Business & Industrial > Work Safety Protective Gear > Protective Aprons
1154
+ Business & Industrial > Work Safety Protective Gear > Protective Eyewear
1155
+ Business & Industrial > Work Safety Protective Gear > Protective Masks
1156
+ Business & Industrial > Work Safety Protective Gear > Protective Masks > Dust Masks
1157
+ Business & Industrial > Work Safety Protective Gear > Protective Masks > Fireman's Masks
1158
+ Business & Industrial > Work Safety Protective Gear > Protective Masks > Gas Masks & Respirators
1159
+ Business & Industrial > Work Safety Protective Gear > Protective Masks > Medical Masks
1160
+ Business & Industrial > Work Safety Protective Gear > Safety Gloves
1161
+ Business & Industrial > Work Safety Protective Gear > Safety Knee Pads
1162
+ Business & Industrial > Work Safety Protective Gear > Welding Helmets
1163
+ Business & Industrial > Work Safety Protective Gear > Work Safety Harnesses
1164
+ Business & Industrial > Work Safety Protective Gear > Work Safety Tethers
1165
+ Cameras & Optics
1166
+ Cameras & Optics > Camera & Optic Accessories
1167
+ Cameras & Optics > Camera & Optic Accessories > Camera & Optic Replacement Cables
1168
+ Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses
1169
+ Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Camera Lenses
1170
+ Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Surveillance Camera Lenses
1171
+ Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Video Camera Lenses
1172
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories
1173
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens & Filter Adapter Rings
1174
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Bags
1175
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Caps
1176
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Converters
1177
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Filters
1178
+ Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Hoods
1179
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories
1180
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Accessory Sets
1181
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Bags & Cases
1182
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Body Replacement Panels & Doors
1183
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Digital Backs
1184
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Film
1185
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Flash Accessories
1186
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Flashes
1187
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Focus Devices
1188
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Gears
1189
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Grips
1190
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Image Sensors
1191
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Lens Zoom Units
1192
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Remote Controls
1193
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Replacement Buttons & Knobs
1194
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Replacement Screens & Displays
1195
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Silencers & Sound Blimps
1196
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Stabilizers & Supports
1197
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Straps
1198
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Sun Hoods & Viewfinder Attachments
1199
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Flash Brackets
1200
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > On-Camera Monitors
1201
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Surveillance Camera Accessories
1202
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Underwater Camera Housing Accessories
1203
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Underwater Camera Housings
1204
+ Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Video Camera Lights
1205
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories
1206
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Binocular & Monocular Accessories
1207
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Optics Bags & Cases
1208
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Rangefinder Accessories
1209
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Spotting Scope Accessories
1210
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Telescope Accessories
1211
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Thermal Optic Accessories
1212
+ Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Weapon Scope & Sight Accessories
1213
+ Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories
1214
+ Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Cases
1215
+ Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Heads
1216
+ Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Collars & Mounts
1217
+ Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Handles
1218
+ Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Spreaders
1219
+ Cameras & Optics > Camera & Optic Accessories > Tripods & Monopods
1220
+ Cameras & Optics > Cameras
1221
+ Cameras & Optics > Cameras > Borescopes
1222
+ Cameras & Optics > Cameras > Digital Cameras
1223
+ Cameras & Optics > Cameras > Disposable Cameras
1224
+ Cameras & Optics > Cameras > Film Cameras
1225
+ Cameras & Optics > Cameras > Surveillance Cameras
1226
+ Cameras & Optics > Cameras > Trail Cameras
1227
+ Cameras & Optics > Cameras > Video Cameras
1228
+ Cameras & Optics > Cameras > Webcams
1229
+ Cameras & Optics > Optics
1230
+ Cameras & Optics > Optics > Binoculars
1231
+ Cameras & Optics > Optics > Monoculars
1232
+ Cameras & Optics > Optics > Rangefinders
1233
+ Cameras & Optics > Optics > Scopes
1234
+ Cameras & Optics > Optics > Scopes > Spotting Scopes
1235
+ Cameras & Optics > Optics > Scopes > Telescopes
1236
+ Cameras & Optics > Optics > Scopes > Weapon Scopes & Sights
1237
+ Cameras & Optics > Photography
1238
+ Cameras & Optics > Photography > Darkroom
1239
+ Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment
1240
+ Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Copystands
1241
+ Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Darkroom Sinks
1242
+ Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Developing Tanks & Reels
1243
+ Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Print Trays, Washers & Dryers
1244
+ Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Retouching Equipment & Supplies
1245
+ Cameras & Optics > Photography > Darkroom > Enlarging Equipment
1246
+ Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Easels
1247
+ Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Timers
1248
+ Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Focusing Aids
1249
+ Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Analyzers
1250
+ Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Enlargers
1251
+ Cameras & Optics > Photography > Darkroom > Photographic Chemicals
1252
+ Cameras & Optics > Photography > Darkroom > Photographic Paper
1253
+ Cameras & Optics > Photography > Darkroom > Safelights
1254
+ Cameras & Optics > Photography > Lighting & Studio
1255
+ Cameras & Optics > Photography > Lighting & Studio > Light Meter Accessories
1256
+ Cameras & Optics > Photography > Lighting & Studio > Light Meters
1257
+ Cameras & Optics > Photography > Lighting & Studio > Studio Backgrounds
1258
+ Cameras & Optics > Photography > Lighting & Studio > Studio Light & Flash Accessories
1259
+ Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls
1260
+ Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Flash Diffusers
1261
+ Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Flash Reflectors
1262
+ Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Lighting Filters & Gobos
1263
+ Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Softboxes
1264
+ Cameras & Optics > Photography > Lighting & Studio > Studio Lights & Flashes
1265
+ Cameras & Optics > Photography > Lighting & Studio > Studio Stand & Mount Accessories
1266
+ Cameras & Optics > Photography > Lighting & Studio > Studio Stands & Mounts
1267
+ Cameras & Optics > Photography > Photo Mounting Supplies
1268
+ Cameras & Optics > Photography > Photo Negative & Slide Storage
1269
+ Electronics
1270
+ Electronics > Arcade Equipment
1271
+ Electronics > Arcade Equipment > Basketball Arcade Games
1272
+ Electronics > Arcade Equipment > Pinball Machine Accessories
1273
+ Electronics > Arcade Equipment > Pinball Machines
1274
+ Electronics > Arcade Equipment > Skee-Ball Machines
1275
+ Electronics > Arcade Equipment > Video Game Arcade Cabinet Accessories
1276
+ Electronics > Arcade Equipment > Video Game Arcade Cabinets
1277
+ Electronics > Audio
1278
+ Electronics > Audio > Audio Accessories
1279
+ Electronics > Audio > Audio Accessories > Audio & Video Receiver Accessories
1280
+ Electronics > Audio > Audio Accessories > Headphone & Headset Accessories
1281
+ Electronics > Audio > Audio Accessories > Headphone & Headset Accessories > Headphone Cushions & Tips
1282
+ Electronics > Audio > Audio Accessories > Karaoke System Accessories
1283
+ Electronics > Audio > Audio Accessories > Karaoke System Accessories > Karaoke Chips
1284
+ Electronics > Audio > Audio Accessories > MP3 Player Accessories
1285
+ Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player & Mobile Phone Accessory Sets
1286
+ Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player Cases
1287
+ Electronics > Audio > Audio Accessories > Microphone Accessories
1288
+ Electronics > Audio > Audio Accessories > Microphone Stands
1289
+ Electronics > Audio > Audio Accessories > Satellite Radio Accessories
1290
+ Electronics > Audio > Audio Accessories > Speaker Accessories
1291
+ Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Bags, Covers & Cases
1292
+ Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Components & Kits
1293
+ Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stand Bags
1294
+ Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stands & Mounts
1295
+ Electronics > Audio > Audio Accessories > Speaker Accessories > Tactile Transducers
1296
+ Electronics > Audio > Audio Accessories > Turntable Accessories
1297
+ Electronics > Audio > Audio Components
1298
+ Electronics > Audio > Audio Components > Audio & Video Receivers
1299
+ Electronics > Audio > Audio Components > Audio Amplifiers
1300
+ Electronics > Audio > Audio Components > Audio Amplifiers > Headphone Amplifiers
1301
+ Electronics > Audio > Audio Components > Audio Amplifiers > Power Amplifiers
1302
+ Electronics > Audio > Audio Components > Audio Mixers
1303
+ Electronics > Audio > Audio Components > Audio Transmitters
1304
+ Electronics > Audio > Audio Components > Audio Transmitters > Bluetooth Transmitters
1305
+ Electronics > Audio > Audio Components > Audio Transmitters > FM Transmitters
1306
+ Electronics > Audio > Audio Components > Channel Strips
1307
+ Electronics > Audio > Audio Components > Direct Boxes
1308
+ Electronics > Audio > Audio Components > Headphones & Headsets
1309
+ Electronics > Audio > Audio Components > Headphones & Headsets > Headphones
1310
+ Electronics > Audio > Audio Components > Headphones & Headsets > Headsets
1311
+ Electronics > Audio > Audio Components > Microphones
1312
+ Electronics > Audio > Audio Components > Signal Processors
1313
+ Electronics > Audio > Audio Components > Signal Processors > Crossovers
1314
+ Electronics > Audio > Audio Components > Signal Processors > Effects Processors
1315
+ Electronics > Audio > Audio Components > Signal Processors > Equalizers
1316
+ Electronics > Audio > Audio Components > Signal Processors > Loudspeaker Management Systems
1317
+ Electronics > Audio > Audio Components > Signal Processors > Microphone Preamps
1318
+ Electronics > Audio > Audio Components > Signal Processors > Noise Gates & Compressors
1319
+ Electronics > Audio > Audio Components > Signal Processors > Phono Preamps
1320
+ Electronics > Audio > Audio Components > Speakers
1321
+ Electronics > Audio > Audio Components > Studio Recording Bundles
1322
+ Electronics > Audio > Audio Players & Recorders
1323
+ Electronics > Audio > Audio Players & Recorders > Boomboxes
1324
+ Electronics > Audio > Audio Players & Recorders > CD Players & Recorders
1325
+ Electronics > Audio > Audio Players & Recorders > Cassette Players & Recorders
1326
+ Electronics > Audio > Audio Players & Recorders > Home Theater Systems
1327
+ Electronics > Audio > Audio Players & Recorders > Jukeboxes
1328
+ Electronics > Audio > Audio Players & Recorders > Karaoke Systems
1329
+ Electronics > Audio > Audio Players & Recorders > MP3 Players
1330
+ Electronics > Audio > Audio Players & Recorders > MiniDisc Players & Recorders
1331
+ Electronics > Audio > Audio Players & Recorders > Multitrack Recorders
1332
+ Electronics > Audio > Audio Players & Recorders > Radios
1333
+ Electronics > Audio > Audio Players & Recorders > Reel-to-Reel Tape Players & Recorders
1334
+ Electronics > Audio > Audio Players & Recorders > Stereo Systems
1335
+ Electronics > Audio > Audio Players & Recorders > Turntables & Record Players
1336
+ Electronics > Audio > Audio Players & Recorders > Voice Recorders
1337
+ Electronics > Audio > Bullhorns
1338
+ Electronics > Audio > DJ & Specialty Audio
1339
+ Electronics > Audio > DJ & Specialty Audio > DJ CD Players
1340
+ Electronics > Audio > DJ & Specialty Audio > DJ Systems
1341
+ Electronics > Audio > Public Address Systems
1342
+ Electronics > Audio > Stage Equipment
1343
+ Electronics > Audio > Stage Equipment > Wireless Transmitters
1344
+ Electronics > Circuit Boards & Components
1345
+ Electronics > Circuit Boards & Components > Circuit Board Accessories
1346
+ Electronics > Circuit Boards & Components > Circuit Decoders & Encoders
1347
+ Electronics > Circuit Boards & Components > Circuit Prototyping
1348
+ Electronics > Circuit Boards & Components > Circuit Prototyping > Breadboards
1349
+ Electronics > Circuit Boards & Components > Electronic Filters
1350
+ Electronics > Circuit Boards & Components > Passive Circuit Components
1351
+ Electronics > Circuit Boards & Components > Passive Circuit Components > Capacitors
1352
+ Electronics > Circuit Boards & Components > Passive Circuit Components > Electronic Oscillators
1353
+ Electronics > Circuit Boards & Components > Passive Circuit Components > Inductors
1354
+ Electronics > Circuit Boards & Components > Passive Circuit Components > Resistors
1355
+ Electronics > Circuit Boards & Components > Printed Circuit Boards
1356
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Camera Circuit Boards
1357
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards
1358
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Computer Inverter Boards
1359
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Hard Drive Circuit Boards
1360
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Motherboards
1361
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Development Boards
1362
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Exercise Machine Circuit Boards
1363
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Household Appliance Circuit Boards
1364
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Pool & Spa Circuit Boards
1365
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Printer, Copier, & Fax Machine Circuit Boards
1366
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Scanner Circuit Boards
1367
+ Electronics > Circuit Boards & Components > Printed Circuit Boards > Television Circuit Boards
1368
+ Electronics > Circuit Boards & Components > Semiconductors
1369
+ Electronics > Circuit Boards & Components > Semiconductors > Diodes
1370
+ Electronics > Circuit Boards & Components > Semiconductors > Integrated Circuits & Chips
1371
+ Electronics > Circuit Boards & Components > Semiconductors > Microcontrollers
1372
+ Electronics > Circuit Boards & Components > Semiconductors > Transistors
1373
+ Electronics > Communications
1374
+ Electronics > Communications > Answering Machines
1375
+ Electronics > Communications > Caller IDs
1376
+ Electronics > Communications > Communication Radio Accessories
1377
+ Electronics > Communications > Communication Radios
1378
+ Electronics > Communications > Communication Radios > CB Radios
1379
+ Electronics > Communications > Communication Radios > Radio Scanners
1380
+ Electronics > Communications > Communication Radios > Two-Way Radios
1381
+ Electronics > Communications > Intercom Accessories
1382
+ Electronics > Communications > Intercoms
1383
+ Electronics > Communications > Pagers
1384
+ Electronics > Communications > Telephony
1385
+ Electronics > Communications > Telephony > Conference Phones
1386
+ Electronics > Communications > Telephony > Corded Phones
1387
+ Electronics > Communications > Telephony > Cordless Phones
1388
+ Electronics > Communications > Telephony > Mobile Phone Accessories
1389
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Camera Accessories
1390
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Cases
1391
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Charms & Straps
1392
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards
1393
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards > Mobile Phone Pre-Paid Cards
1394
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards > SIM Cards
1395
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Replacement Parts
1396
+ Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Stands
1397
+ Electronics > Communications > Telephony > Mobile Phone Accessories > SIM Card Ejection Tools
1398
+ Electronics > Communications > Telephony > Mobile Phones
1399
+ Electronics > Communications > Telephony > Mobile Phones > Contract Mobile Phones
1400
+ Electronics > Communications > Telephony > Mobile Phones > Pre-paid Mobile Phones
1401
+ Electronics > Communications > Telephony > Mobile Phones > Unlocked Mobile Phones
1402
+ Electronics > Communications > Telephony > Satellite Phones
1403
+ Electronics > Communications > Telephony > Telephone Accessories
1404
+ Electronics > Communications > Telephony > Telephone Accessories > Phone Cards
1405
+ Electronics > Communications > Video Conferencing
1406
+ Electronics > Components
1407
+ Electronics > Components > Accelerometers
1408
+ Electronics > Components > Converters
1409
+ Electronics > Components > Converters > Audio Converters
1410
+ Electronics > Components > Converters > Scan Converters
1411
+ Electronics > Components > Electronics Component Connectors
1412
+ Electronics > Components > Modulators
1413
+ Electronics > Components > Splitters
1414
+ Electronics > Computers
1415
+ Electronics > Computers > Barebone Computers
1416
+ Electronics > Computers > Computer Servers
1417
+ Electronics > Computers > Desktop Computers
1418
+ Electronics > Computers > Handheld Devices
1419
+ Electronics > Computers > Handheld Devices > Data Collectors
1420
+ Electronics > Computers > Handheld Devices > E-Book Readers
1421
+ Electronics > Computers > Handheld Devices > PDAs
1422
+ Electronics > Computers > Interactive Kiosks
1423
+ Electronics > Computers > Laptops
1424
+ Electronics > Computers > Smart Glasses
1425
+ Electronics > Computers > Tablet Computers
1426
+ Electronics > Computers > Thin & Zero Clients
1427
+ Electronics > Computers > Thin & Zero Clients > Thin Client Computers
1428
+ Electronics > Computers > Thin & Zero Clients > Zero Client Computers
1429
+ Electronics > Computers > Touch Table Computers
1430
+ Electronics > Electronics Accessories
1431
+ Electronics > Electronics Accessories > Adapters
1432
+ Electronics > Electronics Accessories > Adapters > Audio & Video Cable Adapters & Couplers
1433
+ Electronics > Electronics Accessories > Adapters > Memory Card Adapters
1434
+ Electronics > Electronics Accessories > Adapters > USB Adapters
1435
+ Electronics > Electronics Accessories > Antenna Accessories
1436
+ Electronics > Electronics Accessories > Antenna Accessories > Antenna Mounts & Brackets
1437
+ Electronics > Electronics Accessories > Antenna Accessories > Antenna Rotators
1438
+ Electronics > Electronics Accessories > Antenna Accessories > Satellite LNBs
1439
+ Electronics > Electronics Accessories > Antennas
1440
+ Electronics > Electronics Accessories > Audio & Video Splitters & Switches
1441
+ Electronics > Electronics Accessories > Audio & Video Splitters & Switches > DVI Splitters & Switches
1442
+ Electronics > Electronics Accessories > Audio & Video Splitters & Switches > HDMI Splitters & Switches
1443
+ Electronics > Electronics Accessories > Audio & Video Splitters & Switches > VGA Splitters & Switches
1444
+ Electronics > Electronics Accessories > Blank Media
1445
+ Electronics > Electronics Accessories > Cable Management
1446
+ Electronics > Electronics Accessories > Cable Management > Cable Clips
1447
+ Electronics > Electronics Accessories > Cable Management > Cable Tie Guns
1448
+ Electronics > Electronics Accessories > Cable Management > Cable Trays
1449
+ Electronics > Electronics Accessories > Cable Management > Patch Panels
1450
+ Electronics > Electronics Accessories > Cable Management > Wire & Cable Identification Markers
1451
+ Electronics > Electronics Accessories > Cable Management > Wire & Cable Sleeves
1452
+ Electronics > Electronics Accessories > Cable Management > Wire & Cable Ties
1453
+ Electronics > Electronics Accessories > Cables
1454
+ Electronics > Electronics Accessories > Cables > Audio & Video Cables
1455
+ Electronics > Electronics Accessories > Cables > KVM Cables
1456
+ Electronics > Electronics Accessories > Cables > Network Cables
1457
+ Electronics > Electronics Accessories > Cables > Storage & Data Transfer Cables
1458
+ Electronics > Electronics Accessories > Cables > System & Power Cables
1459
+ Electronics > Electronics Accessories > Cables > Telephone Cables
1460
+ Electronics > Electronics Accessories > Computer Accessories
1461
+ Electronics > Electronics Accessories > Computer Accessories > Computer Accessory Sets
1462
+ Electronics > Electronics Accessories > Computer Accessories > Computer Covers & Skins
1463
+ Electronics > Electronics Accessories > Computer Accessories > Computer Risers & Stands
1464
+ Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories
1465
+ Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories
1466
+ Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories > E-Book Reader Cases
1467
+ Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > PDA Accessories
1468
+ Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > PDA Accessories > PDA Cases
1469
+ Electronics > Electronics Accessories > Computer Accessories > Keyboard & Mouse Wrist Rests
1470
+ Electronics > Electronics Accessories > Computer Accessories > Keyboard Trays & Platforms
1471
+ Electronics > Electronics Accessories > Computer Accessories > Laptop Docking Stations
1472
+ Electronics > Electronics Accessories > Computer Accessories > Mouse Pads
1473
+ Electronics > Electronics Accessories > Computer Accessories > Stylus Pen Nibs & Refills
1474
+ Electronics > Electronics Accessories > Computer Accessories > Stylus Pens
1475
+ Electronics > Electronics Accessories > Computer Accessories > Tablet Computer Docks & Stands
1476
+ Electronics > Electronics Accessories > Computer Components
1477
+ Electronics > Electronics Accessories > Computer Components > Blade Server Enclosures
1478
+ Electronics > Electronics Accessories > Computer Components > Computer Backplates & I/O Shields
1479
+ Electronics > Electronics Accessories > Computer Components > Computer Power Supplies
1480
+ Electronics > Electronics Accessories > Computer Components > Computer Processors
1481
+ Electronics > Electronics Accessories > Computer Components > Computer Racks & Mounts
1482
+ Electronics > Electronics Accessories > Computer Components > Computer Starter Kits
1483
+ Electronics > Electronics Accessories > Computer Components > Computer System Cooling Parts
1484
+ Electronics > Electronics Accessories > Computer Components > Desktop Computer & Server Cases
1485
+ Electronics > Electronics Accessories > Computer Components > E-Book Reader Parts
1486
+ Electronics > Electronics Accessories > Computer Components > E-Book Reader Parts > E-Book Reader Screens & Screen Digitizers
1487
+ Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters
1488
+ Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Audio Cards & Adapters
1489
+ Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Computer Interface Cards & Adapters
1490
+ Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Riser Cards
1491
+ Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > TV Tuner Cards & Adapters
1492
+ Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Video Cards & Adapters
1493
+ Electronics > Electronics Accessories > Computer Components > Input Device Accessories
1494
+ Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Barcode Scanner Stands
1495
+ Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Game Controller Accessories
1496
+ Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Keyboard Keys & Caps
1497
+ Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Mice & Trackball Accessories
1498
+ Electronics > Electronics Accessories > Computer Components > Input Devices
1499
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Barcode Scanners
1500
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Digital Note Taking Pens
1501
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Electronic Card Readers
1502
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Fingerprint Readers
1503
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers
1504
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Game Racing Wheels
1505
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Game Remotes
1506
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Gaming Pads
1507
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Joystick Controllers
1508
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Musical Instrument Game Controllers
1509
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Gesture Control Input Devices
1510
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Graphics Tablets
1511
+ Electronics > Electronics Accessories > Computer Components > Input Devices > KVM Switches
1512
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Keyboards
1513
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Memory Card Readers
1514
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Mice & Trackballs
1515
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Numeric Keypads
1516
+ Electronics > Electronics Accessories > Computer Components > Input Devices > Touchpads
1517
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts
1518
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Hinges
1519
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Housings & Trim
1520
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Cables
1521
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Keyboards
1522
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Screens
1523
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Speakers
1524
+ Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Screen Digitizers
1525
+ Electronics > Electronics Accessories > Computer Components > Storage Devices
1526
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators
1527
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > CD/DVD Duplicators
1528
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > Hard Drive Duplicators
1529
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > USB Drive Duplicators
1530
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Floppy Drives
1531
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories
1532
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Carrying Cases
1533
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Docks
1534
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Enclosures & Mounts
1535
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Arrays
1536
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drives
1537
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Network Storage Systems
1538
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Optical Drives
1539
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > Tape Drives
1540
+ Electronics > Electronics Accessories > Computer Components > Storage Devices > USB Flash Drives
1541
+ Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts
1542
+ Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Housings & Trim
1543
+ Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Replacement Speakers
1544
+ Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Screens & Screen Digitizers
1545
+ Electronics > Electronics Accessories > Computer Components > USB & FireWire Hubs
1546
+ Electronics > Electronics Accessories > Electronics Cleaners
1547
+ Electronics > Electronics Accessories > Electronics Films & Shields
1548
+ Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals
1549
+ Electronics > Electronics Accessories > Electronics Films & Shields > Keyboard Protectors
1550
+ Electronics > Electronics Accessories > Electronics Films & Shields > Privacy Filters
1551
+ Electronics > Electronics Accessories > Electronics Films & Shields > Screen Protectors
1552
+ Electronics > Electronics Accessories > Memory
1553
+ Electronics > Electronics Accessories > Memory > Cache Memory
1554
+ Electronics > Electronics Accessories > Memory > Flash Memory
1555
+ Electronics > Electronics Accessories > Memory > Flash Memory > Flash Memory Cards
1556
+ Electronics > Electronics Accessories > Memory > RAM
1557
+ Electronics > Electronics Accessories > Memory > ROM
1558
+ Electronics > Electronics Accessories > Memory > Video Memory
1559
+ Electronics > Electronics Accessories > Memory Accessories
1560
+ Electronics > Electronics Accessories > Memory Accessories > Memory Cases
1561
+ Electronics > Electronics Accessories > Mobile Phone & Tablet Tripods & Monopods
1562
+ Electronics > Electronics Accessories > Power
1563
+ Electronics > Electronics Accessories > Power > Batteries
1564
+ Electronics > Electronics Accessories > Power > Batteries > Camera Batteries
1565
+ Electronics > Electronics Accessories > Power > Batteries > Cordless Phone Batteries
1566
+ Electronics > Electronics Accessories > Power > Batteries > E-Book Reader Batteries
1567
+ Electronics > Electronics Accessories > Power > Batteries > General Purpose Batteries
1568
+ Electronics > Electronics Accessories > Power > Batteries > Laptop Batteries
1569
+ Electronics > Electronics Accessories > Power > Batteries > MP3 Player Batteries
1570
+ Electronics > Electronics Accessories > Power > Batteries > Mobile Phone Batteries
1571
+ Electronics > Electronics Accessories > Power > Batteries > PDA Batteries
1572
+ Electronics > Electronics Accessories > Power > Batteries > Tablet Computer Batteries
1573
+ Electronics > Electronics Accessories > Power > Batteries > UPS Batteries
1574
+ Electronics > Electronics Accessories > Power > Batteries > Video Camera Batteries
1575
+ Electronics > Electronics Accessories > Power > Batteries > Video Game Console & Controller Batteries
1576
+ Electronics > Electronics Accessories > Power > Battery Accessories
1577
+ Electronics > Electronics Accessories > Power > Battery Accessories > Battery Charge Controllers
1578
+ Electronics > Electronics Accessories > Power > Battery Accessories > Battery Holders
1579
+ Electronics > Electronics Accessories > Power > Battery Accessories > Camera Battery Chargers
1580
+ Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Chargers
1581
+ Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Testers
1582
+ Electronics > Electronics Accessories > Power > Fuel Cells
1583
+ Electronics > Electronics Accessories > Power > Power Adapter & Charger Accessories
1584
+ Electronics > Electronics Accessories > Power > Power Adapters & Chargers
1585
+ Electronics > Electronics Accessories > Power > Power Control Units
1586
+ Electronics > Electronics Accessories > Power > Power Strips & Surge Suppressors
1587
+ Electronics > Electronics Accessories > Power > Power Supply Enclosures
1588
+ Electronics > Electronics Accessories > Power > Surge Protection Devices
1589
+ Electronics > Electronics Accessories > Power > Travel Converters & Adapters
1590
+ Electronics > Electronics Accessories > Power > UPS
1591
+ Electronics > Electronics Accessories > Power > UPS Accessories
1592
+ Electronics > Electronics Accessories > Remote Controls
1593
+ Electronics > Electronics Accessories > Signal Boosters
1594
+ Electronics > Electronics Accessories > Signal Jammers
1595
+ Electronics > Electronics Accessories > Signal Jammers > GPS Jammers
1596
+ Electronics > Electronics Accessories > Signal Jammers > Mobile Phone Jammers
1597
+ Electronics > Electronics Accessories > Signal Jammers > Radar Jammers
1598
+ Electronics > GPS Accessories
1599
+ Electronics > GPS Accessories > GPS Cases
1600
+ Electronics > GPS Accessories > GPS Mounts
1601
+ Electronics > GPS Navigation Systems
1602
+ Electronics > GPS Tracking Devices
1603
+ Electronics > Marine Electronics
1604
+ Electronics > Marine Electronics > Fish Finders
1605
+ Electronics > Marine Electronics > Marine Audio & Video Receivers
1606
+ Electronics > Marine Electronics > Marine Chartplotters & GPS
1607
+ Electronics > Marine Electronics > Marine Radar
1608
+ Electronics > Marine Electronics > Marine Radios
1609
+ Electronics > Marine Electronics > Marine Speakers
1610
+ Electronics > Networking
1611
+ Electronics > Networking > Bridges & Routers
1612
+ Electronics > Networking > Bridges & Routers > Network Bridges
1613
+ Electronics > Networking > Bridges & Routers > VoIP Gateways & Routers
1614
+ Electronics > Networking > Bridges & Routers > Wireless Access Points
1615
+ Electronics > Networking > Bridges & Routers > Wireless Routers
1616
+ Electronics > Networking > Concentrators & Multiplexers
1617
+ Electronics > Networking > Hubs & Switches
1618
+ Electronics > Networking > Modem Accessories
1619
+ Electronics > Networking > Modems
1620
+ Electronics > Networking > Network Cards & Adapters
1621
+ Electronics > Networking > Network Security & Firewall Devices
1622
+ Electronics > Networking > Power Over Ethernet Adapters
1623
+ Electronics > Networking > Print Servers
1624
+ Electronics > Networking > Repeaters & Transceivers
1625
+ Electronics > Print, Copy, Scan & Fax
1626
+ Electronics > Print, Copy, Scan & Fax > 3D Printer Accessories
1627
+ Electronics > Print, Copy, Scan & Fax > 3D Printers
1628
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories
1629
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables
1630
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Drums & Drum Kits
1631
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Filters
1632
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Maintenance Kits
1633
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Ribbons
1634
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printheads
1635
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Toner & Inkjet Cartridge Refills
1636
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Toner & Inkjet Cartridges
1637
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Duplexers
1638
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Memory
1639
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Stands
1640
+ Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer, Copier & Fax Machine Replacement Parts
1641
+ Electronics > Print, Copy, Scan & Fax > Printers, Copiers & Fax Machines
1642
+ Electronics > Print, Copy, Scan & Fax > Scanner Accessories
1643
+ Electronics > Print, Copy, Scan & Fax > Scanners
1644
+ Electronics > Radar Detectors
1645
+ Electronics > Speed Radars
1646
+ Electronics > Toll Collection Devices
1647
+ Electronics > Video
1648
+ Electronics > Video > Computer Monitors
1649
+ Electronics > Video > Projectors
1650
+ Electronics > Video > Projectors > Multimedia Projectors
1651
+ Electronics > Video > Projectors > Overhead Projectors
1652
+ Electronics > Video > Projectors > Slide Projectors
1653
+ Electronics > Video > Satellite & Cable TV
1654
+ Electronics > Video > Satellite & Cable TV > Cable TV Receivers
1655
+ Electronics > Video > Satellite & Cable TV > Satellite Receivers
1656
+ Electronics > Video > Televisions
1657
+ Electronics > Video > Video Accessories
1658
+ Electronics > Video > Video Accessories > 3D Glasses
1659
+ Electronics > Video > Video Accessories > Computer Monitor Accessories
1660
+ Electronics > Video > Video Accessories > Computer Monitor Accessories > Color Calibrators
1661
+ Electronics > Video > Video Accessories > Projector Accessories
1662
+ Electronics > Video > Video Accessories > Projector Accessories > Projection & Tripod Skirts
1663
+ Electronics > Video > Video Accessories > Projector Accessories > Projection Screen Stands
1664
+ Electronics > Video > Video Accessories > Projector Accessories > Projection Screens
1665
+ Electronics > Video > Video Accessories > Projector Accessories > Projector Mounts
1666
+ Electronics > Video > Video Accessories > Projector Accessories > Projector Replacement Lamps
1667
+ Electronics > Video > Video Accessories > Rewinders
1668
+ Electronics > Video > Video Accessories > Television Parts & Accessories
1669
+ Electronics > Video > Video Accessories > Television Parts & Accessories > TV & Monitor Mounts
1670
+ Electronics > Video > Video Accessories > Television Parts & Accessories > TV Converter Boxes
1671
+ Electronics > Video > Video Accessories > Television Parts & Accessories > TV Replacement Lamps
1672
+ Electronics > Video > Video Accessories > Television Parts & Accessories > TV Replacement Speakers
1673
+ Electronics > Video > Video Editing Hardware & Production Equipment
1674
+ Electronics > Video > Video Multiplexers
1675
+ Electronics > Video > Video Players & Recorders
1676
+ Electronics > Video > Video Players & Recorders > DVD & Blu-ray Players
1677
+ Electronics > Video > Video Players & Recorders > DVD Recorders
1678
+ Electronics > Video > Video Players & Recorders > Digital Video Recorders
1679
+ Electronics > Video > Video Players & Recorders > Streaming & Home Media Players
1680
+ Electronics > Video > Video Players & Recorders > VCRs
1681
+ Electronics > Video > Video Servers
1682
+ Electronics > Video > Video Transmitters
1683
+ Electronics > Video Game Console Accessories
1684
+ Electronics > Video Game Console Accessories > Home Game Console Accessories
1685
+ Electronics > Video Game Console Accessories > Portable Game Console Accessories
1686
+ Electronics > Video Game Consoles
1687
+ Food, Beverages & Tobacco
1688
+ Food, Beverages & Tobacco > Beverages
1689
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages
1690
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Beer
1691
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Bitters
1692
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes
1693
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes > Frozen Cocktail Mixes
1694
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes > Shelf-stable Cocktail Mixes
1695
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Flavored Alcoholic Beverages
1696
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Hard Cider
1697
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits
1698
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Absinthe
1699
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Brandy
1700
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Gin
1701
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Liqueurs
1702
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Rum
1703
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju
1704
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju > Shochu
1705
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju > Soju
1706
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Tequila
1707
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Vodka
1708
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Whiskey
1709
+ Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Wine
1710
+ Food, Beverages & Tobacco > Beverages > Buttermilk
1711
+ Food, Beverages & Tobacco > Beverages > Coffee
1712
+ Food, Beverages & Tobacco > Beverages > Eggnog
1713
+ Food, Beverages & Tobacco > Beverages > Fruit Flavored Drinks
1714
+ Food, Beverages & Tobacco > Beverages > Hot Chocolate
1715
+ Food, Beverages & Tobacco > Beverages > Juice
1716
+ Food, Beverages & Tobacco > Beverages > Milk
1717
+ Food, Beverages & Tobacco > Beverages > Non-Dairy Milk
1718
+ Food, Beverages & Tobacco > Beverages > Powdered Beverage Mixes
1719
+ Food, Beverages & Tobacco > Beverages > Soda
1720
+ Food, Beverages & Tobacco > Beverages > Sports & Energy Drinks
1721
+ Food, Beverages & Tobacco > Beverages > Tea & Infusions
1722
+ Food, Beverages & Tobacco > Beverages > Vinegar Drinks
1723
+ Food, Beverages & Tobacco > Beverages > Water
1724
+ Food, Beverages & Tobacco > Beverages > Water > Carbonated Water
1725
+ Food, Beverages & Tobacco > Beverages > Water > Carbonated Water > Flavored Carbonated Water
1726
+ Food, Beverages & Tobacco > Beverages > Water > Carbonated Water > Unflavored Carbonated Water
1727
+ Food, Beverages & Tobacco > Beverages > Water > Distilled Water
1728
+ Food, Beverages & Tobacco > Beverages > Water > Flat Mineral Water
1729
+ Food, Beverages & Tobacco > Beverages > Water > Spring Water
1730
+ Food, Beverages & Tobacco > Food Items
1731
+ Food, Beverages & Tobacco > Food Items > Bakery
1732
+ Food, Beverages & Tobacco > Food Items > Bakery > Bagels
1733
+ Food, Beverages & Tobacco > Food Items > Bakery > Bakery Assortments
1734
+ Food, Beverages & Tobacco > Food Items > Bakery > Breads & Buns
1735
+ Food, Beverages & Tobacco > Food Items > Bakery > Cakes & Dessert Bars
1736
+ Food, Beverages & Tobacco > Food Items > Bakery > Coffee Cakes
1737
+ Food, Beverages & Tobacco > Food Items > Bakery > Cookies
1738
+ Food, Beverages & Tobacco > Food Items > Bakery > Cupcakes
1739
+ Food, Beverages & Tobacco > Food Items > Bakery > Donuts
1740
+ Food, Beverages & Tobacco > Food Items > Bakery > Fudge
1741
+ Food, Beverages & Tobacco > Food Items > Bakery > Ice Cream Cones
1742
+ Food, Beverages & Tobacco > Food Items > Bakery > Muffins
1743
+ Food, Beverages & Tobacco > Food Items > Bakery > Pastries & Scones
1744
+ Food, Beverages & Tobacco > Food Items > Bakery > Pies & Tarts
1745
+ Food, Beverages & Tobacco > Food Items > Bakery > Taco Shells & Tostadas
1746
+ Food, Beverages & Tobacco > Food Items > Bakery > Tortillas & Wraps
1747
+ Food, Beverages & Tobacco > Food Items > Candied & Chocolate Covered Fruit
1748
+ Food, Beverages & Tobacco > Food Items > Candy & Chocolate
1749
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces
1750
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Cocktail Sauce
1751
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Curry Sauce
1752
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings
1753
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Fruit Toppings
1754
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Ice Cream Syrup
1755
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Fish Sauce
1756
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Gravy
1757
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Honey
1758
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Horseradish Sauce
1759
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Hot Sauce
1760
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Ketchup
1761
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Marinades & Grilling Sauces
1762
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mayonnaise
1763
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mustard
1764
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Olives & Capers
1765
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pasta Sauce
1766
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pickled Fruits & Vegetables
1767
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pizza Sauce
1768
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Relish & Chutney
1769
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Salad Dressing
1770
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Satay Sauce
1771
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Soy Sauce
1772
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Sweet and Sour Sauces
1773
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup
1774
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tahini
1775
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tartar Sauce
1776
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > White & Cream Sauces
1777
+ Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Worcestershire Sauce
1778
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients
1779
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chips
1780
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chocolate
1781
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Flavors & Extracts
1782
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes
1783
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Powder
1784
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Soda
1785
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Batter & Coating Mixes
1786
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bean Paste
1787
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bread Crumbs
1788
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Canned & Dry Milk
1789
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cookie Decorating Kits
1790
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oils
1791
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Starch
1792
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Wine
1793
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Corn Syrup
1794
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough
1795
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Bread & Pastry Dough
1796
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Cookie & Brownie Dough
1797
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Pie Crusts
1798
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations
1799
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Egg Replacers
1800
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Floss Sugar
1801
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Flour
1802
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Food Coloring
1803
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Frosting & Icing
1804
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Lemon & Lime Juice
1805
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Marshmallows
1806
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Meal
1807
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Molasses
1808
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Pie & Pastry Fillings
1809
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Shortening & Lard
1810
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Starter Cultures
1811
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Sugar & Sweeteners
1812
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tapioca Pearls
1813
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tomato Paste
1814
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Unflavored Gelatin
1815
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Vinegar
1816
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Waffle & Pancake Mixes
1817
+ Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Yeast
1818
+ Food, Beverages & Tobacco > Food Items > Dairy Products
1819
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Butter & Margarine
1820
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Cheese
1821
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Coffee Creamer
1822
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Cottage Cheese
1823
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Cream
1824
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Sour Cream
1825
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Whipped Cream
1826
+ Food, Beverages & Tobacco > Food Items > Dairy Products > Yogurt
1827
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads
1828
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Apple Butter
1829
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cheese Dips & Spreads
1830
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cream Cheese
1831
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Guacamole
1832
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Hummus
1833
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Jams & Jellies
1834
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters
1835
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Salsa
1836
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Tapenade
1837
+ Food, Beverages & Tobacco > Food Items > Dips & Spreads > Vegetable Dip
1838
+ Food, Beverages & Tobacco > Food Items > Food Gift Baskets
1839
+ Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties
1840
+ Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream & Frozen Yogurt
1841
+ Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream Novelties
1842
+ Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Pops
1843
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables
1844
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Fruits
1845
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Vegetables
1846
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Prepared Beans
1847
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Fruits
1848
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Vegetables
1849
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dry Beans
1850
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits
1851
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Apples
1852
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Atemoyas
1853
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Avocados
1854
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Babacos
1855
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Bananas
1856
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Berries
1857
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Breadfruit
1858
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cactus Pears
1859
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cherimoyas
1860
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits
1861
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Grapefruits
1862
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Kumquats
1863
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Lemons
1864
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Limequats
1865
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Limes
1866
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Oranges
1867
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Tangelos
1868
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Coconuts
1869
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Dates
1870
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Feijoas
1871
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Figs
1872
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Fruit Mixes
1873
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Grapes
1874
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Guavas
1875
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Homely Fruits
1876
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Kiwis
1877
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Longan
1878
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Loquats
1879
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Lychees
1880
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Madroño
1881
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mamey
1882
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mangosteens
1883
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Melons
1884
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Papayas
1885
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Passion Fruit
1886
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pears
1887
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Persimmons
1888
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Physalis
1889
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pineapples
1890
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pitahayas
1891
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pomegranates
1892
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Quince
1893
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Rambutans
1894
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapodillo
1895
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapote
1896
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Soursops
1897
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Starfruits
1898
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits
1899
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Apricots
1900
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Cherries
1901
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Mangoes
1902
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Peaches & Nectarines
1903
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Plumcots
1904
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Plums
1905
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sugar Apples
1906
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Tamarindo
1907
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables
1908
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Arracachas
1909
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Artichokes
1910
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Asparagus
1911
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beans
1912
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beets
1913
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Borage
1914
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Broccoli
1915
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Brussel Sprouts
1916
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cabbage
1917
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cactus Leaves
1918
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cardoon
1919
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Carrots
1920
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cauliflower
1921
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery
1922
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery Roots
1923
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Corn
1924
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cucumbers
1925
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Eggplants
1926
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fennel Bulbs
1927
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fiddlehead Ferns
1928
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Choy
1929
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Lan
1930
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Garlic
1931
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Ginger Root
1932
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gobo Root
1933
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens
1934
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Arugula
1935
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Beet Greens
1936
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Bok Choy
1937
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Chard
1938
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Chicory
1939
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Choy Sum
1940
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Kale
1941
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Lettuce
1942
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > On Choy
1943
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Salad Mixes
1944
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Spinach
1945
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Yu Choy
1946
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Horseradish Root
1947
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Jicama
1948
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Kohlrabi
1949
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Leeks
1950
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Lotus Roots
1951
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Malangas
1952
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Mushrooms
1953
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Okra
1954
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Onions
1955
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsley Roots
1956
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsnips
1957
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peas
1958
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peppers
1959
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Potatoes
1960
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Radishes
1961
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Rhubarb
1962
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Shallots
1963
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sprouts
1964
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Squashes & Gourds
1965
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sugar Cane
1966
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sunchokes
1967
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sweet Potatoes
1968
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tamarillos
1969
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Taro Root
1970
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tomatoes
1971
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Turnips & Rutabagas
1972
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Vegetable Mixes
1973
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Water Chestnuts
1974
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Watercress
1975
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Wheatgrass
1976
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yams
1977
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yuca Root
1978
+ Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fruit Sauces
1979
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal
1980
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Amaranth
1981
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Barley
1982
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Buckwheat
1983
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Cereal & Granola
1984
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Couscous
1985
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Millet
1986
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Oats, Grits & Hot Cereal
1987
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Quinoa
1988
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rice
1989
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rye
1990
+ Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Wheat
1991
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs
1992
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs
1993
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Egg Whites
1994
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Liquid & Frozen Eggs
1995
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Prepared Eggs
1996
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Whole Eggs
1997
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat
1998
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Canned Meats
1999
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Fresh & Frozen Meats
2000
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Lunch & Deli Meats
2001
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood
2002
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Canned Seafood
2003
+ Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Fresh & Frozen Seafood
2004
+ Food, Beverages & Tobacco > Food Items > Nuts & Seeds
2005
+ Food, Beverages & Tobacco > Food Items > Pasta & Noodles
2006
+ Food, Beverages & Tobacco > Food Items > Prepared Foods
2007
+ Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Appetizers & Side Dishes
2008
+ Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Meals & Entrées
2009
+ Food, Beverages & Tobacco > Food Items > Seasonings & Spices
2010
+ Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices
2011
+ Food, Beverages & Tobacco > Food Items > Seasonings & Spices > MSG
2012
+ Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Pepper
2013
+ Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Salt
2014
+ Food, Beverages & Tobacco > Food Items > Snack Foods
2015
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Breadsticks
2016
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars
2017
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars > Cereal Bars
2018
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars > Granola Bars
2019
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Cheese Puffs
2020
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Chips
2021
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers
2022
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Croutons
2023
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Fruit Snacks
2024
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky
2025
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Popcorn
2026
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Pork Rinds
2027
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Pretzels
2028
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Pudding & Gelatin Snacks
2029
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Puffed Rice Cakes
2030
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Salad Toppings
2031
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Sesame Sticks
2032
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Snack Cakes
2033
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Sticky Rice Cakes
2034
+ Food, Beverages & Tobacco > Food Items > Snack Foods > Trail & Snack Mixes
2035
+ Food, Beverages & Tobacco > Food Items > Soups & Broths
2036
+ Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products
2037
+ Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Cheese Alternatives
2038
+ Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Meat Alternatives
2039
+ Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Seitan
2040
+ Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tempeh
2041
+ Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tofu
2042
+ Food, Beverages & Tobacco > Tobacco Products
2043
+ Food, Beverages & Tobacco > Tobacco Products > Chewing Tobacco
2044
+ Food, Beverages & Tobacco > Tobacco Products > Cigarettes
2045
+ Food, Beverages & Tobacco > Tobacco Products > Cigars
2046
+ Food, Beverages & Tobacco > Tobacco Products > Loose Tobacco
2047
+ Food, Beverages & Tobacco > Tobacco Products > Smoking Pipes
2048
+ Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes
2049
+ Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes > Electronic Cigarettes
2050
+ Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes > Vaporizers
2051
+ Furniture
2052
+ Furniture > Baby & Toddler Furniture
2053
+ Furniture > Baby & Toddler Furniture > Baby & Toddler Furniture Sets
2054
+ Furniture > Baby & Toddler Furniture > Bassinet & Cradle Accessories
2055
+ Furniture > Baby & Toddler Furniture > Bassinets & Cradles
2056
+ Furniture > Baby & Toddler Furniture > Changing Tables
2057
+ Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories
2058
+ Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Bumpers & Liners
2059
+ Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Conversion Kits
2060
+ Furniture > Baby & Toddler Furniture > Cribs & Toddler Beds
2061
+ Furniture > Baby & Toddler Furniture > High Chair & Booster Seat Accessories
2062
+ Furniture > Baby & Toddler Furniture > High Chairs & Booster Seats
2063
+ Furniture > Beds & Accessories
2064
+ Furniture > Beds & Accessories > Bed & Bed Frame Accessories
2065
+ Furniture > Beds & Accessories > Beds & Bed Frames
2066
+ Furniture > Beds & Accessories > Headboards & Footboards
2067
+ Furniture > Beds & Accessories > Mattress Foundations
2068
+ Furniture > Beds & Accessories > Mattresses
2069
+ Furniture > Benches
2070
+ Furniture > Benches > Kitchen & Dining Benches
2071
+ Furniture > Benches > Storage & Entryway Benches
2072
+ Furniture > Benches > Vanity Benches
2073
+ Furniture > Cabinets & Storage
2074
+ Furniture > Cabinets & Storage > Armoires & Wardrobes
2075
+ Furniture > Cabinets & Storage > Buffets & Sideboards
2076
+ Furniture > Cabinets & Storage > China Cabinets & Hutches
2077
+ Furniture > Cabinets & Storage > Dressers
2078
+ Furniture > Cabinets & Storage > File Cabinets
2079
+ Furniture > Cabinets & Storage > Ironing Centers
2080
+ Furniture > Cabinets & Storage > Kitchen Cabinets
2081
+ Furniture > Cabinets & Storage > Magazine Racks
2082
+ Furniture > Cabinets & Storage > Media Storage Cabinets & Racks
2083
+ Furniture > Cabinets & Storage > Storage Cabinets & Lockers
2084
+ Furniture > Cabinets & Storage > Storage Chests
2085
+ Furniture > Cabinets & Storage > Storage Chests > Hope Chests
2086
+ Furniture > Cabinets & Storage > Storage Chests > Toy Chests
2087
+ Furniture > Cabinets & Storage > Vanities
2088
+ Furniture > Cabinets & Storage > Vanities > Bathroom Vanities
2089
+ Furniture > Cabinets & Storage > Vanities > Bedroom Vanities
2090
+ Furniture > Cabinets & Storage > Wine & Liquor Cabinets
2091
+ Furniture > Cabinets & Storage > Wine Racks
2092
+ Furniture > Carts & Islands
2093
+ Furniture > Carts & Islands > Kitchen & Dining Carts
2094
+ Furniture > Carts & Islands > Kitchen Islands
2095
+ Furniture > Chair Accessories
2096
+ Furniture > Chair Accessories > Hanging Chair Replacement Parts
2097
+ Furniture > Chairs
2098
+ Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs
2099
+ Furniture > Chairs > Bean Bag Chairs
2100
+ Furniture > Chairs > Chaises
2101
+ Furniture > Chairs > Electric Massaging Chairs
2102
+ Furniture > Chairs > Floor Chairs
2103
+ Furniture > Chairs > Folding Chairs & Stools
2104
+ Furniture > Chairs > Gaming Chairs
2105
+ Furniture > Chairs > Hanging Chairs
2106
+ Furniture > Chairs > Kitchen & Dining Room Chairs
2107
+ Furniture > Chairs > Rocking Chairs
2108
+ Furniture > Chairs > Slipper Chairs
2109
+ Furniture > Chairs > Table & Bar Stools
2110
+ Furniture > Entertainment Centers & TV Stands
2111
+ Furniture > Furniture Sets
2112
+ Furniture > Furniture Sets > Bathroom Furniture Sets
2113
+ Furniture > Furniture Sets > Bedroom Furniture Sets
2114
+ Furniture > Furniture Sets > Kitchen & Dining Furniture Sets
2115
+ Furniture > Furniture Sets > Living Room Furniture Sets
2116
+ Furniture > Futon Frames
2117
+ Furniture > Futon Pads
2118
+ Furniture > Futons
2119
+ Furniture > Office Furniture
2120
+ Furniture > Office Furniture > Desks
2121
+ Furniture > Office Furniture > Office Chairs
2122
+ Furniture > Office Furniture > Office Furniture Sets
2123
+ Furniture > Office Furniture > Workspace Tables
2124
+ Furniture > Office Furniture > Workspace Tables > Art & Drafting Tables
2125
+ Furniture > Office Furniture > Workspace Tables > Conference Room Tables
2126
+ Furniture > Office Furniture > Workstations & Cubicles
2127
+ Furniture > Office Furniture Accessories
2128
+ Furniture > Office Furniture Accessories > Desk Parts & Accessories
2129
+ Furniture > Office Furniture Accessories > Office Chair Accessories
2130
+ Furniture > Office Furniture Accessories > Workstation & Cubicle Accessories
2131
+ Furniture > Ottomans
2132
+ Furniture > Outdoor Furniture
2133
+ Furniture > Outdoor Furniture > Outdoor Beds
2134
+ Furniture > Outdoor Furniture > Outdoor Furniture Sets
2135
+ Furniture > Outdoor Furniture > Outdoor Ottomans
2136
+ Furniture > Outdoor Furniture > Outdoor Seating
2137
+ Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Benches
2138
+ Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Chairs
2139
+ Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sectional Sofa Units
2140
+ Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sofas
2141
+ Furniture > Outdoor Furniture > Outdoor Seating > Sunloungers
2142
+ Furniture > Outdoor Furniture > Outdoor Storage Boxes
2143
+ Furniture > Outdoor Furniture > Outdoor Tables
2144
+ Furniture > Outdoor Furniture Accessories
2145
+ Furniture > Outdoor Furniture Accessories > Outdoor Furniture Covers
2146
+ Furniture > Room Divider Accessories
2147
+ Furniture > Room Dividers
2148
+ Furniture > Shelving
2149
+ Furniture > Shelving > Bookcases & Standing Shelves
2150
+ Furniture > Shelving > Wall Shelves & Ledges
2151
+ Furniture > Shelving Accessories
2152
+ Furniture > Shelving Accessories > Replacement Shelves
2153
+ Furniture > Sofa Accessories
2154
+ Furniture > Sofa Accessories > Chair & Sofa Supports
2155
+ Furniture > Sofa Accessories > Sectional Sofa Units
2156
+ Furniture > Sofas
2157
+ Furniture > Table Accessories
2158
+ Furniture > Table Accessories > Table Legs
2159
+ Furniture > Table Accessories > Table Tops
2160
+ Furniture > Tables
2161
+ Furniture > Tables > Accent Tables
2162
+ Furniture > Tables > Accent Tables > Coffee Tables
2163
+ Furniture > Tables > Accent Tables > End Tables
2164
+ Furniture > Tables > Accent Tables > Sofa Tables
2165
+ Furniture > Tables > Activity Tables
2166
+ Furniture > Tables > Folding Tables
2167
+ Furniture > Tables > Kitchen & Dining Room Tables
2168
+ Furniture > Tables > Kotatsu
2169
+ Furniture > Tables > Nightstands
2170
+ Furniture > Tables > Poker & Game Tables
2171
+ Furniture > Tables > Sewing Machine Tables
2172
+ Hardware
2173
+ Hardware > Building Consumables
2174
+ Hardware > Building Consumables > Chemicals
2175
+ Hardware > Building Consumables > Chemicals > Acid Neutralizers
2176
+ Hardware > Building Consumables > Chemicals > Ammonia
2177
+ Hardware > Building Consumables > Chemicals > Chimney Cleaners
2178
+ Hardware > Building Consumables > Chemicals > Concrete & Masonry Cleaners
2179
+ Hardware > Building Consumables > Chemicals > De-icers
2180
+ Hardware > Building Consumables > Chemicals > Deck & Fence Cleaners
2181
+ Hardware > Building Consumables > Chemicals > Drain Cleaners
2182
+ Hardware > Building Consumables > Chemicals > Electrical Freeze Sprays
2183
+ Hardware > Building Consumables > Chemicals > Lighter Fluid
2184
+ Hardware > Building Consumables > Chemicals > Septic Tank & Cesspool Treatments
2185
+ Hardware > Building Consumables > Hardware Glue & Adhesives
2186
+ Hardware > Building Consumables > Hardware Tape
2187
+ Hardware > Building Consumables > Lubricants
2188
+ Hardware > Building Consumables > Masonry Consumables
2189
+ Hardware > Building Consumables > Masonry Consumables > Bricks & Concrete Blocks
2190
+ Hardware > Building Consumables > Masonry Consumables > Cement, Mortar & Concrete Mixes
2191
+ Hardware > Building Consumables > Masonry Consumables > Grout
2192
+ Hardware > Building Consumables > Painting Consumables
2193
+ Hardware > Building Consumables > Painting Consumables > Paint
2194
+ Hardware > Building Consumables > Painting Consumables > Paint Binders
2195
+ Hardware > Building Consumables > Painting Consumables > Primers
2196
+ Hardware > Building Consumables > Painting Consumables > Stains
2197
+ Hardware > Building Consumables > Painting Consumables > Varnishes & Finishes
2198
+ Hardware > Building Consumables > Plumbing Primer
2199
+ Hardware > Building Consumables > Protective Coatings & Sealants
2200
+ Hardware > Building Consumables > Solder & Flux
2201
+ Hardware > Building Consumables > Solvents, Strippers & Thinners
2202
+ Hardware > Building Consumables > Wall Patching Compounds & Plaster
2203
+ Hardware > Building Materials
2204
+ Hardware > Building Materials > Countertops
2205
+ Hardware > Building Materials > Door Hardware
2206
+ Hardware > Building Materials > Door Hardware > Door Bells & Chimes
2207
+ Hardware > Building Materials > Door Hardware > Door Closers
2208
+ Hardware > Building Materials > Door Hardware > Door Frames
2209
+ Hardware > Building Materials > Door Hardware > Door Keyhole Escutcheons
2210
+ Hardware > Building Materials > Door Hardware > Door Knobs & Handles
2211
+ Hardware > Building Materials > Door Hardware > Door Knockers
2212
+ Hardware > Building Materials > Door Hardware > Door Push Plates
2213
+ Hardware > Building Materials > Door Hardware > Door Stops
2214
+ Hardware > Building Materials > Door Hardware > Door Strikes
2215
+ Hardware > Building Materials > Doors
2216
+ Hardware > Building Materials > Doors > Garage Doors
2217
+ Hardware > Building Materials > Doors > Home Doors
2218
+ Hardware > Building Materials > Drywall
2219
+ Hardware > Building Materials > Flooring & Carpet
2220
+ Hardware > Building Materials > Glass
2221
+ Hardware > Building Materials > Handrails & Railing Systems
2222
+ Hardware > Building Materials > Hatches
2223
+ Hardware > Building Materials > Insulation
2224
+ Hardware > Building Materials > Lumber & Sheet Stock
2225
+ Hardware > Building Materials > Molding
2226
+ Hardware > Building Materials > Rebar & Remesh
2227
+ Hardware > Building Materials > Roofing
2228
+ Hardware > Building Materials > Roofing > Gutter Accessories
2229
+ Hardware > Building Materials > Roofing > Gutters
2230
+ Hardware > Building Materials > Roofing > Roof Flashings
2231
+ Hardware > Building Materials > Roofing > Roofing Shingles & Tiles
2232
+ Hardware > Building Materials > Shutters
2233
+ Hardware > Building Materials > Siding
2234
+ Hardware > Building Materials > Sound Dampening Panels & Foam
2235
+ Hardware > Building Materials > Staircases
2236
+ Hardware > Building Materials > Wall & Ceiling Tile
2237
+ Hardware > Building Materials > Wall Paneling
2238
+ Hardware > Building Materials > Weather Stripping & Weatherization Supplies
2239
+ Hardware > Building Materials > Window Hardware
2240
+ Hardware > Building Materials > Window Hardware > Window Cranks
2241
+ Hardware > Building Materials > Window Hardware > Window Frames
2242
+ Hardware > Building Materials > Windows
2243
+ Hardware > Fencing & Barriers
2244
+ Hardware > Fencing & Barriers > Fence & Gate Accessories
2245
+ Hardware > Fencing & Barriers > Fence Panels
2246
+ Hardware > Fencing & Barriers > Fence Pickets
2247
+ Hardware > Fencing & Barriers > Fence Posts & Rails
2248
+ Hardware > Fencing & Barriers > Garden Borders & Edging
2249
+ Hardware > Fencing & Barriers > Gates
2250
+ Hardware > Fencing & Barriers > Lattice
2251
+ Hardware > Fencing & Barriers > Safety & Crowd Control Barriers
2252
+ Hardware > Fuel
2253
+ Hardware > Fuel > Home Heating Oil
2254
+ Hardware > Fuel > Kerosene
2255
+ Hardware > Fuel > Kerosene > Clear Kerosene
2256
+ Hardware > Fuel > Kerosene > Dyed Kerosene
2257
+ Hardware > Fuel > Propane
2258
+ Hardware > Fuel Containers & Tanks
2259
+ Hardware > Hardware Accessories
2260
+ Hardware > Hardware Accessories > Brackets & Reinforcement Braces
2261
+ Hardware > Hardware Accessories > Cabinet Hardware
2262
+ Hardware > Hardware Accessories > Cabinet Hardware > Cabinet & Furniture Keyhole Escutcheons
2263
+ Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Backplates
2264
+ Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Catches
2265
+ Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Doors
2266
+ Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Knobs & Handles
2267
+ Hardware > Hardware Accessories > Casters
2268
+ Hardware > Hardware Accessories > Chain, Wire & Rope
2269
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Bungee Cords
2270
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Chains
2271
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Pull Chains
2272
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Ropes & Hardware Cable
2273
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Tie Down Straps
2274
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Twine
2275
+ Hardware > Hardware Accessories > Chain, Wire & Rope > Utility Wire
2276
+ Hardware > Hardware Accessories > Coils
2277
+ Hardware > Hardware Accessories > Concrete Molds
2278
+ Hardware > Hardware Accessories > Dowel Pins & Rods
2279
+ Hardware > Hardware Accessories > Drawer Slides
2280
+ Hardware > Hardware Accessories > Drop Cloths
2281
+ Hardware > Hardware Accessories > Filters & Screens
2282
+ Hardware > Hardware Accessories > Flagging & Caution Tape
2283
+ Hardware > Hardware Accessories > Gas Hoses
2284
+ Hardware > Hardware Accessories > Ground Spikes
2285
+ Hardware > Hardware Accessories > Hardware Fasteners
2286
+ Hardware > Hardware Accessories > Hardware Fasteners > Drywall Anchors
2287
+ Hardware > Hardware Accessories > Hardware Fasteners > Nails
2288
+ Hardware > Hardware Accessories > Hardware Fasteners > Nuts & Bolts
2289
+ Hardware > Hardware Accessories > Hardware Fasteners > Rivets
2290
+ Hardware > Hardware Accessories > Hardware Fasteners > Screw Posts
2291
+ Hardware > Hardware Accessories > Hardware Fasteners > Screws
2292
+ Hardware > Hardware Accessories > Hardware Fasteners > Threaded Rods
2293
+ Hardware > Hardware Accessories > Hardware Fasteners > Washers
2294
+ Hardware > Hardware Accessories > Hinges
2295
+ Hardware > Hardware Accessories > Hooks, Buckles & Fasteners
2296
+ Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Chain Connectors & Links
2297
+ Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Gear Ties
2298
+ Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Lifting Hooks, Clamps & Shackles
2299
+ Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Utility Buckles
2300
+ Hardware > Hardware Accessories > Lubrication Hoses
2301
+ Hardware > Hardware Accessories > Metal Casting Molds
2302
+ Hardware > Hardware Accessories > Moving & Soundproofing Blankets & Covers
2303
+ Hardware > Hardware Accessories > Pneumatic Hoses
2304
+ Hardware > Hardware Accessories > Post Base Plates
2305
+ Hardware > Hardware Accessories > Springs
2306
+ Hardware > Hardware Accessories > Tarps
2307
+ Hardware > Hardware Accessories > Tool Storage & Organization
2308
+ Hardware > Hardware Accessories > Tool Storage & Organization > Garden Hose Storage
2309
+ Hardware > Hardware Accessories > Tool Storage & Organization > Tool & Equipment Belts
2310
+ Hardware > Hardware Accessories > Tool Storage & Organization > Tool Bags
2311
+ Hardware > Hardware Accessories > Tool Storage & Organization > Tool Boxes
2312
+ Hardware > Hardware Accessories > Tool Storage & Organization > Tool Cabinets & Chests
2313
+ Hardware > Hardware Accessories > Tool Storage & Organization > Tool Organizer Liners & Inserts
2314
+ Hardware > Hardware Accessories > Tool Storage & Organization > Tool Sheaths
2315
+ Hardware > Hardware Accessories > Tool Storage & Organization > Work Benches
2316
+ Hardware > Hardware Accessories > Wall Jacks & Braces
2317
+ Hardware > Hardware Pumps
2318
+ Hardware > Hardware Pumps > Home Appliance Pumps
2319
+ Hardware > Hardware Pumps > Pool, Fountain & Pond Pumps
2320
+ Hardware > Hardware Pumps > Sprinkler, Booster & Irrigation System Pumps
2321
+ Hardware > Hardware Pumps > Sump, Sewage & Effluent Pumps
2322
+ Hardware > Hardware Pumps > Utility Pumps
2323
+ Hardware > Hardware Pumps > Well Pumps & Systems
2324
+ Hardware > Heating, Ventilation & Air Conditioning
2325
+ Hardware > Heating, Ventilation & Air Conditioning > Air & Filter Dryers
2326
+ Hardware > Heating, Ventilation & Air Conditioning > Air Ducts
2327
+ Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls
2328
+ Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Control Panels
2329
+ Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Humidistats
2330
+ Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Thermostats
2331
+ Hardware > Heating, Ventilation & Air Conditioning > Vents & Flues
2332
+ Hardware > Locks & Keys
2333
+ Hardware > Locks & Keys > Key Blanks
2334
+ Hardware > Locks & Keys > Key Caps
2335
+ Hardware > Locks & Keys > Key Card Entry Systems
2336
+ Hardware > Locks & Keys > Locks & Latches
2337
+ Hardware > Plumbing
2338
+ Hardware > Plumbing > Plumbing Fittings & Supports
2339
+ Hardware > Plumbing > Plumbing Fittings & Supports > Gaskets & O-Rings
2340
+ Hardware > Plumbing > Plumbing Fittings & Supports > In-Wall Carriers & Mounting Frames
2341
+ Hardware > Plumbing > Plumbing Fittings & Supports > Nozzles
2342
+ Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Adapters & Bushings
2343
+ Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Caps & Plugs
2344
+ Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Connectors
2345
+ Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Flanges
2346
+ Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Pipe Clamps
2347
+ Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Regulators
2348
+ Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Valves
2349
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts
2350
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories
2351
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Bases & Feet
2352
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Skirts
2353
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Spouts
2354
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components
2355
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Covers & Strainers
2356
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Frames
2357
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Liners
2358
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Openers
2359
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Rods
2360
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Plumbing Traps
2361
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Plumbing Wastes
2362
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drains
2363
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories
2364
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories > Faucet Aerators
2365
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories > Faucet Handles & Controls
2366
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Fixture Plates
2367
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts
2368
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Bathtub & Shower Jets
2369
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Electric & Power Showers
2370
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Arms & Connectors
2371
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Bases
2372
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Columns
2373
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Doors & Enclosures
2374
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Heads
2375
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Walls & Surrounds
2376
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Water Filters
2377
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Sink Accessories
2378
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Sink Accessories > Sink Legs
2379
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories
2380
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Ballcocks & Flappers
2381
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Bidet Faucets & Sprayers
2382
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet & Bidet Seats
2383
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Seat Covers
2384
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Seat Lid Covers
2385
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tank Covers
2386
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tank Levers
2387
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tanks
2388
+ Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Trim
2389
+ Hardware > Plumbing > Plumbing Fixtures
2390
+ Hardware > Plumbing > Plumbing Fixtures > Bathroom Suites
2391
+ Hardware > Plumbing > Plumbing Fixtures > Bathtubs
2392
+ Hardware > Plumbing > Plumbing Fixtures > Faucets
2393
+ Hardware > Plumbing > Plumbing Fixtures > Shower Stalls & Kits
2394
+ Hardware > Plumbing > Plumbing Fixtures > Sinks
2395
+ Hardware > Plumbing > Plumbing Fixtures > Sinks > Bathroom Sinks
2396
+ Hardware > Plumbing > Plumbing Fixtures > Sinks > Kitchen & Utility Sinks
2397
+ Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets
2398
+ Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Bidets
2399
+ Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Toilets
2400
+ Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Urinals
2401
+ Hardware > Plumbing > Plumbing Hoses & Supply Lines
2402
+ Hardware > Plumbing > Plumbing Pipes
2403
+ Hardware > Plumbing > Plumbing Repair Kits
2404
+ Hardware > Plumbing > Water Dispensing & Filtration
2405
+ Hardware > Plumbing > Water Dispensing & Filtration > In-Line Water Filters
2406
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers
2407
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Drinking Fountains
2408
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Water Chillers
2409
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Distillers
2410
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories
2411
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Cartridges
2412
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Housings
2413
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Softener Salt
2414
+ Hardware > Plumbing > Water Dispensing & Filtration > Water Softeners
2415
+ Hardware > Plumbing > Water Levelers
2416
+ Hardware > Plumbing > Water Timers
2417
+ Hardware > Plumbing > Well Supplies
2418
+ Hardware > Power & Electrical Supplies
2419
+ Hardware > Power & Electrical Supplies > Armatures, Rotors & Stators
2420
+ Hardware > Power & Electrical Supplies > Ballasts & Starters
2421
+ Hardware > Power & Electrical Supplies > Carbon Brushes
2422
+ Hardware > Power & Electrical Supplies > Circuit Breaker Panels
2423
+ Hardware > Power & Electrical Supplies > Conduit & Housings
2424
+ Hardware > Power & Electrical Supplies > Conduit & Housings > Electrical Conduit
2425
+ Hardware > Power & Electrical Supplies > Conduit & Housings > Heat-Shrink Tubing
2426
+ Hardware > Power & Electrical Supplies > Electrical Motors
2427
+ Hardware > Power & Electrical Supplies > Electrical Mount Boxes & Brackets
2428
+ Hardware > Power & Electrical Supplies > Electrical Plug Caps
2429
+ Hardware > Power & Electrical Supplies > Electrical Switches
2430
+ Hardware > Power & Electrical Supplies > Electrical Switches > Light Switches
2431
+ Hardware > Power & Electrical Supplies > Electrical Switches > Specialty Electrical Switches & Relays
2432
+ Hardware > Power & Electrical Supplies > Electrical Wires & Cable
2433
+ Hardware > Power & Electrical Supplies > Extension Cord Accessories
2434
+ Hardware > Power & Electrical Supplies > Extension Cords
2435
+ Hardware > Power & Electrical Supplies > Generator Accessories
2436
+ Hardware > Power & Electrical Supplies > Generators
2437
+ Hardware > Power & Electrical Supplies > Home Automation Kits
2438
+ Hardware > Power & Electrical Supplies > Phone & Data Jacks
2439
+ Hardware > Power & Electrical Supplies > Power Converters
2440
+ Hardware > Power & Electrical Supplies > Power Inlets
2441
+ Hardware > Power & Electrical Supplies > Power Inverters
2442
+ Hardware > Power & Electrical Supplies > Power Outlets & Sockets
2443
+ Hardware > Power & Electrical Supplies > Solar Energy Kits
2444
+ Hardware > Power & Electrical Supplies > Solar Panels
2445
+ Hardware > Power & Electrical Supplies > Voltage Transformers & Regulators
2446
+ Hardware > Power & Electrical Supplies > Wall Plates & Covers
2447
+ Hardware > Power & Electrical Supplies > Wall Socket Controls & Sensors
2448
+ Hardware > Power & Electrical Supplies > Wire Caps & Nuts
2449
+ Hardware > Power & Electrical Supplies > Wire Terminals & Connectors
2450
+ Hardware > Small Engines
2451
+ Hardware > Storage Tanks
2452
+ Hardware > Tool Accessories
2453
+ Hardware > Tool Accessories > Abrasive Blaster Accessories
2454
+ Hardware > Tool Accessories > Abrasive Blaster Accessories > Sandblasting Cabinets
2455
+ Hardware > Tool Accessories > Axe Accessories
2456
+ Hardware > Tool Accessories > Axe Accessories > Axe Handles
2457
+ Hardware > Tool Accessories > Axe Accessories > Axe Heads
2458
+ Hardware > Tool Accessories > Cutter Accessories
2459
+ Hardware > Tool Accessories > Cutter Accessories > Nibbler Dies
2460
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories
2461
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill & Screwdriver Bits
2462
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Bit Extensions
2463
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Bit Sharpeners
2464
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Chucks
2465
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Stands & Guides
2466
+ Hardware > Tool Accessories > Drill & Screwdriver Accessories > Hole Saws
2467
+ Hardware > Tool Accessories > Driver Accessories
2468
+ Hardware > Tool Accessories > Flashlight Accessories
2469
+ Hardware > Tool Accessories > Grinder Accessories
2470
+ Hardware > Tool Accessories > Grinder Accessories > Grinding Wheels & Points
2471
+ Hardware > Tool Accessories > Hammer Accessories
2472
+ Hardware > Tool Accessories > Hammer Accessories > Air Hammer Accessories
2473
+ Hardware > Tool Accessories > Hammer Accessories > Hammer Handles
2474
+ Hardware > Tool Accessories > Hammer Accessories > Hammer Heads
2475
+ Hardware > Tool Accessories > Industrial Staples
2476
+ Hardware > Tool Accessories > Jigs
2477
+ Hardware > Tool Accessories > Magnetizers & Demagnetizers
2478
+ Hardware > Tool Accessories > Mattock & Pickaxe Accessories
2479
+ Hardware > Tool Accessories > Mattock & Pickaxe Accessories > Mattock & Pickaxe Handles
2480
+ Hardware > Tool Accessories > Measuring Tool & Sensor Accessories
2481
+ Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Electrical Testing Tool Accessories
2482
+ Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Gas Detector Accessories
2483
+ Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Measuring Scale Accessories
2484
+ Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Multimeter Accessories
2485
+ Hardware > Tool Accessories > Mixing Tool Paddles
2486
+ Hardware > Tool Accessories > Paint Tool Accessories
2487
+ Hardware > Tool Accessories > Paint Tool Accessories > Airbrush Accessories
2488
+ Hardware > Tool Accessories > Paint Tool Accessories > Paint Brush Cleaning Solutions
2489
+ Hardware > Tool Accessories > Paint Tool Accessories > Paint Roller Accessories
2490
+ Hardware > Tool Accessories > Power Tool Batteries
2491
+ Hardware > Tool Accessories > Power Tool Chargers
2492
+ Hardware > Tool Accessories > Router Accessories
2493
+ Hardware > Tool Accessories > Router Accessories > Router Bits
2494
+ Hardware > Tool Accessories > Router Accessories > Router Tables
2495
+ Hardware > Tool Accessories > Sanding Accessories
2496
+ Hardware > Tool Accessories > Sanding Accessories > Sandpaper & Sanding Sponges
2497
+ Hardware > Tool Accessories > Saw Accessories
2498
+ Hardware > Tool Accessories > Saw Accessories > Band Saw Accessories
2499
+ Hardware > Tool Accessories > Saw Accessories > Handheld Circular Saw Accessories
2500
+ Hardware > Tool Accessories > Saw Accessories > Jigsaw Accessories
2501
+ Hardware > Tool Accessories > Saw Accessories > Miter Saw Accessories
2502
+ Hardware > Tool Accessories > Saw Accessories > Table Saw Accessories
2503
+ Hardware > Tool Accessories > Shaper Accessories
2504
+ Hardware > Tool Accessories > Shaper Accessories > Shaper Cutters
2505
+ Hardware > Tool Accessories > Soldering Iron Accessories
2506
+ Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Stands
2507
+ Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Tips
2508
+ Hardware > Tool Accessories > Tool Blades
2509
+ Hardware > Tool Accessories > Tool Blades > Cutter & Scraper Blades
2510
+ Hardware > Tool Accessories > Tool Blades > Saw Blades
2511
+ Hardware > Tool Accessories > Tool Handle Wedges
2512
+ Hardware > Tool Accessories > Tool Safety Tethers
2513
+ Hardware > Tool Accessories > Tool Sockets
2514
+ Hardware > Tool Accessories > Tool Stands
2515
+ Hardware > Tool Accessories > Tool Stands > Saw Stands
2516
+ Hardware > Tool Accessories > Wedge Tools
2517
+ Hardware > Tool Accessories > Welding Accessories
2518
+ Hardware > Tools
2519
+ Hardware > Tools > Abrasive Blasters
2520
+ Hardware > Tools > Anvils
2521
+ Hardware > Tools > Axes
2522
+ Hardware > Tools > Carpentry Jointers
2523
+ Hardware > Tools > Carving Chisels & Gouges
2524
+ Hardware > Tools > Caulking Tools
2525
+ Hardware > Tools > Chimney Brushes
2526
+ Hardware > Tools > Compactors
2527
+ Hardware > Tools > Compressors
2528
+ Hardware > Tools > Concrete Brooms
2529
+ Hardware > Tools > Cutters
2530
+ Hardware > Tools > Cutters > Bolt Cutters
2531
+ Hardware > Tools > Cutters > Glass Cutters
2532
+ Hardware > Tools > Cutters > Handheld Metal Shears & Nibblers
2533
+ Hardware > Tools > Cutters > Nippers
2534
+ Hardware > Tools > Cutters > Pipe Cutters
2535
+ Hardware > Tools > Cutters > Rebar Cutters
2536
+ Hardware > Tools > Cutters > Tile & Shingle Cutters
2537
+ Hardware > Tools > Cutters > Utility Knives
2538
+ Hardware > Tools > Deburrers
2539
+ Hardware > Tools > Dollies & Hand Trucks
2540
+ Hardware > Tools > Drills
2541
+ Hardware > Tools > Drills > Augers
2542
+ Hardware > Tools > Drills > Drill Presses
2543
+ Hardware > Tools > Drills > Handheld Power Drills
2544
+ Hardware > Tools > Drills > Mortisers
2545
+ Hardware > Tools > Drills > Pneumatic Drills
2546
+ Hardware > Tools > Electrician Fish Tape
2547
+ Hardware > Tools > Flashlights & Headlamps
2548
+ Hardware > Tools > Flashlights & Headlamps > Flashlights
2549
+ Hardware > Tools > Flashlights & Headlamps > Headlamps
2550
+ Hardware > Tools > Grease Guns
2551
+ Hardware > Tools > Grinders
2552
+ Hardware > Tools > Grips
2553
+ Hardware > Tools > Hammers
2554
+ Hardware > Tools > Hammers > Manual Hammers
2555
+ Hardware > Tools > Hammers > Powered Hammers
2556
+ Hardware > Tools > Handheld Power Mixers
2557
+ Hardware > Tools > Hardware Torches
2558
+ Hardware > Tools > Heat Guns
2559
+ Hardware > Tools > Impact Wrenches & Drivers
2560
+ Hardware > Tools > Industrial Vibrators
2561
+ Hardware > Tools > Inspection Mirrors
2562
+ Hardware > Tools > Ladders & Scaffolding
2563
+ Hardware > Tools > Ladders & Scaffolding > Ladder Carts
2564
+ Hardware > Tools > Ladders & Scaffolding > Ladders
2565
+ Hardware > Tools > Ladders & Scaffolding > Scaffolding
2566
+ Hardware > Tools > Ladders & Scaffolding > Step Stools
2567
+ Hardware > Tools > Ladders & Scaffolding > Work Platforms
2568
+ Hardware > Tools > Lathes
2569
+ Hardware > Tools > Light Bulb Changers
2570
+ Hardware > Tools > Lighters & Matches
2571
+ Hardware > Tools > Log Splitters
2572
+ Hardware > Tools > Magnetic Sweepers
2573
+ Hardware > Tools > Marking Tools
2574
+ Hardware > Tools > Masonry Tools
2575
+ Hardware > Tools > Masonry Tools > Brick Tools
2576
+ Hardware > Tools > Masonry Tools > Cement Mixers
2577
+ Hardware > Tools > Masonry Tools > Construction Lines
2578
+ Hardware > Tools > Masonry Tools > Floats
2579
+ Hardware > Tools > Masonry Tools > Grout Sponges
2580
+ Hardware > Tools > Masonry Tools > Masonry Edgers & Groovers
2581
+ Hardware > Tools > Masonry Tools > Masonry Jointers
2582
+ Hardware > Tools > Masonry Tools > Masonry Trowels
2583
+ Hardware > Tools > Masonry Tools > Power Trowels
2584
+ Hardware > Tools > Mattocks & Pickaxes
2585
+ Hardware > Tools > Measuring Tools & Sensors
2586
+ Hardware > Tools > Measuring Tools & Sensors > Air Quality Meters
2587
+ Hardware > Tools > Measuring Tools & Sensors > Altimeters
2588
+ Hardware > Tools > Measuring Tools & Sensors > Anemometers
2589
+ Hardware > Tools > Measuring Tools & Sensors > Barometers
2590
+ Hardware > Tools > Measuring Tools & Sensors > Calipers
2591
+ Hardware > Tools > Measuring Tools & Sensors > Cruising Rods
2592
+ Hardware > Tools > Measuring Tools & Sensors > Distance Meters
2593
+ Hardware > Tools > Measuring Tools & Sensors > Dividers
2594
+ Hardware > Tools > Measuring Tools & Sensors > Electrical Testing Tools
2595
+ Hardware > Tools > Measuring Tools & Sensors > Flow Meters & Controllers
2596
+ Hardware > Tools > Measuring Tools & Sensors > Gas Detectors
2597
+ Hardware > Tools > Measuring Tools & Sensors > Gauges
2598
+ Hardware > Tools > Measuring Tools & Sensors > Geiger Counters
2599
+ Hardware > Tools > Measuring Tools & Sensors > Hygrometers
2600
+ Hardware > Tools > Measuring Tools & Sensors > Infrared Thermometers
2601
+ Hardware > Tools > Measuring Tools & Sensors > Knife Guides
2602
+ Hardware > Tools > Measuring Tools & Sensors > Levels
2603
+ Hardware > Tools > Measuring Tools & Sensors > Levels > Bubble Levels
2604
+ Hardware > Tools > Measuring Tools & Sensors > Levels > Laser Levels
2605
+ Hardware > Tools > Measuring Tools & Sensors > Levels > Sight Levels
2606
+ Hardware > Tools > Measuring Tools & Sensors > Measuring Scales
2607
+ Hardware > Tools > Measuring Tools & Sensors > Measuring Wheels
2608
+ Hardware > Tools > Measuring Tools & Sensors > Moisture Meters
2609
+ Hardware > Tools > Measuring Tools & Sensors > Probes & Finders
2610
+ Hardware > Tools > Measuring Tools & Sensors > Protractors
2611
+ Hardware > Tools > Measuring Tools & Sensors > Rebar Locators
2612
+ Hardware > Tools > Measuring Tools & Sensors > Rulers
2613
+ Hardware > Tools > Measuring Tools & Sensors > Seismometer
2614
+ Hardware > Tools > Measuring Tools & Sensors > Sound Meters
2615
+ Hardware > Tools > Measuring Tools & Sensors > Squares
2616
+ Hardware > Tools > Measuring Tools & Sensors > Straight Edges
2617
+ Hardware > Tools > Measuring Tools & Sensors > Stud Sensors
2618
+ Hardware > Tools > Measuring Tools & Sensors > Tape Measures
2619
+ Hardware > Tools > Measuring Tools & Sensors > Theodolites
2620
+ Hardware > Tools > Measuring Tools & Sensors > Thermal Imaging Cameras
2621
+ Hardware > Tools > Measuring Tools & Sensors > Thermocouples & Thermopiles
2622
+ Hardware > Tools > Measuring Tools & Sensors > Transducers
2623
+ Hardware > Tools > Measuring Tools & Sensors > UV Light Meters
2624
+ Hardware > Tools > Measuring Tools & Sensors > Vibration Meters
2625
+ Hardware > Tools > Measuring Tools & Sensors > Weather Forecasters & Stations
2626
+ Hardware > Tools > Measuring Tools & Sensors > pH Meters
2627
+ Hardware > Tools > Milling Machines
2628
+ Hardware > Tools > Multifunction Power Tools
2629
+ Hardware > Tools > Nail Pullers
2630
+ Hardware > Tools > Nailers & Staplers
2631
+ Hardware > Tools > Oil Filter Drains
2632
+ Hardware > Tools > Paint Tools
2633
+ Hardware > Tools > Paint Tools > Airbrushes
2634
+ Hardware > Tools > Paint Tools > Paint Brushes
2635
+ Hardware > Tools > Paint Tools > Paint Edgers
2636
+ Hardware > Tools > Paint Tools > Paint Rollers
2637
+ Hardware > Tools > Paint Tools > Paint Shakers
2638
+ Hardware > Tools > Paint Tools > Paint Sponges
2639
+ Hardware > Tools > Paint Tools > Paint Sprayers
2640
+ Hardware > Tools > Paint Tools > Paint Strainers
2641
+ Hardware > Tools > Paint Tools > Paint Trays
2642
+ Hardware > Tools > Pickup Tools
2643
+ Hardware > Tools > Pipe & Bar Benders
2644
+ Hardware > Tools > Pipe & Tube Cleaners
2645
+ Hardware > Tools > Pipe Brushes
2646
+ Hardware > Tools > Planers
2647
+ Hardware > Tools > Planes
2648
+ Hardware > Tools > Pliers
2649
+ Hardware > Tools > Plungers
2650
+ Hardware > Tools > Polishers & Buffers
2651
+ Hardware > Tools > Post Hole Diggers
2652
+ Hardware > Tools > Pry Bars
2653
+ Hardware > Tools > Punches & Awls
2654
+ Hardware > Tools > Putty Knives & Scrapers
2655
+ Hardware > Tools > Reamers
2656
+ Hardware > Tools > Riveting Tools
2657
+ Hardware > Tools > Riveting Tools > Rivet Guns
2658
+ Hardware > Tools > Riveting Tools > Rivet Pliers
2659
+ Hardware > Tools > Routing Tools
2660
+ Hardware > Tools > Sanders
2661
+ Hardware > Tools > Sanding Blocks
2662
+ Hardware > Tools > Saw Horses
2663
+ Hardware > Tools > Saws
2664
+ Hardware > Tools > Saws > Band Saws
2665
+ Hardware > Tools > Saws > Cut-Off Saws
2666
+ Hardware > Tools > Saws > Hand Saws
2667
+ Hardware > Tools > Saws > Handheld Circular Saws
2668
+ Hardware > Tools > Saws > Jigsaws
2669
+ Hardware > Tools > Saws > Masonry & Tile Saws
2670
+ Hardware > Tools > Saws > Miter Saws
2671
+ Hardware > Tools > Saws > Panel Saws
2672
+ Hardware > Tools > Saws > Reciprocating Saws
2673
+ Hardware > Tools > Saws > Scroll Saws
2674
+ Hardware > Tools > Saws > Table Saws
2675
+ Hardware > Tools > Screwdrivers
2676
+ Hardware > Tools > Shapers
2677
+ Hardware > Tools > Sharpeners
2678
+ Hardware > Tools > Socket Drivers
2679
+ Hardware > Tools > Soldering Irons
2680
+ Hardware > Tools > Tap Reseaters
2681
+ Hardware > Tools > Taps & Dies
2682
+ Hardware > Tools > Threading Machines
2683
+ Hardware > Tools > Tool Clamps & Vises
2684
+ Hardware > Tools > Tool Files
2685
+ Hardware > Tools > Tool Keys
2686
+ Hardware > Tools > Tool Knives
2687
+ Hardware > Tools > Tool Sets
2688
+ Hardware > Tools > Tool Sets > Hand Tool Sets
2689
+ Hardware > Tools > Tool Sets > Power Tool Combo Sets
2690
+ Hardware > Tools > Welding Guns & Plasma Cutters
2691
+ Hardware > Tools > Wire & Cable Hand Tools
2692
+ Hardware > Tools > Work Lights
2693
+ Hardware > Tools > Wrenches
2694
+ Health & Beauty
2695
+ Health & Beauty > Health Care
2696
+ Health & Beauty > Health Care > Acupuncture
2697
+ Health & Beauty > Health Care > Acupuncture > Acupuncture Models
2698
+ Health & Beauty > Health Care > Acupuncture > Acupuncture Needles
2699
+ Health & Beauty > Health Care > Bed Pans
2700
+ Health & Beauty > Health Care > Biometric Monitor Accessories
2701
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Activity Monitor Accessories
2702
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories
2703
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Control Solution
2704
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Test Strips
2705
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Lancing Devices
2706
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories
2707
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories > Blood Pressure Monitor Cuffs
2708
+ Health & Beauty > Health Care > Biometric Monitor Accessories > Body Weight Scale Accessories
2709
+ Health & Beauty > Health Care > Biometric Monitors
2710
+ Health & Beauty > Health Care > Biometric Monitors > Activity Monitors
2711
+ Health & Beauty > Health Care > Biometric Monitors > Blood Glucose Meters
2712
+ Health & Beauty > Health Care > Biometric Monitors > Blood Pressure Monitors
2713
+ Health & Beauty > Health Care > Biometric Monitors > Body Fat Analyzers
2714
+ Health & Beauty > Health Care > Biometric Monitors > Body Weight Scales
2715
+ Health & Beauty > Health Care > Biometric Monitors > Breathalyzers
2716
+ Health & Beauty > Health Care > Biometric Monitors > Cholesterol Analyzers
2717
+ Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests
2718
+ Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests > Fertility Tests & Monitors
2719
+ Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests > Ovulation Tests
2720
+ Health & Beauty > Health Care > Biometric Monitors > Medical Thermometers
2721
+ Health & Beauty > Health Care > Biometric Monitors > Prenatal Heart Rate Monitors
2722
+ Health & Beauty > Health Care > Biometric Monitors > Pulse Oximeters
2723
+ Health & Beauty > Health Care > Condoms
2724
+ Health & Beauty > Health Care > Conductivity Gels & Lotions
2725
+ Health & Beauty > Health Care > Contraceptive Cases
2726
+ Health & Beauty > Health Care > First Aid
2727
+ Health & Beauty > Health Care > First Aid > Antiseptics & Cleaning Supplies
2728
+ Health & Beauty > Health Care > First Aid > Cast & Bandage Protectors
2729
+ Health & Beauty > Health Care > First Aid > Eye Wash Supplies
2730
+ Health & Beauty > Health Care > First Aid > First Aid Kits
2731
+ Health & Beauty > Health Care > First Aid > Hot & Cold Therapies
2732
+ Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heat Rubs
2733
+ Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heating Pads
2734
+ Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Ice Packs
2735
+ Health & Beauty > Health Care > First Aid > Medical Tape & Bandages
2736
+ Health & Beauty > Health Care > Fitness & Nutrition
2737
+ Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Bars
2738
+ Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Drinks & Shakes
2739
+ Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Gels & Chews
2740
+ Health & Beauty > Health Care > Fitness & Nutrition > Nutritional Food Purées
2741
+ Health & Beauty > Health Care > Fitness & Nutrition > Tube Feeding Supplements
2742
+ Health & Beauty > Health Care > Fitness & Nutrition > Vitamins & Supplements
2743
+ Health & Beauty > Health Care > Hearing Aids
2744
+ Health & Beauty > Health Care > Incontinence Aids
2745
+ Health & Beauty > Health Care > Light Therapy Lamps
2746
+ Health & Beauty > Health Care > Medical Alarm Systems
2747
+ Health & Beauty > Health Care > Medical Identification Tags & Jewelry
2748
+ Health & Beauty > Health Care > Medical Tests
2749
+ Health & Beauty > Health Care > Medical Tests > Allergy Test Kits
2750
+ Health & Beauty > Health Care > Medical Tests > Blood Typing Test Kits
2751
+ Health & Beauty > Health Care > Medical Tests > Drug Tests
2752
+ Health & Beauty > Health Care > Medical Tests > HIV Tests
2753
+ Health & Beauty > Health Care > Medical Tests > Pregnancy Tests
2754
+ Health & Beauty > Health Care > Medical Tests > Urinary Tract Infection Tests
2755
+ Health & Beauty > Health Care > Medicine & Drugs
2756
+ Health & Beauty > Health Care > Mobility & Accessibility
2757
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment
2758
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Mobility Scooters
2759
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Stair Lifts
2760
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Transfer Boards & Sheets
2761
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Wheelchairs
2762
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment Accessories
2763
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures
2764
+ Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures > Shower Benches & Seats
2765
+ Health & Beauty > Health Care > Mobility & Accessibility > Walking Aid Accessories
2766
+ Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids
2767
+ Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Canes & Walking Sticks
2768
+ Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Crutches
2769
+ Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Walkers
2770
+ Health & Beauty > Health Care > Occupational & Physical Therapy Equipment
2771
+ Health & Beauty > Health Care > Occupational & Physical Therapy Equipment > Electrical Muscle Stimulators
2772
+ Health & Beauty > Health Care > Occupational & Physical Therapy Equipment > Therapeutic Swings
2773
+ Health & Beauty > Health Care > Pillboxes
2774
+ Health & Beauty > Health Care > Respiratory Care
2775
+ Health & Beauty > Health Care > Respiratory Care > Nebulizers
2776
+ Health & Beauty > Health Care > Respiratory Care > Oxygen Tanks
2777
+ Health & Beauty > Health Care > Respiratory Care > PAP Machines
2778
+ Health & Beauty > Health Care > Respiratory Care > PAP Masks
2779
+ Health & Beauty > Health Care > Respiratory Care > Steam Inhalers
2780
+ Health & Beauty > Health Care > Specimen Cups
2781
+ Health & Beauty > Health Care > Spermicides
2782
+ Health & Beauty > Health Care > Stump Shrinkers
2783
+ Health & Beauty > Health Care > Supports & Braces
2784
+ Health & Beauty > Health Care > Surgical Lubricants
2785
+ Health & Beauty > Jewelry Cleaning & Care
2786
+ Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaning Solutions & Polishes
2787
+ Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaning Tools
2788
+ Health & Beauty > Jewelry Cleaning & Care > Jewelry Holders
2789
+ Health & Beauty > Jewelry Cleaning & Care > Jewelry Steam Cleaners
2790
+ Health & Beauty > Jewelry Cleaning & Care > Watch Repair Kits
2791
+ Health & Beauty > Personal Care
2792
+ Health & Beauty > Personal Care > Back Care
2793
+ Health & Beauty > Personal Care > Back Care > Back & Lumbar Support Cushions
2794
+ Health & Beauty > Personal Care > Cosmetics
2795
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body
2796
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Adult Hygienic Wipes
2797
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bar Soap
2798
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Additives
2799
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Brushes
2800
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Sponges & Loofahs
2801
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Body Wash
2802
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Hand Sanitizers & Wipes
2803
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Liquid Hand Soap
2804
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Powdered Hand Soap
2805
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body > Shower Caps
2806
+ Health & Beauty > Personal Care > Cosmetics > Bath & Body Gift Sets
2807
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Sets
2808
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tool Cleansers
2809
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools
2810
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools
2811
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Double Eyelid Glue & Tape
2812
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyebrow Stencils
2813
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curler Refills
2814
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curlers
2815
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Face Mirrors
2816
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Facial Blotting Paper
2817
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories
2818
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Adhesive
2819
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Applicators
2820
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Remover
2821
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Brushes
2822
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Sponges
2823
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Refillable Makeup Palettes & Cases
2824
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools
2825
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Pushers
2826
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Scissors
2827
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure & Pedicure Spacers
2828
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure Tool Sets
2829
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Buffers
2830
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Clippers
2831
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drill Accessories
2832
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drills
2833
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Dryers
2834
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Files & Emery Boards
2835
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools
2836
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Facial Saunas
2837
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Foot Files
2838
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Lotion & Sunscreen Applicators
2839
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Pumice Stones
2840
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Extractors
2841
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Rollers
2842
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brush Heads
2843
+ Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brushes & Systems
2844
+ Health & Beauty > Personal Care > Cosmetics > Makeup
2845
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup
2846
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body & Hair Glitter
2847
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body Paint & Foundation
2848
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Costume & Stage Makeup
2849
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup
2850
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Primer
2851
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Shadow
2852
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyebrow Enhancers
2853
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyeliner
2854
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > False Eyelashes
2855
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Lash & Brow Growth Treatments
2856
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara
2857
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara Primer
2858
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup
2859
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Blushes & Bronzers
2860
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Powder
2861
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Primer
2862
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Foundations & Concealers
2863
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Highlighters & Luminizers
2864
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup
2865
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip & Cheek Stains
2866
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Gloss
2867
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Liner
2868
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Primer
2869
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lipstick
2870
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Makeup Finishing Sprays
2871
+ Health & Beauty > Personal Care > Cosmetics > Makeup > Temporary Tattoos
2872
+ Health & Beauty > Personal Care > Cosmetics > Nail Care
2873
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Cuticle Cream & Oil
2874
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > False Nails
2875
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Manicure Glue
2876
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Art Kits & Accessories
2877
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Drying Drops & Sprays
2878
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Removers
2879
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Thinners
2880
+ Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polishes
2881
+ Health & Beauty > Personal Care > Cosmetics > Perfume & Cologne
2882
+ Health & Beauty > Personal Care > Cosmetics > Skin Care
2883
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Acne Treatments & Kits
2884
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Anti-Aging Skin Care Kits
2885
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Oil
2886
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Powder
2887
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Compressed Skin Care Mask Sheets
2888
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansers
2889
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansing Kits
2890
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Pore Strips
2891
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments
2892
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments > Lip Balms
2893
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments > Medicated Lip Treatments
2894
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer
2895
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Makeup Removers
2896
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Petroleum Jelly
2897
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Care Masks & Peels
2898
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Insect Repellent
2899
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Sunscreen
2900
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products
2901
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Self Tanner
2902
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Tanning Oil & Lotion
2903
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents
2904
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents > Astringents
2905
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents > Toners
2906
+ Health & Beauty > Personal Care > Cosmetics > Skin Care > Wart Removers
2907
+ Health & Beauty > Personal Care > Cotton Balls
2908
+ Health & Beauty > Personal Care > Cotton Swabs
2909
+ Health & Beauty > Personal Care > Deodorant & Anti-Perspirant
2910
+ Health & Beauty > Personal Care > Deodorant & Anti-Perspirant > Anti-Perspirant
2911
+ Health & Beauty > Personal Care > Deodorant & Anti-Perspirant > Deodorant
2912
+ Health & Beauty > Personal Care > Ear Care
2913
+ Health & Beauty > Personal Care > Ear Care > Ear Candles
2914
+ Health & Beauty > Personal Care > Ear Care > Ear Drops
2915
+ Health & Beauty > Personal Care > Ear Care > Ear Dryers
2916
+ Health & Beauty > Personal Care > Ear Care > Ear Picks & Spoons
2917
+ Health & Beauty > Personal Care > Ear Care > Ear Syringes
2918
+ Health & Beauty > Personal Care > Ear Care > Ear Wax Removal Kits
2919
+ Health & Beauty > Personal Care > Ear Care > Earplug Dispensers
2920
+ Health & Beauty > Personal Care > Ear Care > Earplugs
2921
+ Health & Beauty > Personal Care > Enema Kits & Supplies
2922
+ Health & Beauty > Personal Care > Feminine Sanitary Supplies
2923
+ Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Deodorant
2924
+ Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Douches & Creams
2925
+ Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Pads & Protectors
2926
+ Health & Beauty > Personal Care > Feminine Sanitary Supplies > Menstrual Cups
2927
+ Health & Beauty > Personal Care > Feminine Sanitary Supplies > Tampons
2928
+ Health & Beauty > Personal Care > Foot Care
2929
+ Health & Beauty > Personal Care > Foot Care > Bunion Care Supplies
2930
+ Health & Beauty > Personal Care > Foot Care > Corn & Callus Care Supplies
2931
+ Health & Beauty > Personal Care > Foot Care > Foot Odor Removers
2932
+ Health & Beauty > Personal Care > Foot Care > Insoles & Inserts
2933
+ Health & Beauty > Personal Care > Foot Care > Toe Spacers
2934
+ Health & Beauty > Personal Care > Hair Care
2935
+ Health & Beauty > Personal Care > Hair Care > Hair Care Kits
2936
+ Health & Beauty > Personal Care > Hair Care > Hair Color
2937
+ Health & Beauty > Personal Care > Hair Care > Hair Color Removers
2938
+ Health & Beauty > Personal Care > Hair Care > Hair Coloring Accessories
2939
+ Health & Beauty > Personal Care > Hair Care > Hair Loss Concealers
2940
+ Health & Beauty > Personal Care > Hair Care > Hair Loss Treatments
2941
+ Health & Beauty > Personal Care > Hair Care > Hair Permanents & Straighteners
2942
+ Health & Beauty > Personal Care > Hair Care > Hair Shears
2943
+ Health & Beauty > Personal Care > Hair Care > Hair Steamers & Heat Caps
2944
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Products
2945
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories
2946
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Curler Clips & Pins
2947
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Dryer Accessories
2948
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Iron Accessories
2949
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools
2950
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Combs & Brushes
2951
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Curling Irons
2952
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Curlers
2953
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Dryers
2954
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Straighteners
2955
+ Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Styling Tool Sets
2956
+ Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner
2957
+ Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner > Conditioners
2958
+ Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner > Shampoo
2959
+ Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner > Shampoo & Conditioner Sets
2960
+ Health & Beauty > Personal Care > Massage & Relaxation
2961
+ Health & Beauty > Personal Care > Massage & Relaxation > Back Scratchers
2962
+ Health & Beauty > Personal Care > Massage & Relaxation > Eye Pillows
2963
+ Health & Beauty > Personal Care > Massage & Relaxation > Massage Chairs
2964
+ Health & Beauty > Personal Care > Massage & Relaxation > Massage Oil
2965
+ Health & Beauty > Personal Care > Massage & Relaxation > Massage Stone Warmers
2966
+ Health & Beauty > Personal Care > Massage & Relaxation > Massage Stones
2967
+ Health & Beauty > Personal Care > Massage & Relaxation > Massage Tables
2968
+ Health & Beauty > Personal Care > Massage & Relaxation > Massagers
2969
+ Health & Beauty > Personal Care > Massage & Relaxation > Massagers > Electric Massagers
2970
+ Health & Beauty > Personal Care > Massage & Relaxation > Massagers > Manual Massage Tools
2971
+ Health & Beauty > Personal Care > Massage & Relaxation > Massagers > Massage Cushions
2972
+ Health & Beauty > Personal Care > Oral Care
2973
+ Health & Beauty > Personal Care > Oral Care > Breath Spray
2974
+ Health & Beauty > Personal Care > Oral Care > Dental Floss
2975
+ Health & Beauty > Personal Care > Oral Care > Dental Mouthguards
2976
+ Health & Beauty > Personal Care > Oral Care > Dental Water Jet Replacement Tips
2977
+ Health & Beauty > Personal Care > Oral Care > Dental Water Jets
2978
+ Health & Beauty > Personal Care > Oral Care > Denture Adhesives
2979
+ Health & Beauty > Personal Care > Oral Care > Denture Cleaners
2980
+ Health & Beauty > Personal Care > Oral Care > Denture Repair Kits
2981
+ Health & Beauty > Personal Care > Oral Care > Dentures
2982
+ Health & Beauty > Personal Care > Oral Care > Gum Stimulators
2983
+ Health & Beauty > Personal Care > Oral Care > Mouthwash
2984
+ Health & Beauty > Personal Care > Oral Care > Orthodontic Appliance Cases
2985
+ Health & Beauty > Personal Care > Oral Care > Power Flossers
2986
+ Health & Beauty > Personal Care > Oral Care > Teeth Whiteners
2987
+ Health & Beauty > Personal Care > Oral Care > Tongue Scrapers
2988
+ Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories
2989
+ Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Covers
2990
+ Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Replacement Heads
2991
+ Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Sanitizers
2992
+ Health & Beauty > Personal Care > Oral Care > Toothbrushes
2993
+ Health & Beauty > Personal Care > Oral Care > Toothpaste
2994
+ Health & Beauty > Personal Care > Oral Care > Toothpaste Squeezers & Dispensers
2995
+ Health & Beauty > Personal Care > Oral Care > Toothpicks
2996
+ Health & Beauty > Personal Care > Personal Lubricants
2997
+ Health & Beauty > Personal Care > Shaving & Grooming
2998
+ Health & Beauty > Personal Care > Shaving & Grooming > Aftershave
2999
+ Health & Beauty > Personal Care > Shaving & Grooming > Body & Facial Hair Bleach
3000
+ Health & Beauty > Personal Care > Shaving & Grooming > Electric Razor Accessories
3001
+ Health & Beauty > Personal Care > Shaving & Grooming > Electric Razors
3002
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Clipper & Trimmer Accessories
3003
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Clippers & Trimmers
3004
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal
3005
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Depilatories
3006
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Electrolysis Devices
3007
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Epilators
3008
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Hair Removal Wax Warmers
3009
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Laser & IPL Hair Removal Devices
3010
+ Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Waxing Kits & Supplies
3011
+ Health & Beauty > Personal Care > Shaving & Grooming > Razors & Razor Blades
3012
+ Health & Beauty > Personal Care > Shaving & Grooming > Shaving Bowls & Mugs
3013
+ Health & Beauty > Personal Care > Shaving & Grooming > Shaving Brushes
3014
+ Health & Beauty > Personal Care > Shaving & Grooming > Shaving Cream
3015
+ Health & Beauty > Personal Care > Shaving & Grooming > Shaving Kits
3016
+ Health & Beauty > Personal Care > Shaving & Grooming > Styptic Pencils
3017
+ Health & Beauty > Personal Care > Sleeping Aids
3018
+ Health & Beauty > Personal Care > Sleeping Aids > Eye Masks
3019
+ Health & Beauty > Personal Care > Sleeping Aids > Snoring & Sleep Apnea Aids
3020
+ Health & Beauty > Personal Care > Sleeping Aids > Travel Pillows
3021
+ Health & Beauty > Personal Care > Sleeping Aids > White Noise Machines
3022
+ Health & Beauty > Personal Care > Spray Tanning Tents
3023
+ Health & Beauty > Personal Care > Tanning Beds
3024
+ Health & Beauty > Personal Care > Tweezers
3025
+ Health & Beauty > Personal Care > Vision Care
3026
+ Health & Beauty > Personal Care > Vision Care > Contact Lens Care
3027
+ Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Care Kits
3028
+ Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Cases
3029
+ Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Solution
3030
+ Health & Beauty > Personal Care > Vision Care > Contact Lenses
3031
+ Health & Beauty > Personal Care > Vision Care > Eye Drops & Lubricants
3032
+ Health & Beauty > Personal Care > Vision Care > Eyeglass Lenses
3033
+ Health & Beauty > Personal Care > Vision Care > Eyeglasses
3034
+ Health & Beauty > Personal Care > Vision Care > Eyewear Accessories
3035
+ Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Cases & Holders
3036
+ Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Lens Cleaning Solutions
3037
+ Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Replacement Parts
3038
+ Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Straps & Chains
3039
+ Health & Beauty > Personal Care > Vision Care > Sunglass Lenses
3040
+ Home & Garden
3041
+ Home & Garden > Bathroom Accessories
3042
+ Home & Garden > Bathroom Accessories > Bath Caddies
3043
+ Home & Garden > Bathroom Accessories > Bath Mats & Rugs
3044
+ Home & Garden > Bathroom Accessories > Bath Pillows
3045
+ Home & Garden > Bathroom Accessories > Bathroom Accessory Mounts
3046
+ Home & Garden > Bathroom Accessories > Bathroom Accessory Sets
3047
+ Home & Garden > Bathroom Accessories > Facial Tissue Holders
3048
+ Home & Garden > Bathroom Accessories > Hand Dryer Accessories
3049
+ Home & Garden > Bathroom Accessories > Hand Dryers
3050
+ Home & Garden > Bathroom Accessories > Medicine Cabinets
3051
+ Home & Garden > Bathroom Accessories > Robe Hooks
3052
+ Home & Garden > Bathroom Accessories > Safety Grab Bars
3053
+ Home & Garden > Bathroom Accessories > Shower Curtain Rings
3054
+ Home & Garden > Bathroom Accessories > Shower Curtains
3055
+ Home & Garden > Bathroom Accessories > Shower Rods
3056
+ Home & Garden > Bathroom Accessories > Soap & Lotion Dispensers
3057
+ Home & Garden > Bathroom Accessories > Soap Dishes & Holders
3058
+ Home & Garden > Bathroom Accessories > Toilet Brush Replacement Heads
3059
+ Home & Garden > Bathroom Accessories > Toilet Brushes & Holders
3060
+ Home & Garden > Bathroom Accessories > Toilet Paper Holders
3061
+ Home & Garden > Bathroom Accessories > Toothbrush Holders
3062
+ Home & Garden > Bathroom Accessories > Towel Racks & Holders
3063
+ Home & Garden > Business & Home Security
3064
+ Home & Garden > Business & Home Security > Dummy Surveillance Cameras
3065
+ Home & Garden > Business & Home Security > Home Alarm Systems
3066
+ Home & Garden > Business & Home Security > Motion Sensors
3067
+ Home & Garden > Business & Home Security > Safety & Security Mirrors
3068
+ Home & Garden > Business & Home Security > Security Lights
3069
+ Home & Garden > Business & Home Security > Security Monitors & Recorders
3070
+ Home & Garden > Business & Home Security > Security Safe Accessories
3071
+ Home & Garden > Business & Home Security > Security Safes
3072
+ Home & Garden > Business & Home Security > Security System Sensors
3073
+ Home & Garden > Decor
3074
+ Home & Garden > Decor > Address Signs
3075
+ Home & Garden > Decor > Artificial Flora
3076
+ Home & Garden > Decor > Artificial Food
3077
+ Home & Garden > Decor > Artwork
3078
+ Home & Garden > Decor > Artwork > Decorative Tapestries
3079
+ Home & Garden > Decor > Artwork > Posters, Prints, & Visual Artwork
3080
+ Home & Garden > Decor > Artwork > Sculptures & Statues
3081
+ Home & Garden > Decor > Backrest Pillows
3082
+ Home & Garden > Decor > Baskets
3083
+ Home & Garden > Decor > Bird & Wildlife Feeder Accessories
3084
+ Home & Garden > Decor > Bird & Wildlife Feeders
3085
+ Home & Garden > Decor > Bird & Wildlife Feeders > Bird Feeders
3086
+ Home & Garden > Decor > Bird & Wildlife Feeders > Butterfly Feeders
3087
+ Home & Garden > Decor > Bird & Wildlife Feeders > Squirrel Feeders
3088
+ Home & Garden > Decor > Bird & Wildlife House Accessories
3089
+ Home & Garden > Decor > Bird & Wildlife Houses
3090
+ Home & Garden > Decor > Bird & Wildlife Houses > Bat Houses
3091
+ Home & Garden > Decor > Bird & Wildlife Houses > Birdhouses
3092
+ Home & Garden > Decor > Bird & Wildlife Houses > Butterfly Houses
3093
+ Home & Garden > Decor > Bird Baths
3094
+ Home & Garden > Decor > Bookends
3095
+ Home & Garden > Decor > Cardboard Cutouts
3096
+ Home & Garden > Decor > Chair & Sofa Cushions
3097
+ Home & Garden > Decor > Clock Parts
3098
+ Home & Garden > Decor > Clocks
3099
+ Home & Garden > Decor > Clocks > Alarm Clocks
3100
+ Home & Garden > Decor > Clocks > Desk & Shelf Clocks
3101
+ Home & Garden > Decor > Clocks > Floor & Grandfather Clocks
3102
+ Home & Garden > Decor > Clocks > Wall Clocks
3103
+ Home & Garden > Decor > Coat & Hat Racks
3104
+ Home & Garden > Decor > Decorative Bells
3105
+ Home & Garden > Decor > Decorative Bottles
3106
+ Home & Garden > Decor > Decorative Bowls
3107
+ Home & Garden > Decor > Decorative Jars
3108
+ Home & Garden > Decor > Decorative Plaques
3109
+ Home & Garden > Decor > Decorative Plates
3110
+ Home & Garden > Decor > Decorative Trays
3111
+ Home & Garden > Decor > Door Mats
3112
+ Home & Garden > Decor > Dreamcatchers
3113
+ Home & Garden > Decor > Dried Flowers
3114
+ Home & Garden > Decor > Ecospheres
3115
+ Home & Garden > Decor > Figurines
3116
+ Home & Garden > Decor > Finials
3117
+ Home & Garden > Decor > Flag & Windsock Accessories
3118
+ Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Lights
3119
+ Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Mounting Hardware & Kits
3120
+ Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Poles
3121
+ Home & Garden > Decor > Flags & Windsocks
3122
+ Home & Garden > Decor > Flameless Candles
3123
+ Home & Garden > Decor > Fountains & Ponds
3124
+ Home & Garden > Decor > Fountains & Ponds > Fountain & Pond Accessories
3125
+ Home & Garden > Decor > Fountains & Ponds > Fountains & Waterfalls
3126
+ Home & Garden > Decor > Fountains & Ponds > Ponds
3127
+ Home & Garden > Decor > Garden & Stepping Stones
3128
+ Home & Garden > Decor > Growth Charts
3129
+ Home & Garden > Decor > Home Decor Decals
3130
+ Home & Garden > Decor > Home Fragrance Accessories
3131
+ Home & Garden > Decor > Home Fragrance Accessories > Candle & Oil Warmers
3132
+ Home & Garden > Decor > Home Fragrance Accessories > Candle Holders
3133
+ Home & Garden > Decor > Home Fragrance Accessories > Candle Snuffers
3134
+ Home & Garden > Decor > Home Fragrance Accessories > Incense Holders
3135
+ Home & Garden > Decor > Home Fragrances
3136
+ Home & Garden > Decor > Home Fragrances > Air Fresheners
3137
+ Home & Garden > Decor > Home Fragrances > Candles
3138
+ Home & Garden > Decor > Home Fragrances > Fragrance Oil
3139
+ Home & Garden > Decor > Home Fragrances > Incense
3140
+ Home & Garden > Decor > Home Fragrances > Potpourri
3141
+ Home & Garden > Decor > Home Fragrances > Wax Tarts
3142
+ Home & Garden > Decor > Hourglasses
3143
+ Home & Garden > Decor > House Numbers & Letters
3144
+ Home & Garden > Decor > Lawn Ornaments & Garden Sculptures
3145
+ Home & Garden > Decor > Mail Slots
3146
+ Home & Garden > Decor > Mailbox Accessories
3147
+ Home & Garden > Decor > Mailbox Accessories > Mailbox Covers
3148
+ Home & Garden > Decor > Mailbox Accessories > Mailbox Enclosures
3149
+ Home & Garden > Decor > Mailbox Accessories > Mailbox Flags
3150
+ Home & Garden > Decor > Mailbox Accessories > Mailbox Posts
3151
+ Home & Garden > Decor > Mailbox Accessories > Mailbox Replacement Doors
3152
+ Home & Garden > Decor > Mailboxes
3153
+ Home & Garden > Decor > Mirrors
3154
+ Home & Garden > Decor > Music Boxes
3155
+ Home & Garden > Decor > Napkin Rings
3156
+ Home & Garden > Decor > Novelty Signs
3157
+ Home & Garden > Decor > Ottoman Cushions
3158
+ Home & Garden > Decor > Picture Frames
3159
+ Home & Garden > Decor > Piggy Banks & Money Jars
3160
+ Home & Garden > Decor > Rain Chains
3161
+ Home & Garden > Decor > Rain Gauges
3162
+ Home & Garden > Decor > Refrigerator Magnets
3163
+ Home & Garden > Decor > Rugs
3164
+ Home & Garden > Decor > Seasonal & Holiday Decorations
3165
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Advent Calendars
3166
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Skirts
3167
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Stands
3168
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Easter Egg Decorating Kits
3169
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Displays & Stands
3170
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Hooks
3171
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornaments
3172
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stocking Hangers
3173
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stockings
3174
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Japanese Traditional Dolls
3175
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Nativity Sets
3176
+ Home & Garden > Decor > Seasonal & Holiday Decorations > Seasonal Village Sets & Accessories
3177
+ Home & Garden > Decor > Shadow Boxes
3178
+ Home & Garden > Decor > Slipcovers
3179
+ Home & Garden > Decor > Snow Globes
3180
+ Home & Garden > Decor > Suncatchers
3181
+ Home & Garden > Decor > Sundials
3182
+ Home & Garden > Decor > Throw Pillows
3183
+ Home & Garden > Decor > Trunks
3184
+ Home & Garden > Decor > Vase Fillers & Table Scatters
3185
+ Home & Garden > Decor > Vases
3186
+ Home & Garden > Decor > Wallpaper
3187
+ Home & Garden > Decor > Weather Vanes & Roof Decor
3188
+ Home & Garden > Decor > Wind Chimes
3189
+ Home & Garden > Decor > Wind Wheels & Spinners
3190
+ Home & Garden > Decor > Window Magnets
3191
+ Home & Garden > Decor > Window Treatment Accessories
3192
+ Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rings
3193
+ Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rods
3194
+ Home & Garden > Decor > Window Treatment Accessories > Curtain Holdbacks & Tassels
3195
+ Home & Garden > Decor > Window Treatment Accessories > Window Treatment Replacement Parts
3196
+ Home & Garden > Decor > Window Treatments
3197
+ Home & Garden > Decor > Window Treatments > Curtains & Drapes
3198
+ Home & Garden > Decor > Window Treatments > Stained Glass Panels
3199
+ Home & Garden > Decor > Window Treatments > Window Blinds & Shades
3200
+ Home & Garden > Decor > Window Treatments > Window Films
3201
+ Home & Garden > Decor > Window Treatments > Window Screens
3202
+ Home & Garden > Decor > Window Treatments > Window Valances & Cornices
3203
+ Home & Garden > Decor > World Globes
3204
+ Home & Garden > Decor > Wreaths & Garlands
3205
+ Home & Garden > Emergency Preparedness
3206
+ Home & Garden > Emergency Preparedness > Earthquake Alarms
3207
+ Home & Garden > Emergency Preparedness > Emergency Blankets
3208
+ Home & Garden > Emergency Preparedness > Emergency Food Kits
3209
+ Home & Garden > Emergency Preparedness > Emergency Tools & Kits
3210
+ Home & Garden > Emergency Preparedness > Furniture Anchors
3211
+ Home & Garden > Fireplace & Wood Stove Accessories
3212
+ Home & Garden > Fireplace & Wood Stove Accessories > Bellows
3213
+ Home & Garden > Fireplace & Wood Stove Accessories > Fireplace & Wood Stove Grates
3214
+ Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Andirons
3215
+ Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Reflectors
3216
+ Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Screens
3217
+ Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Tools
3218
+ Home & Garden > Fireplace & Wood Stove Accessories > Firewood & Fuel
3219
+ Home & Garden > Fireplace & Wood Stove Accessories > Hearth Pads
3220
+ Home & Garden > Fireplace & Wood Stove Accessories > Log Rack & Carrier Accessories
3221
+ Home & Garden > Fireplace & Wood Stove Accessories > Log Racks & Carriers
3222
+ Home & Garden > Fireplace & Wood Stove Accessories > Wood Stove Fans & Blowers
3223
+ Home & Garden > Fireplaces
3224
+ Home & Garden > Flood, Fire & Gas Safety
3225
+ Home & Garden > Flood, Fire & Gas Safety > Fire Alarm Control Panels
3226
+ Home & Garden > Flood, Fire & Gas Safety > Fire Alarms
3227
+ Home & Garden > Flood, Fire & Gas Safety > Fire Extinguisher & Equipment Storage
3228
+ Home & Garden > Flood, Fire & Gas Safety > Fire Extinguishers
3229
+ Home & Garden > Flood, Fire & Gas Safety > Fire Sprinklers
3230
+ Home & Garden > Flood, Fire & Gas Safety > Heat Detectors
3231
+ Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors
3232
+ Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors > Carbon Monoxide Detectors
3233
+ Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors > Smoke Detectors
3234
+ Home & Garden > Flood, Fire & Gas Safety > Water & Flood Detectors
3235
+ Home & Garden > Household Appliance Accessories
3236
+ Home & Garden > Household Appliance Accessories > Air Conditioner Accessories
3237
+ Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Covers
3238
+ Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Filters
3239
+ Home & Garden > Household Appliance Accessories > Air Purifier Accessories
3240
+ Home & Garden > Household Appliance Accessories > Air Purifier Accessories > Air Purifier Filters
3241
+ Home & Garden > Household Appliance Accessories > Dehumidifier Accessories
3242
+ Home & Garden > Household Appliance Accessories > Fan Accessories
3243
+ Home & Garden > Household Appliance Accessories > Floor & Steam Cleaner Accessories
3244
+ Home & Garden > Household Appliance Accessories > Furnace & Boiler Accessories
3245
+ Home & Garden > Household Appliance Accessories > Heating Radiator Accessories
3246
+ Home & Garden > Household Appliance Accessories > Heating Radiator Accessories > Heating Radiator Reflectors
3247
+ Home & Garden > Household Appliance Accessories > Humidifier Accessories
3248
+ Home & Garden > Household Appliance Accessories > Humidifier Accessories > Humidifier Filters
3249
+ Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories
3250
+ Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Garment Steamer Accessories
3251
+ Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Iron Accessories
3252
+ Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Steam Press Accessories
3253
+ Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washer & Dryer Accessories
3254
+ Home & Garden > Household Appliance Accessories > Patio Heater Accessories
3255
+ Home & Garden > Household Appliance Accessories > Patio Heater Accessories > Patio Heater Covers
3256
+ Home & Garden > Household Appliance Accessories > Vacuum Accessories
3257
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories
3258
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Anode Rods
3259
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Hot Water Tanks
3260
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Elements
3261
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Expansion Tanks
3262
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Pans
3263
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Stacks
3264
+ Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Vents
3265
+ Home & Garden > Household Appliances
3266
+ Home & Garden > Household Appliances > Climate Control Appliances
3267
+ Home & Garden > Household Appliances > Climate Control Appliances > Air Conditioners
3268
+ Home & Garden > Household Appliances > Climate Control Appliances > Air Purifiers
3269
+ Home & Garden > Household Appliances > Climate Control Appliances > Dehumidifiers
3270
+ Home & Garden > Household Appliances > Climate Control Appliances > Duct Heaters
3271
+ Home & Garden > Household Appliances > Climate Control Appliances > Evaporative Coolers
3272
+ Home & Garden > Household Appliances > Climate Control Appliances > Fans
3273
+ Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ceiling Fans
3274
+ Home & Garden > Household Appliances > Climate Control Appliances > Fans > Desk & Pedestal Fans
3275
+ Home & Garden > Household Appliances > Climate Control Appliances > Fans > Powered Hand Fans & Misters
3276
+ Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ventilation Fans
3277
+ Home & Garden > Household Appliances > Climate Control Appliances > Fans > Wall Mount Fans
3278
+ Home & Garden > Household Appliances > Climate Control Appliances > Furnaces & Boilers
3279
+ Home & Garden > Household Appliances > Climate Control Appliances > Heating Radiators
3280
+ Home & Garden > Household Appliances > Climate Control Appliances > Humidifiers
3281
+ Home & Garden > Household Appliances > Climate Control Appliances > Outdoor Misting Systems
3282
+ Home & Garden > Household Appliances > Climate Control Appliances > Patio Heaters
3283
+ Home & Garden > Household Appliances > Climate Control Appliances > Space Heaters
3284
+ Home & Garden > Household Appliances > Floor & Carpet Dryers
3285
+ Home & Garden > Household Appliances > Floor & Steam Cleaners
3286
+ Home & Garden > Household Appliances > Floor & Steam Cleaners > Carpet Shampooers
3287
+ Home & Garden > Household Appliances > Floor & Steam Cleaners > Carpet Steamers
3288
+ Home & Garden > Household Appliances > Floor & Steam Cleaners > Floor Scrubbers
3289
+ Home & Garden > Household Appliances > Floor & Steam Cleaners > Steam Mops
3290
+ Home & Garden > Household Appliances > Floor Polishers & Buffers
3291
+ Home & Garden > Household Appliances > Futon Dryers
3292
+ Home & Garden > Household Appliances > Garage Door Keypads & Remotes
3293
+ Home & Garden > Household Appliances > Garage Door Openers
3294
+ Home & Garden > Household Appliances > Laundry Appliances
3295
+ Home & Garden > Household Appliances > Laundry Appliances > Dryers
3296
+ Home & Garden > Household Appliances > Laundry Appliances > Garment Steamers
3297
+ Home & Garden > Household Appliances > Laundry Appliances > Irons & Ironing Systems
3298
+ Home & Garden > Household Appliances > Laundry Appliances > Laundry Combo Units
3299
+ Home & Garden > Household Appliances > Laundry Appliances > Steam Presses
3300
+ Home & Garden > Household Appliances > Laundry Appliances > Washing Machines
3301
+ Home & Garden > Household Appliances > Ultrasonic Cleaners
3302
+ Home & Garden > Household Appliances > Vacuums
3303
+ Home & Garden > Household Appliances > Wallpaper Steamers
3304
+ Home & Garden > Household Appliances > Water Heaters
3305
+ Home & Garden > Household Supplies
3306
+ Home & Garden > Household Supplies > Drawer & Shelf Liners
3307
+ Home & Garden > Household Supplies > Floor Protection Films & Runners
3308
+ Home & Garden > Household Supplies > Furniture Floor Protectors
3309
+ Home & Garden > Household Supplies > Garage Floor Mats
3310
+ Home & Garden > Household Supplies > Garbage Bags
3311
+ Home & Garden > Household Supplies > Household Cleaning Supplies
3312
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Broom & Mop Handles
3313
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Broom Heads
3314
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Brooms
3315
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Buckets
3316
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Carpet Sweepers
3317
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Cleaning Gloves
3318
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Duster Refills
3319
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Dusters
3320
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Dustpans
3321
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Fabric & Upholstery Protectors
3322
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products
3323
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > All-Purpose Cleaners
3324
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Carpet Cleaners
3325
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Descalers & Decalcifiers
3326
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dish Detergent & Soap
3327
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dishwasher Cleaners
3328
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Fabric & Upholstery Cleaners
3329
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Floor Cleaners
3330
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Furniture Cleaners & Polish
3331
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners
3332
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners > Glass Cleaners
3333
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners > Muti-surface Cleaners
3334
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Household Disinfectants
3335
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Oven & Grill Cleaners
3336
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Pet Odor & Stain Removers
3337
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Rinse Aids
3338
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Stainless Steel Cleaners & Polishes
3339
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Toilet Bowl Cleaners
3340
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Tub & Tile Cleaners
3341
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Washing Machine Cleaners
3342
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Mop Heads & Refills
3343
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Mops
3344
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brush Heads & Refills
3345
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brushes
3346
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Shop Towels & General-Purpose Cleaning Cloths
3347
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Sponges & Scouring Pads
3348
+ Home & Garden > Household Supplies > Household Cleaning Supplies > Squeegees
3349
+ Home & Garden > Household Supplies > Household Paper Products
3350
+ Home & Garden > Household Supplies > Household Paper Products > Facial Tissues
3351
+ Home & Garden > Household Supplies > Household Paper Products > Paper Napkins
3352
+ Home & Garden > Household Supplies > Household Paper Products > Paper Towels
3353
+ Home & Garden > Household Supplies > Household Paper Products > Toilet Paper
3354
+ Home & Garden > Household Supplies > Household Thermometers
3355
+ Home & Garden > Household Supplies > Laundry Supplies
3356
+ Home & Garden > Household Supplies > Laundry Supplies > Bleach
3357
+ Home & Garden > Household Supplies > Laundry Supplies > Clothespins
3358
+ Home & Garden > Household Supplies > Laundry Supplies > Dry Cleaning Kits
3359
+ Home & Garden > Household Supplies > Laundry Supplies > Drying Racks & Hangers
3360
+ Home & Garden > Household Supplies > Laundry Supplies > Fabric Refreshers
3361
+ Home & Garden > Household Supplies > Laundry Supplies > Fabric Shavers
3362
+ Home & Garden > Household Supplies > Laundry Supplies > Fabric Softeners & Dryer Sheets
3363
+ Home & Garden > Household Supplies > Laundry Supplies > Fabric Stain Removers
3364
+ Home & Garden > Household Supplies > Laundry Supplies > Fabric Starch
3365
+ Home & Garden > Household Supplies > Laundry Supplies > Garment Shields
3366
+ Home & Garden > Household Supplies > Laundry Supplies > Iron Rests
3367
+ Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Pads & Covers
3368
+ Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Replacement Parts
3369
+ Home & Garden > Household Supplies > Laundry Supplies > Ironing Boards
3370
+ Home & Garden > Household Supplies > Laundry Supplies > Laundry Balls
3371
+ Home & Garden > Household Supplies > Laundry Supplies > Laundry Baskets
3372
+ Home & Garden > Household Supplies > Laundry Supplies > Laundry Detergent
3373
+ Home & Garden > Household Supplies > Laundry Supplies > Laundry Wash Bags & Frames
3374
+ Home & Garden > Household Supplies > Laundry Supplies > Lint Rollers
3375
+ Home & Garden > Household Supplies > Laundry Supplies > Wrinkle Releasers & Anti-Static Sprays
3376
+ Home & Garden > Household Supplies > Moisture Absorbers
3377
+ Home & Garden > Household Supplies > Pest Control
3378
+ Home & Garden > Household Supplies > Pest Control > Fly Swatters
3379
+ Home & Garden > Household Supplies > Pest Control > Pest Control Traps
3380
+ Home & Garden > Household Supplies > Pest Control > Pesticides
3381
+ Home & Garden > Household Supplies > Pest Control > Repellents
3382
+ Home & Garden > Household Supplies > Pest Control > Repellents > Animal & Pet Repellents
3383
+ Home & Garden > Household Supplies > Pest Control > Repellents > Household Insect Repellents
3384
+ Home & Garden > Household Supplies > Rug Pads
3385
+ Home & Garden > Household Supplies > Shoe Care & Tools
3386
+ Home & Garden > Household Supplies > Shoe Care & Tools > Boot Pulls
3387
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Bags
3388
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Brushes
3389
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Care Kits
3390
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Dryers
3391
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Horns & Dressing Aids
3392
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishers
3393
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishes & Waxes
3394
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Scrapers
3395
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Treatments & Dyes
3396
+ Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Trees & Shapers
3397
+ Home & Garden > Household Supplies > Stair Treads
3398
+ Home & Garden > Household Supplies > Storage & Organization
3399
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage
3400
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Charging Valets
3401
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Closet Organizers & Garment Racks
3402
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Clothes Valets
3403
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hangers
3404
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hat Boxes
3405
+ Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Shoe Racks & Organizers
3406
+ Home & Garden > Household Supplies > Storage & Organization > Flatware Chests
3407
+ Home & Garden > Household Supplies > Storage & Organization > Household Drawer Organizer Inserts
3408
+ Home & Garden > Household Supplies > Storage & Organization > Household Storage Bags
3409
+ Home & Garden > Household Supplies > Storage & Organization > Household Storage Caddies
3410
+ Home & Garden > Household Supplies > Storage & Organization > Household Storage Containers
3411
+ Home & Garden > Household Supplies > Storage & Organization > Household Storage Drawers
3412
+ Home & Garden > Household Supplies > Storage & Organization > Photo Storage
3413
+ Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Albums
3414
+ Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Storage Boxes
3415
+ Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks
3416
+ Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Ironing Board Hooks & Racks
3417
+ Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Umbrella Stands & Racks
3418
+ Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Utility Hooks
3419
+ Home & Garden > Household Supplies > Trash Compactor Accessories
3420
+ Home & Garden > Household Supplies > Waste Containment
3421
+ Home & Garden > Household Supplies > Waste Containment > Dumpsters
3422
+ Home & Garden > Household Supplies > Waste Containment > Hazardous Waste Containers
3423
+ Home & Garden > Household Supplies > Waste Containment > Recycling Containers
3424
+ Home & Garden > Household Supplies > Waste Containment > Trash Cans & Wastebaskets
3425
+ Home & Garden > Household Supplies > Waste Containment Accessories
3426
+ Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Carts
3427
+ Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Enclosures
3428
+ Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Labels & Signs
3429
+ Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Lids
3430
+ Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Wheels
3431
+ Home & Garden > Kitchen & Dining
3432
+ Home & Garden > Kitchen & Dining > Barware
3433
+ Home & Garden > Kitchen & Dining > Barware > Absinthe Fountains
3434
+ Home & Garden > Kitchen & Dining > Barware > Beer Dispensers & Taps
3435
+ Home & Garden > Kitchen & Dining > Barware > Beverage Chilling Cubes & Sticks
3436
+ Home & Garden > Kitchen & Dining > Barware > Beverage Tubs & Chillers
3437
+ Home & Garden > Kitchen & Dining > Barware > Bottle Caps
3438
+ Home & Garden > Kitchen & Dining > Barware > Bottle Stoppers & Savers
3439
+ Home & Garden > Kitchen & Dining > Barware > Coaster Holders
3440
+ Home & Garden > Kitchen & Dining > Barware > Coasters
3441
+ Home & Garden > Kitchen & Dining > Barware > Cocktail & Barware Tool Sets
3442
+ Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools
3443
+ Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Bar Ice Picks
3444
+ Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Bottle Openers
3445
+ Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Cocktail Shakers
3446
+ Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Cocktail Strainers
3447
+ Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Muddlers
3448
+ Home & Garden > Kitchen & Dining > Barware > Corkscrews
3449
+ Home & Garden > Kitchen & Dining > Barware > Decanters
3450
+ Home & Garden > Kitchen & Dining > Barware > Foil Cutters
3451
+ Home & Garden > Kitchen & Dining > Barware > Wine Aerators
3452
+ Home & Garden > Kitchen & Dining > Barware > Wine Bottle Holders
3453
+ Home & Garden > Kitchen & Dining > Barware > Wine Glass Charms
3454
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware
3455
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware
3456
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bakeware Sets
3457
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Baking & Cookie Sheets
3458
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bread Pans & Molds
3459
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Broiling Pans
3460
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Cake Pans & Molds
3461
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Muffin & Pastry Pans
3462
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pie & Quiche Pans
3463
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Pans
3464
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Stones
3465
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Ramekins & Souffle Dishes
3466
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Roasting Pans
3467
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories
3468
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Mats & Liners
3469
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Weights
3470
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Roasting Pan Racks
3471
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware
3472
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware & Bakeware Combo Sets
3473
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Casserole Dishes
3474
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Cookware Sets
3475
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Crêpe & Blini Pans
3476
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Double Boilers
3477
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Dutch Ovens
3478
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Fermentation & Pickling Crocks
3479
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Griddles & Grill Pans
3480
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Grill Presses
3481
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Paella Pans
3482
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Pressure Cookers & Canners
3483
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Saucepans
3484
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Sauté Pans
3485
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Skillets & Frying Pans
3486
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stock Pots
3487
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stovetop Kettles
3488
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Tagines & Clay Cooking Pots
3489
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Woks
3490
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories
3491
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Handles
3492
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Lids
3493
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pressure Cooker & Canner Accessories
3494
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Steamer Baskets
3495
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories
3496
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Brushes
3497
+ Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Rings
3498
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers
3499
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Airpots
3500
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Canteens
3501
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Coolers
3502
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves
3503
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Can & Bottle Sleeves
3504
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Cup Sleeves
3505
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Flasks
3506
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Insulated Bags
3507
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Lunch Boxes & Totes
3508
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Picnic Baskets
3509
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Replacement Drink Lids
3510
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Thermoses
3511
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Water Bottles
3512
+ Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Wine Carrier Bags
3513
+ Home & Garden > Kitchen & Dining > Food Storage
3514
+ Home & Garden > Kitchen & Dining > Food Storage > Bread Boxes & Bags
3515
+ Home & Garden > Kitchen & Dining > Food Storage > Candy Buckets
3516
+ Home & Garden > Kitchen & Dining > Food Storage > Cookie Jars
3517
+ Home & Garden > Kitchen & Dining > Food Storage > Food Container Covers
3518
+ Home & Garden > Kitchen & Dining > Food Storage > Food Storage Bags
3519
+ Home & Garden > Kitchen & Dining > Food Storage > Food Storage Containers
3520
+ Home & Garden > Kitchen & Dining > Food Storage > Food Wraps
3521
+ Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Foil
3522
+ Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Parchment Paper
3523
+ Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Plastic Wrap
3524
+ Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Wax Paper
3525
+ Home & Garden > Kitchen & Dining > Food Storage > Honey Jars
3526
+ Home & Garden > Kitchen & Dining > Food Storage Accessories
3527
+ Home & Garden > Kitchen & Dining > Food Storage Accessories > Food & Beverage Labels
3528
+ Home & Garden > Kitchen & Dining > Food Storage Accessories > Food Wrap Dispensers
3529
+ Home & Garden > Kitchen & Dining > Food Storage Accessories > Oxygen Absorbers
3530
+ Home & Garden > Kitchen & Dining > Food Storage Accessories > Twist Ties & Bag Clips
3531
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories
3532
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Breadmaker Accessories
3533
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories
3534
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanter Warmers
3535
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanters
3536
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filter Baskets
3537
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filters
3538
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Grinder Accessories
3539
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Grinders
3540
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker & Espresso Machine Replacement Parts
3541
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker Water Filters
3542
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Frothing Pitchers
3543
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Portafilters
3544
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cooktop, Oven & Range Accessories
3545
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cotton Candy Machine Accessories
3546
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Deep Fryer Accessories
3547
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Dishwasher Parts & Accessories
3548
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Kettle Accessories
3549
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Skillet & Wok Accessories
3550
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories
3551
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Cooking Gel Fuels
3552
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Forks
3553
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Pot Stands
3554
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories
3555
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Sheets
3556
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Trays
3557
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories
3558
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer & Blender Accessories
3559
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Freezer Accessories
3560
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Garbage Disposal Accessories
3561
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories
3562
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories > Ice Cream Maker Freezer Bowls
3563
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Crusher & Shaver Accessories
3564
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Maker Accessories
3565
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Juicer Accessories
3566
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Microwave Oven Accessories
3567
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories
3568
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Briquettes
3569
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Chimneys
3570
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Carts
3571
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Covers
3572
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Racks & Toppers
3573
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Replacement Parts
3574
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Spits & Baskets
3575
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grilling Planks
3576
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Smoking Chips & Pellets
3577
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Pasta Maker Accessories
3578
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Popcorn Maker Accessories
3579
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Portable Cooking Stove Accessories
3580
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Range Hood Accessories
3581
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Refrigerator Accessories
3582
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Soda Maker Accessories
3583
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories
3584
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pan Covers
3585
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pans
3586
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Toaster Accessories
3587
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories
3588
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories > Vacuum Sealer Bags
3589
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Waffle Iron Accessories
3590
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories
3591
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories > Water Cooler Bottles
3592
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Wine Fridge Accessories
3593
+ Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Yogurt Maker Accessories
3594
+ Home & Garden > Kitchen & Dining > Kitchen Appliances
3595
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Beverage Warmers
3596
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Breadmakers
3597
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Chocolate Tempering Machines
3598
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines
3599
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Drip Coffee Makers
3600
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Electric & Stovetop Espresso Pots
3601
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Espresso Machines
3602
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > French Presses
3603
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Percolators
3604
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Vacuum Coffee Makers
3605
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Cooktops
3606
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Cotton Candy Machines
3607
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Deep Fryers
3608
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Deli Slicers
3609
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Dishwashers
3610
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Griddles & Grills
3611
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Kettles
3612
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Skillets & Woks
3613
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Fondue Pots & Sets
3614
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers
3615
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Egg Cookers
3616
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Food Steamers
3617
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Rice Cookers
3618
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Slow Cookers
3619
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Thermal Cookers
3620
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Water Ovens
3621
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Dehydrators
3622
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills
3623
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Mixers & Blenders
3624
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Smokers
3625
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers
3626
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Chafing Dishes
3627
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Food Heat Lamps
3628
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Rice Keepers
3629
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Steam Tables
3630
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Freezers
3631
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Frozen Drink Makers
3632
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Garbage Disposals
3633
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Gas Griddles
3634
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Drink Makers
3635
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Plates
3636
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Cream Makers
3637
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Crushers & Shavers
3638
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Makers
3639
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Juicers
3640
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Knife Sharpeners
3641
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Microwave Ovens
3642
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Milk Frothers & Steamers
3643
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Mochi Makers
3644
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Outdoor Grills
3645
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens
3646
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Pasta Makers
3647
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Popcorn Makers
3648
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Portable Cooking Stoves
3649
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Range Hoods
3650
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Ranges
3651
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Refrigerators
3652
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Roaster Ovens & Rotisseries
3653
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Soda Makers
3654
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Soy Milk Makers
3655
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Tea Makers
3656
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills
3657
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Countertop & Toaster Ovens
3658
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Donut Makers
3659
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Muffin & Cupcake Makers
3660
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizza Makers & Ovens
3661
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizzelle Makers
3662
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pretzel Makers
3663
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Sandwich Makers
3664
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Toasters
3665
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Tortilla & Flatbread Makers
3666
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Waffle Irons
3667
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Trash Compactors
3668
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Vacuum Sealers
3669
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Coolers
3670
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Filters
3671
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Wine Fridges
3672
+ Home & Garden > Kitchen & Dining > Kitchen Appliances > Yogurt Makers
3673
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils
3674
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Aprons
3675
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Baking Peels
3676
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basters
3677
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basting Brushes
3678
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Beverage Dispensers
3679
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Decorating Supplies
3680
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Servers
3681
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Crushers
3682
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Openers
3683
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Carving Forks
3684
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Channel Knives
3685
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Colanders & Strainers
3686
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Condiment Dispensers
3687
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Cutters
3688
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Presses
3689
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometer Accessories
3690
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometers
3691
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Timers
3692
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Torches
3693
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooling Racks
3694
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cutting Boards
3695
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dish Racks & Drain Boards
3696
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dough Wheels
3697
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories
3698
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories > Electric Knife Replacement Blades
3699
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knives
3700
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Flour Sifters
3701
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food & Drink Stencils
3702
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers
3703
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Lobster & Crab Crackers
3704
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers
3705
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers > Decorative Nutcrackers
3706
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Dispensers
3707
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Graters & Zesters
3708
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Peelers & Corers
3709
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Steaming Bags
3710
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Sticks & Skewers
3711
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Funnels
3712
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Garlic Presses
3713
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Gelatin Molds
3714
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ice Cube Trays
3715
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Jerky Guns
3716
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Knives
3717
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Molds
3718
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers
3719
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Can Organizers
3720
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Drinkware Holders
3721
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Cabinet Organizers
3722
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Counter & Beverage Station Organizers
3723
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Utensil Holders & Racks
3724
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Knife Blocks & Holders
3725
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Napkin Holders & Dispensers
3726
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Paper Towel Holders & Dispensers
3727
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Pot Racks
3728
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Spice Organizers
3729
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Straw Holders & Dispensers
3730
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Sugar Caddies
3731
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Toothpick Holders & Dispensers
3732
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Utensil & Flatware Trays
3733
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers
3734
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bench Scrapers
3735
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bowl Scrapers
3736
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Grill Scrapers
3737
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Shears
3738
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers
3739
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Utensil Sets
3740
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ladles
3741
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mashers
3742
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Measuring Cups & Spoons
3743
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Meat Tenderizers
3744
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mixing Bowls
3745
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mortars & Pestles
3746
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oil & Vinegar Dispensers
3747
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Bags
3748
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Mitts & Pot Holders
3749
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pasta Molds & Stamps
3750
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Blenders
3751
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Cloths
3752
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutter Accessories
3753
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutters
3754
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ricers
3755
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories
3756
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Covers & Sleeves
3757
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Rings
3758
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pins
3759
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Dressing Mixers & Shakers
3760
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Spinners
3761
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops
3762
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Cream Scoops
3763
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Scoops
3764
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Melon Ballers
3765
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Popcorn & French Fry Scoops
3766
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Caddies
3767
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Mats & Grids
3768
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Slotted Spoons
3769
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spatulas
3770
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spice Grinder Accessories
3771
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spice Grinders
3772
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spoon Rests
3773
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sugar Dispensers
3774
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sushi Mats
3775
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tea Strainers
3776
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tongs
3777
+ Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Whisks
3778
+ Home & Garden > Kitchen & Dining > Prefabricated Kitchens & Kitchenettes
3779
+ Home & Garden > Kitchen & Dining > Tableware
3780
+ Home & Garden > Kitchen & Dining > Tableware > Coffee & Tea Sets
3781
+ Home & Garden > Kitchen & Dining > Tableware > Coffee Servers & Tea Pots
3782
+ Home & Garden > Kitchen & Dining > Tableware > Dinnerware
3783
+ Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Bowls
3784
+ Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Dinnerware Sets
3785
+ Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Plates
3786
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware
3787
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses
3788
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Cups
3789
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Saucers
3790
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Drinkware Sets
3791
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Mugs
3792
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Shot Glasses
3793
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware
3794
+ Home & Garden > Kitchen & Dining > Tableware > Drinkware > Tumblers
3795
+ Home & Garden > Kitchen & Dining > Tableware > Flatware
3796
+ Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopstick Accessories
3797
+ Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopsticks
3798
+ Home & Garden > Kitchen & Dining > Tableware > Flatware > Flatware Sets
3799
+ Home & Garden > Kitchen & Dining > Tableware > Flatware > Forks
3800
+ Home & Garden > Kitchen & Dining > Tableware > Flatware > Spoons
3801
+ Home & Garden > Kitchen & Dining > Tableware > Flatware > Table Knives
3802
+ Home & Garden > Kitchen & Dining > Tableware > Salt & Pepper Shakers
3803
+ Home & Garden > Kitchen & Dining > Tableware > Serveware
3804
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Butter Dishes
3805
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Boards
3806
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Stands
3807
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Egg Cups
3808
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Gravy Boats
3809
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Punch Bowls
3810
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Pitchers & Carafes
3811
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Platters
3812
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Trays
3813
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Sugar Bowls & Creamers
3814
+ Home & Garden > Kitchen & Dining > Tableware > Serveware > Tureens
3815
+ Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories
3816
+ Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Punch Bowl Stands
3817
+ Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Lids
3818
+ Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Stands
3819
+ Home & Garden > Kitchen & Dining > Tableware > Tablecloth Clips & Weights
3820
+ Home & Garden > Kitchen & Dining > Tableware > Trivets
3821
+ Home & Garden > Lawn & Garden
3822
+ Home & Garden > Lawn & Garden > Gardening
3823
+ Home & Garden > Lawn & Garden > Gardening > Composting
3824
+ Home & Garden > Lawn & Garden > Gardening > Composting > Compost
3825
+ Home & Garden > Lawn & Garden > Gardening > Composting > Compost Aerators
3826
+ Home & Garden > Lawn & Garden > Gardening > Composting > Composters
3827
+ Home & Garden > Lawn & Garden > Gardening > Disease Control
3828
+ Home & Garden > Lawn & Garden > Gardening > Fertilizers
3829
+ Home & Garden > Lawn & Garden > Gardening > Garden Pot Saucers & Trays
3830
+ Home & Garden > Lawn & Garden > Gardening > Gardening Accessories
3831
+ Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Scooters, Seats & Kneelers
3832
+ Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Totes
3833
+ Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Potting Benches
3834
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories
3835
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Gardening Tool Handles
3836
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Gardening Tool Heads
3837
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Wheelbarrow Parts
3838
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools
3839
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Bulb Planting Tools
3840
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Cultivating Tools
3841
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Forks
3842
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Sickles & Machetes
3843
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Trowels
3844
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn & Garden Sprayers
3845
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn Rollers
3846
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Saws
3847
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Shears
3848
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Rakes
3849
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Shovels & Spades
3850
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Spreaders
3851
+ Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Wheelbarrows
3852
+ Home & Garden > Lawn & Garden > Gardening > Greenhouses
3853
+ Home & Garden > Lawn & Garden > Gardening > Herbicides
3854
+ Home & Garden > Lawn & Garden > Gardening > Landscape Fabric
3855
+ Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories
3856
+ Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories > Landscape Fabric Staples & Pins
3857
+ Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories > Landscape Fabric Tape
3858
+ Home & Garden > Lawn & Garden > Gardening > Mulch
3859
+ Home & Garden > Lawn & Garden > Gardening > Plant Cages & Supports
3860
+ Home & Garden > Lawn & Garden > Gardening > Plant Stands
3861
+ Home & Garden > Lawn & Garden > Gardening > Pot & Planter Liners
3862
+ Home & Garden > Lawn & Garden > Gardening > Pots & Planters
3863
+ Home & Garden > Lawn & Garden > Gardening > Rain Barrels
3864
+ Home & Garden > Lawn & Garden > Gardening > Sands & Soils
3865
+ Home & Garden > Lawn & Garden > Gardening > Sands & Soils > Sand
3866
+ Home & Garden > Lawn & Garden > Gardening > Sands & Soils > Soil
3867
+ Home & Garden > Lawn & Garden > Outdoor Living
3868
+ Home & Garden > Lawn & Garden > Outdoor Living > Awning Accessories
3869
+ Home & Garden > Lawn & Garden > Outdoor Living > Awnings
3870
+ Home & Garden > Lawn & Garden > Outdoor Living > Hammock Parts & Accessories
3871
+ Home & Garden > Lawn & Garden > Outdoor Living > Hammocks
3872
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets
3873
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Beach Mats
3874
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Picnic Blankets
3875
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Poncho Liners
3876
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures
3877
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopies & Gazebos
3878
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories
3879
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Enclosure Kits
3880
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Frames
3881
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Tops
3882
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Poles
3883
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Weights
3884
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Arches, Trellises, Arbors & Pergolas
3885
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Bridges
3886
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Sheds, Garages & Carports
3887
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories
3888
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella & Sunshade Fabric
3889
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Bases
3890
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Covers
3891
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Enclosure Kits
3892
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Lights
3893
+ Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrellas & Sunshades
3894
+ Home & Garden > Lawn & Garden > Outdoor Living > Porch Swing Accessories
3895
+ Home & Garden > Lawn & Garden > Outdoor Living > Porch Swings
3896
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment
3897
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Chainsaws
3898
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Grass Edgers
3899
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Hedge Trimmers
3900
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Aerators & Dethatchers
3901
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers
3902
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Riding Mowers
3903
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Robotic Mowers
3904
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Tow-Behind Mowers
3905
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Walk-Behind Mowers
3906
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Vacuums
3907
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Leaf Blowers
3908
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Base Units
3909
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Sets
3910
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Sweepers
3911
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Tillers & Cultivators
3912
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Pressure Washers
3913
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Snow Blowers
3914
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Tractors
3915
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment > Weed Trimmers
3916
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories
3917
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories
3918
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Bars
3919
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Chains
3920
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Grass Edger Accessories
3921
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Hedge Trimmer Accessories
3922
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories
3923
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Brush Mower Attachments
3924
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Bags
3925
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Belts
3926
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Blades
3927
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Covers
3928
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Mulch Kits
3929
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Mulch Plugs & Plates
3930
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Pulleys & Idlers
3931
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tire Tubes
3932
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tires
3933
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Wheels
3934
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Striping Kits
3935
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Sweepers
3936
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories
3937
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories > Leaf Blower Tubes
3938
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments
3939
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Grass Edger Attachments
3940
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Ground & Leaf Blower Attachments
3941
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Hedge Trimmer Attachments
3942
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Pole Saw Attachments
3943
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Tiller & Cultivator Attachments
3944
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Weed Trimmer Attachments
3945
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries
3946
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Pressure Washer Accessories
3947
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Snow Blower Accessories
3948
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories
3949
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories > Tractor Tires
3950
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories > Tractor Wheels
3951
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories
3952
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Blades & Spools
3953
+ Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Spool Covers
3954
+ Home & Garden > Lawn & Garden > Snow Removal
3955
+ Home & Garden > Lawn & Garden > Snow Removal > Ice Scrapers & Snow Brushes
3956
+ Home & Garden > Lawn & Garden > Snow Removal > Snow Shovels
3957
+ Home & Garden > Lawn & Garden > Watering & Irrigation
3958
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hose Fittings & Valves
3959
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hose Spray Nozzles
3960
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hoses
3961
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories
3962
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories > Sprinkler Controls
3963
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories > Sprinkler Valves
3964
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinklers & Sprinkler Heads
3965
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Can Accesssories
3966
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Cans
3967
+ Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Globes & Spikes
3968
+ Home & Garden > Lighting
3969
+ Home & Garden > Lighting > Emergency Lighting
3970
+ Home & Garden > Lighting > Floating & Submersible Lights
3971
+ Home & Garden > Lighting > Flood & Spot Lights
3972
+ Home & Garden > Lighting > In-Ground Lights
3973
+ Home & Garden > Lighting > Lamps
3974
+ Home & Garden > Lighting > Landscape Pathway Lighting
3975
+ Home & Garden > Lighting > Light Bulbs
3976
+ Home & Garden > Lighting > Light Bulbs > Compact Fluorescent Lamps
3977
+ Home & Garden > Lighting > Light Bulbs > Fluorescent Tubes
3978
+ Home & Garden > Lighting > Light Bulbs > Incandescent Light Bulbs
3979
+ Home & Garden > Lighting > Light Bulbs > LED Light Bulbs
3980
+ Home & Garden > Lighting > Light Ropes & Strings
3981
+ Home & Garden > Lighting > Lighting Fixtures
3982
+ Home & Garden > Lighting > Lighting Fixtures > Cabinet Light Fixtures
3983
+ Home & Garden > Lighting > Lighting Fixtures > Ceiling Light Fixtures
3984
+ Home & Garden > Lighting > Lighting Fixtures > Chandeliers
3985
+ Home & Garden > Lighting > Lighting Fixtures > Wall Light Fixtures
3986
+ Home & Garden > Lighting > Night Lights & Ambient Lighting
3987
+ Home & Garden > Lighting > Picture Lights
3988
+ Home & Garden > Lighting > Tiki Torches & Oil Lamps
3989
+ Home & Garden > Lighting > Track Lighting
3990
+ Home & Garden > Lighting > Track Lighting > Track Lighting Accessories
3991
+ Home & Garden > Lighting > Track Lighting > Track Lighting Fixtures
3992
+ Home & Garden > Lighting > Track Lighting > Track Lighting Rails
3993
+ Home & Garden > Lighting Accessories
3994
+ Home & Garden > Lighting Accessories > Lamp Post Bases
3995
+ Home & Garden > Lighting Accessories > Lamp Post Mounts
3996
+ Home & Garden > Lighting Accessories > Lamp Shades
3997
+ Home & Garden > Lighting Accessories > Lighting Timers
3998
+ Home & Garden > Lighting Accessories > Oil Lamp Fuel
3999
+ Home & Garden > Linens & Bedding
4000
+ Home & Garden > Linens & Bedding > Bedding
4001
+ Home & Garden > Linens & Bedding > Bedding > Bed Canopies
4002
+ Home & Garden > Linens & Bedding > Bedding > Bed Sheets
4003
+ Home & Garden > Linens & Bedding > Bedding > Bedskirts
4004
+ Home & Garden > Linens & Bedding > Bedding > Blankets
4005
+ Home & Garden > Linens & Bedding > Bedding > Duvet Covers
4006
+ Home & Garden > Linens & Bedding > Bedding > Mattress Protectors
4007
+ Home & Garden > Linens & Bedding > Bedding > Mattress Protectors > Mattress Encasements
4008
+ Home & Garden > Linens & Bedding > Bedding > Mattress Protectors > Mattress Pads
4009
+ Home & Garden > Linens & Bedding > Bedding > Nap Mats
4010
+ Home & Garden > Linens & Bedding > Bedding > Pillowcases & Shams
4011
+ Home & Garden > Linens & Bedding > Bedding > Pillows
4012
+ Home & Garden > Linens & Bedding > Bedding > Quilts & Comforters
4013
+ Home & Garden > Linens & Bedding > Kitchen Linens Sets
4014
+ Home & Garden > Linens & Bedding > Table Linens
4015
+ Home & Garden > Linens & Bedding > Table Linens > Cloth Napkins
4016
+ Home & Garden > Linens & Bedding > Table Linens > Doilies
4017
+ Home & Garden > Linens & Bedding > Table Linens > Placemats
4018
+ Home & Garden > Linens & Bedding > Table Linens > Table Runners
4019
+ Home & Garden > Linens & Bedding > Table Linens > Table Skirts
4020
+ Home & Garden > Linens & Bedding > Table Linens > Tablecloths
4021
+ Home & Garden > Linens & Bedding > Towels
4022
+ Home & Garden > Linens & Bedding > Towels > Bath Towels & Washcloths
4023
+ Home & Garden > Linens & Bedding > Towels > Beach Towels
4024
+ Home & Garden > Linens & Bedding > Towels > Kitchen Towels
4025
+ Home & Garden > Parasols & Rain Umbrellas
4026
+ Home & Garden > Plants
4027
+ Home & Garden > Plants > Aquatic Plants
4028
+ Home & Garden > Plants > Flowers
4029
+ Home & Garden > Plants > Indoor & Outdoor Plants
4030
+ Home & Garden > Plants > Indoor & Outdoor Plants > Bushes & Shrubs
4031
+ Home & Garden > Plants > Indoor & Outdoor Plants > Landscaping & Garden Plants
4032
+ Home & Garden > Plants > Indoor & Outdoor Plants > Potted Houseplants
4033
+ Home & Garden > Plants > Plant & Herb Growing Kits
4034
+ Home & Garden > Plants > Seeds
4035
+ Home & Garden > Plants > Seeds > Plant & Flower Bulbs
4036
+ Home & Garden > Plants > Seeds > Seeds & Seed Tape
4037
+ Home & Garden > Plants > Trees
4038
+ Home & Garden > Pool & Spa
4039
+ Home & Garden > Pool & Spa > Pool & Spa Accessories
4040
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Diving Boards
4041
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Chlorine Generators
4042
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Filters
4043
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Maintenance Kits
4044
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Brushes & Brooms
4045
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cleaner Hoses
4046
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cleaners & Chemicals
4047
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cover Accessories
4048
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Covers & Ground Cloths
4049
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Deck Kits
4050
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Floats & Loungers
4051
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Heaters
4052
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Ladders, Steps & Ramps
4053
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Liners
4054
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Skimmers
4055
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Sweeps & Vacuums
4056
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Toys
4057
+ Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Water Slides
4058
+ Home & Garden > Pool & Spa > Sauna Accessories
4059
+ Home & Garden > Pool & Spa > Sauna Accessories > Sauna Buckets & Ladles
4060
+ Home & Garden > Pool & Spa > Sauna Accessories > Sauna Heaters
4061
+ Home & Garden > Pool & Spa > Sauna Accessories > Sauna Kits
4062
+ Home & Garden > Pool & Spa > Saunas
4063
+ Home & Garden > Pool & Spa > Spas
4064
+ Home & Garden > Pool & Spa > Swimming Pools
4065
+ Home & Garden > Smoking Accessories
4066
+ Home & Garden > Smoking Accessories > Ashtrays
4067
+ Home & Garden > Smoking Accessories > Cigar Cases
4068
+ Home & Garden > Smoking Accessories > Cigar Cutters & Punches
4069
+ Home & Garden > Smoking Accessories > Cigarette Cases
4070
+ Home & Garden > Smoking Accessories > Cigarette Holders
4071
+ Home & Garden > Smoking Accessories > Humidor Accessories
4072
+ Home & Garden > Smoking Accessories > Humidors
4073
+ Home & Garden > Umbrella Sleeves & Cases
4074
+ Home & Garden > Wood Stoves
4075
+ Luggage & Bags
4076
+ Luggage & Bags > Backpacks
4077
+ Luggage & Bags > Briefcases
4078
+ Luggage & Bags > Cosmetic & Toiletry Bags
4079
+ Luggage & Bags > Diaper Bags
4080
+ Luggage & Bags > Dry Boxes
4081
+ Luggage & Bags > Duffel Bags
4082
+ Luggage & Bags > Fanny Packs
4083
+ Luggage & Bags > Garment Bags
4084
+ Luggage & Bags > Luggage Accessories
4085
+ Luggage & Bags > Luggage Accessories > Dry Box Liners & Inserts
4086
+ Luggage & Bags > Luggage Accessories > Luggage Covers
4087
+ Luggage & Bags > Luggage Accessories > Luggage Racks & Stands
4088
+ Luggage & Bags > Luggage Accessories > Luggage Straps
4089
+ Luggage & Bags > Luggage Accessories > Luggage Tags
4090
+ Luggage & Bags > Luggage Accessories > Packing Organizers
4091
+ Luggage & Bags > Luggage Accessories > Travel Bottles & Containers
4092
+ Luggage & Bags > Luggage Accessories > Travel Pouches
4093
+ Luggage & Bags > Messenger Bags
4094
+ Luggage & Bags > Shopping Totes
4095
+ Luggage & Bags > Suitcases
4096
+ Luggage & Bags > Train Cases
4097
+ Mature
4098
+ Mature > Erotic
4099
+ Mature > Erotic > Erotic Books
4100
+ Mature > Erotic > Erotic Clothing
4101
+ Mature > Erotic > Erotic DVDs & Videos
4102
+ Mature > Erotic > Erotic Food & Edibles
4103
+ Mature > Erotic > Erotic Games
4104
+ Mature > Erotic > Erotic Magazines
4105
+ Mature > Erotic > Pole Dancing Kits
4106
+ Mature > Erotic > Sex Toys
4107
+ Mature > Weapons
4108
+ Mature > Weapons > Brass Knuckles
4109
+ Mature > Weapons > Clubs & Batons
4110
+ Mature > Weapons > Combat Knives
4111
+ Mature > Weapons > Gun Care & Accessories
4112
+ Mature > Weapons > Gun Care & Accessories > Ammunition
4113
+ Mature > Weapons > Gun Care & Accessories > Ammunition Cases & Holders
4114
+ Mature > Weapons > Gun Care & Accessories > Gun Cases & Range Bags
4115
+ Mature > Weapons > Gun Care & Accessories > Gun Cleaning
4116
+ Mature > Weapons > Gun Care & Accessories > Gun Cleaning > Gun Cleaning Cloths & Swabs
4117
+ Mature > Weapons > Gun Care & Accessories > Gun Cleaning > Gun Cleaning Patches
4118
+ Mature > Weapons > Gun Care & Accessories > Gun Cleaning > Gun Cleaning Solvents
4119
+ Mature > Weapons > Gun Care & Accessories > Gun Grips
4120
+ Mature > Weapons > Gun Care & Accessories > Gun Holsters
4121
+ Mature > Weapons > Gun Care & Accessories > Gun Lights
4122
+ Mature > Weapons > Gun Care & Accessories > Gun Rails
4123
+ Mature > Weapons > Gun Care & Accessories > Gun Slings
4124
+ Mature > Weapons > Gun Care & Accessories > Reloading Supplies & Equipment
4125
+ Mature > Weapons > Gun Care & Accessories > Reloading Supplies & Equipment > Ammunition Reloading Presses
4126
+ Mature > Weapons > Guns
4127
+ Mature > Weapons > Mace & Pepper Spray
4128
+ Mature > Weapons > Nunchucks
4129
+ Mature > Weapons > Spears
4130
+ Mature > Weapons > Staff & Stick Weapons
4131
+ Mature > Weapons > Stun Guns & Tasers
4132
+ Mature > Weapons > Swords
4133
+ Mature > Weapons > Throwing Stars
4134
+ Mature > Weapons > Whips
4135
+ Media
4136
+ Media > Books
4137
+ Media > Books > Audiobooks
4138
+ Media > Books > E-books
4139
+ Media > Books > Print Books
4140
+ Media > Carpentry & Woodworking Project Plans
4141
+ Media > DVDs & Videos
4142
+ Media > DVDs & Videos > Film & Television DVDs
4143
+ Media > DVDs & Videos > Film & Television Digital Downloads
4144
+ Media > DVDs & Videos > Film & Television VHS Tapes
4145
+ Media > Magazines & Newspapers
4146
+ Media > Magazines & Newspapers > Magazines
4147
+ Media > Magazines & Newspapers > Newspapers
4148
+ Media > Music & Sound Recordings
4149
+ Media > Music & Sound Recordings > Digital Music Downloads
4150
+ Media > Music & Sound Recordings > Music CDs
4151
+ Media > Music & Sound Recordings > Music Cassette Tapes
4152
+ Media > Music & Sound Recordings > Records & LPs
4153
+ Media > Music & Sound Recordings > Spoken Word & Field Recordings
4154
+ Media > Product Manuals
4155
+ Media > Product Manuals > Camera & Optics Manuals
4156
+ Media > Product Manuals > Electronics Manuals
4157
+ Media > Product Manuals > Exercise & Fitness Equipment Manuals
4158
+ Media > Product Manuals > Household Appliance Manuals
4159
+ Media > Product Manuals > Kitchen Appliance Manuals
4160
+ Media > Product Manuals > Model & Toys Manuals
4161
+ Media > Product Manuals > Office Supply Manuals
4162
+ Media > Product Manuals > Power Tool & Equipment Manuals
4163
+ Media > Product Manuals > Vehicle Service Manuals
4164
+ Media > Sheet Music
4165
+ Office Supplies
4166
+ Office Supplies > Book Accessories
4167
+ Office Supplies > Book Accessories > Book Covers
4168
+ Office Supplies > Book Accessories > Book Lights
4169
+ Office Supplies > Book Accessories > Book Stands & Rests
4170
+ Office Supplies > Book Accessories > Bookmarks
4171
+ Office Supplies > Desk Pads & Blotters
4172
+ Office Supplies > Filing & Organization
4173
+ Office Supplies > Filing & Organization > Address Books
4174
+ Office Supplies > Filing & Organization > Binding Supplies
4175
+ Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories
4176
+ Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Binder Rings
4177
+ Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Index Dividers
4178
+ Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Sheet Protectors
4179
+ Office Supplies > Filing & Organization > Binding Supplies > Binders
4180
+ Office Supplies > Filing & Organization > Binding Supplies > Binding Combs & Spines
4181
+ Office Supplies > Filing & Organization > Binding Supplies > Binding Machines
4182
+ Office Supplies > Filing & Organization > Business Card Books
4183
+ Office Supplies > Filing & Organization > Business Card Stands
4184
+ Office Supplies > Filing & Organization > CD/DVD Cases & Organizers
4185
+ Office Supplies > Filing & Organization > Calendars, Organizers & Planners
4186
+ Office Supplies > Filing & Organization > Card Files
4187
+ Office Supplies > Filing & Organization > Card Sleeves
4188
+ Office Supplies > Filing & Organization > Cash Boxes
4189
+ Office Supplies > Filing & Organization > Desk Organizers
4190
+ Office Supplies > Filing & Organization > File Boxes
4191
+ Office Supplies > Filing & Organization > File Folders
4192
+ Office Supplies > Filing & Organization > Folders & Report Covers
4193
+ Office Supplies > Filing & Organization > Folders & Report Covers > Pocket Folders
4194
+ Office Supplies > Filing & Organization > Folders & Report Covers > Report Covers
4195
+ Office Supplies > Filing & Organization > Greeting Card Organizers
4196
+ Office Supplies > Filing & Organization > Mail Sorters
4197
+ Office Supplies > Filing & Organization > Pen & Pencil Cases
4198
+ Office Supplies > Filing & Organization > Portfolios & Padfolios
4199
+ Office Supplies > Filing & Organization > Portfolios & Padfolios > Padfolios
4200
+ Office Supplies > Filing & Organization > Portfolios & Padfolios > Portfolios
4201
+ Office Supplies > Filing & Organization > Recipe Card Boxes
4202
+ Office Supplies > General Office Supplies
4203
+ Office Supplies > General Office Supplies > Brass Fasteners
4204
+ Office Supplies > General Office Supplies > Correction Fluids, Pens & Tapes
4205
+ Office Supplies > General Office Supplies > Correction Fluids, Pens & Tapes > Correction Fluids
4206
+ Office Supplies > General Office Supplies > Correction Fluids, Pens & Tapes > Correction Pens
4207
+ Office Supplies > General Office Supplies > Correction Fluids, Pens & Tapes > Correction Tapes
4208
+ Office Supplies > General Office Supplies > Erasers
4209
+ Office Supplies > General Office Supplies > Labels & Tags
4210
+ Office Supplies > General Office Supplies > Labels & Tags > Address Labels
4211
+ Office Supplies > General Office Supplies > Labels & Tags > Folder Tabs
4212
+ Office Supplies > General Office Supplies > Labels & Tags > Label Clips
4213
+ Office Supplies > General Office Supplies > Labels & Tags > Label Tapes & Refill Rolls
4214
+ Office Supplies > General Office Supplies > Labels & Tags > Shipping Labels
4215
+ Office Supplies > General Office Supplies > Labels & Tags > Shipping Tags
4216
+ Office Supplies > General Office Supplies > Laminating Film, Pouches & Sheets
4217
+ Office Supplies > General Office Supplies > Mounting Putty
4218
+ Office Supplies > General Office Supplies > Office Tape
4219
+ Office Supplies > General Office Supplies > Paper Clips & Clamps
4220
+ Office Supplies > General Office Supplies > Paper Clips & Clamps > Binder Clips
4221
+ Office Supplies > General Office Supplies > Paper Clips & Clamps > Paper Clips
4222
+ Office Supplies > General Office Supplies > Paper Products
4223
+ Office Supplies > General Office Supplies > Paper Products > Binder Paper
4224
+ Office Supplies > General Office Supplies > Paper Products > Blank ID Cards
4225
+ Office Supplies > General Office Supplies > Paper Products > Business Cards
4226
+ Office Supplies > General Office Supplies > Paper Products > Business Forms & Receipts
4227
+ Office Supplies > General Office Supplies > Paper Products > Checks
4228
+ Office Supplies > General Office Supplies > Paper Products > Cover Paper
4229
+ Office Supplies > General Office Supplies > Paper Products > Envelopes
4230
+ Office Supplies > General Office Supplies > Paper Products > Index Cards
4231
+ Office Supplies > General Office Supplies > Paper Products > Notebooks & Notepads
4232
+ Office Supplies > General Office Supplies > Paper Products > Post Cards
4233
+ Office Supplies > General Office Supplies > Paper Products > Printer & Copier Paper
4234
+ Office Supplies > General Office Supplies > Paper Products > Receipt & Adding Machine Paper Rolls
4235
+ Office Supplies > General Office Supplies > Paper Products > Stationery
4236
+ Office Supplies > General Office Supplies > Paper Products > Sticky Notes
4237
+ Office Supplies > General Office Supplies > Rubber Bands
4238
+ Office Supplies > General Office Supplies > Staples
4239
+ Office Supplies > General Office Supplies > Tacks & Pushpins
4240
+ Office Supplies > Impulse Sealers
4241
+ Office Supplies > Lap Desks
4242
+ Office Supplies > Name Plates
4243
+ Office Supplies > Office & Chair Mats
4244
+ Office Supplies > Office & Chair Mats > Anti-Fatigue Mats
4245
+ Office Supplies > Office & Chair Mats > Chair Mats
4246
+ Office Supplies > Office & Chair Mats > Office Mats
4247
+ Office Supplies > Office Carts
4248
+ Office Supplies > Office Carts > AV Carts
4249
+ Office Supplies > Office Carts > Book Carts
4250
+ Office Supplies > Office Carts > File Carts
4251
+ Office Supplies > Office Carts > Mail Carts
4252
+ Office Supplies > Office Carts > Utility Carts
4253
+ Office Supplies > Office Equipment
4254
+ Office Supplies > Office Equipment > Calculator Accessories
4255
+ Office Supplies > Office Equipment > Calculators
4256
+ Office Supplies > Office Equipment > Calculators > Basic Calculators
4257
+ Office Supplies > Office Equipment > Calculators > Construction Calculators
4258
+ Office Supplies > Office Equipment > Calculators > Financial Calculators
4259
+ Office Supplies > Office Equipment > Calculators > Graphing Calculators
4260
+ Office Supplies > Office Equipment > Calculators > Scientific Calculators
4261
+ Office Supplies > Office Equipment > Electronic Dictionaries & Translators
4262
+ Office Supplies > Office Equipment > Label Makers
4263
+ Office Supplies > Office Equipment > Laminators
4264
+ Office Supplies > Office Equipment > Office Shredders
4265
+ Office Supplies > Office Equipment > Postage Meters
4266
+ Office Supplies > Office Equipment > Time & Attendance Clocks
4267
+ Office Supplies > Office Equipment > Transcribers & Dictation Systems
4268
+ Office Supplies > Office Equipment > Typewriters
4269
+ Office Supplies > Office Instruments
4270
+ Office Supplies > Office Instruments > Call Bells
4271
+ Office Supplies > Office Instruments > Clipboards
4272
+ Office Supplies > Office Instruments > Letter Openers
4273
+ Office Supplies > Office Instruments > Magnifiers
4274
+ Office Supplies > Office Instruments > Office Rubber Stamps
4275
+ Office Supplies > Office Instruments > Pencil Sharpeners
4276
+ Office Supplies > Office Instruments > Staple Removers
4277
+ Office Supplies > Office Instruments > Staplers
4278
+ Office Supplies > Office Instruments > Tape Dispensers
4279
+ Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories
4280
+ Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Marker & Highlighter Ink Refills
4281
+ Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Marker & Highlighter Ink Refills > Highlighter Refills
4282
+ Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Marker & Highlighter Ink Refills > Marker Refills
4283
+ Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pen Ink & Refills
4284
+ Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pencil Lead & Refills
4285
+ Office Supplies > Office Instruments > Writing & Drawing Instruments
4286
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Art Charcoals
4287
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Chalk
4288
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Crayons
4289
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Markers & Highlighters
4290
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Markers & Highlighters > Highlighters
4291
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Markers & Highlighters > Markers
4292
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Multifunction Writing Instruments
4293
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pastels
4294
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils
4295
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pen & Pencil Sets
4296
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils
4297
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Art Pencils
4298
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Writing Pencils
4299
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Writing Pencils > Mechanical Pencils
4300
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Writing Pencils > Wooden Pencils
4301
+ Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pens
4302
+ Office Supplies > Paper Handling
4303
+ Office Supplies > Paper Handling > Fingertip Grips
4304
+ Office Supplies > Paper Handling > Hole Punches
4305
+ Office Supplies > Paper Handling > Paper Folding Machines
4306
+ Office Supplies > Paper Handling > Paper Joggers
4307
+ Office Supplies > Paper Handling > Paperweights
4308
+ Office Supplies > Paper Handling > Pencil Boards
4309
+ Office Supplies > Presentation Supplies
4310
+ Office Supplies > Presentation Supplies > Chalkboards
4311
+ Office Supplies > Presentation Supplies > Display Boards
4312
+ Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories
4313
+ Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories > Bulletin Board Trim
4314
+ Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories > Bulletin Board Trim Sets
4315
+ Office Supplies > Presentation Supplies > Display Boards > Bulletin Boards
4316
+ Office Supplies > Presentation Supplies > Display Boards > Foam Boards
4317
+ Office Supplies > Presentation Supplies > Display Boards > Mounting Boards
4318
+ Office Supplies > Presentation Supplies > Display Boards > Poster Boards
4319
+ Office Supplies > Presentation Supplies > Document Cameras
4320
+ Office Supplies > Presentation Supplies > Dry-Erase Boards
4321
+ Office Supplies > Presentation Supplies > Easel Pads
4322
+ Office Supplies > Presentation Supplies > Easels
4323
+ Office Supplies > Presentation Supplies > Laser Pointers
4324
+ Office Supplies > Presentation Supplies > Lecterns
4325
+ Office Supplies > Presentation Supplies > Transparencies
4326
+ Office Supplies > Presentation Supplies > Wireless Presenters
4327
+ Office Supplies > Shipping Supplies
4328
+ Office Supplies > Shipping Supplies > Moving & Shipping Boxes
4329
+ Office Supplies > Shipping Supplies > Packing Materials
4330
+ Office Supplies > Shipping Supplies > Packing Tape
4331
+ Religious & Ceremonial
4332
+ Religious & Ceremonial > Memorial Ceremony Supplies
4333
+ Religious & Ceremonial > Memorial Ceremony Supplies > Memorial Urns
4334
+ Religious & Ceremonial > Religious Items
4335
+ Religious & Ceremonial > Religious Items > Prayer Beads
4336
+ Religious & Ceremonial > Religious Items > Prayer Cards
4337
+ Religious & Ceremonial > Religious Items > Religious Altars
4338
+ Religious & Ceremonial > Religious Items > Religious Veils
4339
+ Religious & Ceremonial > Religious Items > Tarot Cards
4340
+ Religious & Ceremonial > Wedding Ceremony Supplies
4341
+ Religious & Ceremonial > Wedding Ceremony Supplies > Aisle Runners
4342
+ Religious & Ceremonial > Wedding Ceremony Supplies > Flower Girl Baskets
4343
+ Religious & Ceremonial > Wedding Ceremony Supplies > Ring Pillows & Holders
4344
+ Software
4345
+ Software > Computer Software
4346
+ Software > Computer Software > Antivirus & Security Software
4347
+ Software > Computer Software > Business & Productivity Software
4348
+ Software > Computer Software > Compilers & Programming Tools
4349
+ Software > Computer Software > Computer Utilities & Maintenance Software
4350
+ Software > Computer Software > Dictionary & Translation Software
4351
+ Software > Computer Software > Educational Software
4352
+ Software > Computer Software > Financial, Tax & Accounting Software
4353
+ Software > Computer Software > GPS Map Data & Software
4354
+ Software > Computer Software > Handheld & PDA Software
4355
+ Software > Computer Software > Multimedia & Design Software
4356
+ Software > Computer Software > Multimedia & Design Software > 3D Modeling Software
4357
+ Software > Computer Software > Multimedia & Design Software > Animation Editing Software
4358
+ Software > Computer Software > Multimedia & Design Software > Graphic Design & Illustration Software
4359
+ Software > Computer Software > Multimedia & Design Software > Home & Interior Design Software
4360
+ Software > Computer Software > Multimedia & Design Software > Home Publishing Software
4361
+ Software > Computer Software > Multimedia & Design Software > Media Viewing Software
4362
+ Software > Computer Software > Multimedia & Design Software > Music Composition Software
4363
+ Software > Computer Software > Multimedia & Design Software > Sound Editing Software
4364
+ Software > Computer Software > Multimedia & Design Software > Video Editing Software
4365
+ Software > Computer Software > Multimedia & Design Software > Web Design Software
4366
+ Software > Computer Software > Network Software
4367
+ Software > Computer Software > Office Application Software
4368
+ Software > Computer Software > Operating Systems
4369
+ Software > Computer Software > Restore Disks
4370
+ Software > Digital Goods & Currency
4371
+ Software > Digital Goods & Currency > Computer Icons
4372
+ Software > Digital Goods & Currency > Desktop Wallpaper
4373
+ Software > Digital Goods & Currency > Digital Artwork
4374
+ Software > Digital Goods & Currency > Document Templates
4375
+ Software > Digital Goods & Currency > Fonts
4376
+ Software > Digital Goods & Currency > Stock Photographs & Video Footage
4377
+ Software > Digital Goods & Currency > Virtual Currency
4378
+ Software > Video Game Software
4379
+ Sporting Goods
4380
+ Sporting Goods > Athletics
4381
+ Sporting Goods > Athletics > Baseball & Softball
4382
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Bases & Plates
4383
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Batting Gloves
4384
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Gloves & Mitts
4385
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Pitching Mats
4386
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Pitching Mounds
4387
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear
4388
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Baseball & Softball Batting Helmets
4389
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Baseball & Softball Chest Protectors
4390
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Baseball & Softball Leg Guards
4391
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Catchers Equipment Sets
4392
+ Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Catchers Helmets & Masks
4393
+ Sporting Goods > Athletics > Baseball & Softball > Baseball Bats
4394
+ Sporting Goods > Athletics > Baseball & Softball > Baseballs
4395
+ Sporting Goods > Athletics > Baseball & Softball > Pitching Machines
4396
+ Sporting Goods > Athletics > Baseball & Softball > Softball Bats
4397
+ Sporting Goods > Athletics > Baseball & Softball > Softballs
4398
+ Sporting Goods > Athletics > Basketball
4399
+ Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories
4400
+ Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Backboards
4401
+ Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Hoop Padding
4402
+ Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Hoop Posts
4403
+ Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Nets
4404
+ Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Rims
4405
+ Sporting Goods > Athletics > Basketball > Basketball Hoops
4406
+ Sporting Goods > Athletics > Basketball > Basketball Training Aids
4407
+ Sporting Goods > Athletics > Basketball > Basketballs
4408
+ Sporting Goods > Athletics > Boxing & Martial Arts
4409
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear
4410
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & MMA Hand Wraps
4411
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & Martial Arts Arm Guards
4412
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & Martial Arts Body Protectors
4413
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & Martial Arts Headgear
4414
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing Gloves & Mitts
4415
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > MMA Shin Guards
4416
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment
4417
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Boxing & MMA Punch Mitts
4418
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Grappling Dummies
4419
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Punching & Training Bag Accessories
4420
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Punching & Training Bags
4421
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Strike Shields
4422
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing Ring Parts
4423
+ Sporting Goods > Athletics > Boxing & Martial Arts > Boxing Rings
4424
+ Sporting Goods > Athletics > Boxing & Martial Arts > Martial Arts Belts
4425
+ Sporting Goods > Athletics > Boxing & Martial Arts > Martial Arts Weapons
4426
+ Sporting Goods > Athletics > Broomball Equipment
4427
+ Sporting Goods > Athletics > Cheerleading
4428
+ Sporting Goods > Athletics > Cheerleading > Cheerleading Pom Poms
4429
+ Sporting Goods > Athletics > Coaching & Officiating
4430
+ Sporting Goods > Athletics > Coaching & Officiating > Captains Armbands
4431
+ Sporting Goods > Athletics > Coaching & Officiating > Field & Court Boundary Markers
4432
+ Sporting Goods > Athletics > Coaching & Officiating > Flip Coins & Discs
4433
+ Sporting Goods > Athletics > Coaching & Officiating > Linesman Flags
4434
+ Sporting Goods > Athletics > Coaching & Officiating > Penalty Cards & Flags
4435
+ Sporting Goods > Athletics > Coaching & Officiating > Pitch Counters
4436
+ Sporting Goods > Athletics > Coaching & Officiating > Referee Stands & Chairs
4437
+ Sporting Goods > Athletics > Coaching & Officiating > Referee Wallets
4438
+ Sporting Goods > Athletics > Coaching & Officiating > Scoreboards
4439
+ Sporting Goods > Athletics > Coaching & Officiating > Sport & Safety Whistles
4440
+ Sporting Goods > Athletics > Coaching & Officiating > Umpire Indicators
4441
+ Sporting Goods > Athletics > Cricket
4442
+ Sporting Goods > Athletics > Cricket > Cricket Balls
4443
+ Sporting Goods > Athletics > Cricket > Cricket Bat Accessories
4444
+ Sporting Goods > Athletics > Cricket > Cricket Bat Accessories > Cricket Bat Grips
4445
+ Sporting Goods > Athletics > Cricket > Cricket Bats
4446
+ Sporting Goods > Athletics > Cricket > Cricket Equipment Sets
4447
+ Sporting Goods > Athletics > Cricket > Cricket Protective Gear
4448
+ Sporting Goods > Athletics > Cricket > Cricket Protective Gear > Cricket Gloves
4449
+ Sporting Goods > Athletics > Cricket > Cricket Protective Gear > Cricket Helmets
4450
+ Sporting Goods > Athletics > Cricket > Cricket Protective Gear > Cricket Leg Guards
4451
+ Sporting Goods > Athletics > Cricket > Cricket Stumps
4452
+ Sporting Goods > Athletics > Dancing
4453
+ Sporting Goods > Athletics > Dancing > Ballet Barres
4454
+ Sporting Goods > Athletics > Fencing
4455
+ Sporting Goods > Athletics > Fencing > Fencing Protective Gear
4456
+ Sporting Goods > Athletics > Fencing > Fencing Protective Gear > Fencing Gloves & Cuffs
4457
+ Sporting Goods > Athletics > Fencing > Fencing Protective Gear > Fencing Jackets & Lamés
4458
+ Sporting Goods > Athletics > Fencing > Fencing Protective Gear > Fencing Masks
4459
+ Sporting Goods > Athletics > Fencing > Fencing Weapons
4460
+ Sporting Goods > Athletics > Field Hockey & Lacrosse
4461
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear
4462
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Gloves
4463
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Helmets
4464
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Masks & Goggles
4465
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Pads
4466
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey Balls
4467
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey Goals
4468
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey Sticks
4469
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Balls
4470
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Equipment Sets
4471
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Goals
4472
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts
4473
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts > Lacrosse Mesh & String
4474
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts > Lacrosse Stick Heads
4475
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts > Lacrosse Stick Shafts
4476
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Sticks
4477
+ Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Training Aids
4478
+ Sporting Goods > Athletics > Figure Skating & Hockey
4479
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Balls & Pucks
4480
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Goals
4481
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear
4482
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Elbow Pads
4483
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Gloves
4484
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Goalie Equipment Sets
4485
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Helmets
4486
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Pants
4487
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Shin Guards & Leg Pads
4488
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Shoulder Pads & Chest Protectors
4489
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Suspenders & Belts
4490
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Sledges
4491
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Care
4492
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Parts
4493
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Parts > Hockey Stick Blades
4494
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Parts > Hockey Stick Shafts
4495
+ Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Sticks
4496
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories
4497
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Figure Skate Boots
4498
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Ice Skate Blades
4499
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Ice Skate Sharpeners
4500
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Skate Blade Guards
4501
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Skate Lace Tighteners
4502
+ Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skates
4503
+ Sporting Goods > Athletics > Football
4504
+ Sporting Goods > Athletics > Football > Football Gloves
4505
+ Sporting Goods > Athletics > Football > Football Goal Posts
4506
+ Sporting Goods > Athletics > Football > Football Kicking Tees & Holders
4507
+ Sporting Goods > Athletics > Football > Football Protective Gear
4508
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Girdles
4509
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories
4510
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Chin Straps
4511
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Face Masks
4512
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Helmet Padding
4513
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Helmet Visors
4514
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmets
4515
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Neck Rolls
4516
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Rib Protection Shirts & Vests
4517
+ Sporting Goods > Athletics > Football > Football Protective Gear > Football Shoulder Pads
4518
+ Sporting Goods > Athletics > Football > Football Training Equipment
4519
+ Sporting Goods > Athletics > Football > Football Training Equipment > Football Dummies & Sleds
4520
+ Sporting Goods > Athletics > Football > Footballs
4521
+ Sporting Goods > Athletics > General Purpose Athletic Equipment
4522
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Altitude Training Masks
4523
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Athletic Cups
4524
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Carrying Bags & Carts
4525
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Pump Accessories
4526
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Pump Accessories > Ball Pump Needles
4527
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Pumps
4528
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Exercise & Gym Mat Storage Racks & Carts
4529
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Grip Spray & Chalk
4530
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Gym Mats
4531
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Practice Nets & Screens
4532
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Speed & Agility Ladders & Hurdles
4533
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Sports & Agility Cones
4534
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Sports Megaphones
4535
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Sports Mouthguards
4536
+ Sporting Goods > Athletics > General Purpose Athletic Equipment > Stadium Seats & Cushions
4537
+ Sporting Goods > Athletics > Gymnastics
4538
+ Sporting Goods > Athletics > Gymnastics > Gymnastics Bars & Balance Beams
4539
+ Sporting Goods > Athletics > Gymnastics > Gymnastics Protective Gear
4540
+ Sporting Goods > Athletics > Gymnastics > Gymnastics Protective Gear > Gymnastics Grips
4541
+ Sporting Goods > Athletics > Gymnastics > Gymnastics Rings
4542
+ Sporting Goods > Athletics > Gymnastics > Gymnastics Springboards
4543
+ Sporting Goods > Athletics > Gymnastics > Pommel Horses
4544
+ Sporting Goods > Athletics > Gymnastics > Vaulting Horses
4545
+ Sporting Goods > Athletics > Racquetball & Squash
4546
+ Sporting Goods > Athletics > Racquetball & Squash > Racquetball & Squash Balls
4547
+ Sporting Goods > Athletics > Racquetball & Squash > Racquetball & Squash Eyewear
4548
+ Sporting Goods > Athletics > Racquetball & Squash > Racquetball & Squash Gloves
4549
+ Sporting Goods > Athletics > Racquetball & Squash > Racquetball Racquets
4550
+ Sporting Goods > Athletics > Racquetball & Squash > Squash Racquets
4551
+ Sporting Goods > Athletics > Rounders
4552
+ Sporting Goods > Athletics > Rounders > Rounders Bats
4553
+ Sporting Goods > Athletics > Rounders > Rounders Gloves
4554
+ Sporting Goods > Athletics > Rugby
4555
+ Sporting Goods > Athletics > Rugby > Rugby Balls
4556
+ Sporting Goods > Athletics > Rugby > Rugby Gloves
4557
+ Sporting Goods > Athletics > Rugby > Rugby Posts
4558
+ Sporting Goods > Athletics > Rugby > Rugby Protective Gear
4559
+ Sporting Goods > Athletics > Rugby > Rugby Protective Gear > Rugby Headgear
4560
+ Sporting Goods > Athletics > Rugby > Rugby Training Aids
4561
+ Sporting Goods > Athletics > Soccer
4562
+ Sporting Goods > Athletics > Soccer > Soccer Balls
4563
+ Sporting Goods > Athletics > Soccer > Soccer Corner Flags
4564
+ Sporting Goods > Athletics > Soccer > Soccer Gloves
4565
+ Sporting Goods > Athletics > Soccer > Soccer Goal Accessories
4566
+ Sporting Goods > Athletics > Soccer > Soccer Goals
4567
+ Sporting Goods > Athletics > Soccer > Soccer Protective Gear
4568
+ Sporting Goods > Athletics > Soccer > Soccer Protective Gear > Soccer Shin Guards
4569
+ Sporting Goods > Athletics > Team Handball
4570
+ Sporting Goods > Athletics > Team Handball > Handballs
4571
+ Sporting Goods > Athletics > Tennis
4572
+ Sporting Goods > Athletics > Tennis > Tennis Ball Hoppers & Carts
4573
+ Sporting Goods > Athletics > Tennis > Tennis Ball Machines
4574
+ Sporting Goods > Athletics > Tennis > Tennis Ball Savers
4575
+ Sporting Goods > Athletics > Tennis > Tennis Balls
4576
+ Sporting Goods > Athletics > Tennis > Tennis Nets
4577
+ Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories
4578
+ Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Racquet Vibration Dampeners
4579
+ Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet Bags
4580
+ Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet Grips & Tape
4581
+ Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet Grommets
4582
+ Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet String
4583
+ Sporting Goods > Athletics > Tennis > Tennis Racquets
4584
+ Sporting Goods > Athletics > Track & Field
4585
+ Sporting Goods > Athletics > Track & Field > Discus
4586
+ Sporting Goods > Athletics > Track & Field > High Jump Crossbars
4587
+ Sporting Goods > Athletics > Track & Field > High Jump Pits
4588
+ Sporting Goods > Athletics > Track & Field > Javelins
4589
+ Sporting Goods > Athletics > Track & Field > Pole Vault Pits
4590
+ Sporting Goods > Athletics > Track & Field > Relay Batons
4591
+ Sporting Goods > Athletics > Track & Field > Shot Puts
4592
+ Sporting Goods > Athletics > Track & Field > Starter Pistols
4593
+ Sporting Goods > Athletics > Track & Field > Throwing Hammers
4594
+ Sporting Goods > Athletics > Track & Field > Track Hurdles
4595
+ Sporting Goods > Athletics > Track & Field > Track Starting Blocks
4596
+ Sporting Goods > Athletics > Track & Field > Vaulting Poles
4597
+ Sporting Goods > Athletics > Volleyball
4598
+ Sporting Goods > Athletics > Volleyball > Volleyball Nets
4599
+ Sporting Goods > Athletics > Volleyball > Volleyball Protective Gear
4600
+ Sporting Goods > Athletics > Volleyball > Volleyball Protective Gear > Volleyball Knee Pads
4601
+ Sporting Goods > Athletics > Volleyball > Volleyball Training Aids
4602
+ Sporting Goods > Athletics > Volleyball > Volleyballs
4603
+ Sporting Goods > Athletics > Wallyball Equipment
4604
+ Sporting Goods > Athletics > Water Polo
4605
+ Sporting Goods > Athletics > Water Polo > Water Polo Balls
4606
+ Sporting Goods > Athletics > Water Polo > Water Polo Caps
4607
+ Sporting Goods > Athletics > Water Polo > Water Polo Goals
4608
+ Sporting Goods > Athletics > Wrestling
4609
+ Sporting Goods > Athletics > Wrestling > Wrestling Protective Gear
4610
+ Sporting Goods > Athletics > Wrestling > Wrestling Protective Gear > Wrestling Headgear
4611
+ Sporting Goods > Athletics > Wrestling > Wrestling Protective Gear > Wrestling Knee Pads
4612
+ Sporting Goods > Exercise & Fitness
4613
+ Sporting Goods > Exercise & Fitness > Ab Wheels & Rollers
4614
+ Sporting Goods > Exercise & Fitness > Aerobic Steps
4615
+ Sporting Goods > Exercise & Fitness > Balance Trainers
4616
+ Sporting Goods > Exercise & Fitness > Cardio
4617
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories
4618
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Elliptical Trainer Accessories
4619
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Exercise Bike Accessories
4620
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Rowing Machine Accessories
4621
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Stair Climber & Stepper Accessories
4622
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Treadmill Accessories
4623
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines
4624
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Elliptical Trainers
4625
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Exercise Bikes
4626
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Rowing Machines
4627
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Stair Climbers & Steppers
4628
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Stair Climbers & Steppers > Stair Climbers
4629
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Stair Climbers & Steppers > Stair Steppers
4630
+ Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Treadmills
4631
+ Sporting Goods > Exercise & Fitness > Cardio > Jump Ropes
4632
+ Sporting Goods > Exercise & Fitness > Exercise Balls
4633
+ Sporting Goods > Exercise & Fitness > Exercise Bands
4634
+ Sporting Goods > Exercise & Fitness > Exercise Benches
4635
+ Sporting Goods > Exercise & Fitness > Exercise Equipment Mats
4636
+ Sporting Goods > Exercise & Fitness > Exercise Machine & Equipment Sets
4637
+ Sporting Goods > Exercise & Fitness > Exercise Wedges
4638
+ Sporting Goods > Exercise & Fitness > Foam Roller Accessories
4639
+ Sporting Goods > Exercise & Fitness > Foam Roller Accessories > Foam Roller Storage Bags
4640
+ Sporting Goods > Exercise & Fitness > Foam Rollers
4641
+ Sporting Goods > Exercise & Fitness > Hand Exercisers
4642
+ Sporting Goods > Exercise & Fitness > Inversion Tables & Systems
4643
+ Sporting Goods > Exercise & Fitness > Medicine Balls
4644
+ Sporting Goods > Exercise & Fitness > Power Towers
4645
+ Sporting Goods > Exercise & Fitness > Push Up & Pull Up Bars
4646
+ Sporting Goods > Exercise & Fitness > Reaction Balls
4647
+ Sporting Goods > Exercise & Fitness > Speed & Resistance Parachutes
4648
+ Sporting Goods > Exercise & Fitness > Sport Safety Lights & Reflectors
4649
+ Sporting Goods > Exercise & Fitness > Stopwatches
4650
+ Sporting Goods > Exercise & Fitness > Suspension Trainers
4651
+ Sporting Goods > Exercise & Fitness > Vibration Exercise Machines
4652
+ Sporting Goods > Exercise & Fitness > Weight Lifting
4653
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories
4654
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories > Free Weight Storage Racks
4655
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories > Weight Bar Collars
4656
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories > Weight Bars
4657
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weights
4658
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Belts
4659
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Gloves & Hand Supports
4660
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Machine & Exercise Bench Accessories
4661
+ Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Machines & Racks
4662
+ Sporting Goods > Exercise & Fitness > Weighted Clothing
4663
+ Sporting Goods > Exercise & Fitness > Yoga & Pilates
4664
+ Sporting Goods > Exercise & Fitness > Yoga & Pilates > Pilates Machines
4665
+ Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Blocks
4666
+ Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Mats
4667
+ Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Towels
4668
+ Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga Mat Bags & Straps
4669
+ Sporting Goods > Indoor Games
4670
+ Sporting Goods > Indoor Games > Air Hockey
4671
+ Sporting Goods > Indoor Games > Air Hockey > Air Hockey Equipment
4672
+ Sporting Goods > Indoor Games > Air Hockey > Air Hockey Table Parts
4673
+ Sporting Goods > Indoor Games > Air Hockey > Air Hockey Tables
4674
+ Sporting Goods > Indoor Games > Billiards
4675
+ Sporting Goods > Indoor Games > Billiards > Billiard Ball Racks
4676
+ Sporting Goods > Indoor Games > Billiards > Billiard Balls
4677
+ Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories
4678
+ Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Cases
4679
+ Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Chalk
4680
+ Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Racks
4681
+ Sporting Goods > Indoor Games > Billiards > Billiard Cues & Bridges
4682
+ Sporting Goods > Indoor Games > Billiards > Billiard Gloves
4683
+ Sporting Goods > Indoor Games > Billiards > Billiard Table Lights
4684
+ Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories
4685
+ Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Pockets
4686
+ Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Brushes
4687
+ Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Cloth
4688
+ Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Covers
4689
+ Sporting Goods > Indoor Games > Billiards > Billiard Tables
4690
+ Sporting Goods > Indoor Games > Bowling
4691
+ Sporting Goods > Indoor Games > Bowling > Bowling Ball Bags
4692
+ Sporting Goods > Indoor Games > Bowling > Bowling Balls
4693
+ Sporting Goods > Indoor Games > Bowling > Bowling Gloves
4694
+ Sporting Goods > Indoor Games > Bowling > Bowling Pins
4695
+ Sporting Goods > Indoor Games > Bowling > Bowling Wrist Supports
4696
+ Sporting Goods > Indoor Games > Foosball
4697
+ Sporting Goods > Indoor Games > Foosball > Foosball Balls
4698
+ Sporting Goods > Indoor Games > Foosball > Foosball Table Parts & Accessories
4699
+ Sporting Goods > Indoor Games > Foosball > Foosball Tables
4700
+ Sporting Goods > Indoor Games > Multi-Game Tables
4701
+ Sporting Goods > Indoor Games > Ping Pong
4702
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Balls
4703
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Nets & Posts
4704
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Paddle Accessories
4705
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Paddles & Sets
4706
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Robot Accessories
4707
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Robots
4708
+ Sporting Goods > Indoor Games > Ping Pong > Ping Pong Tables
4709
+ Sporting Goods > Indoor Games > Table Shuffleboard
4710
+ Sporting Goods > Indoor Games > Table Shuffleboard > Shuffleboard Tables
4711
+ Sporting Goods > Indoor Games > Table Shuffleboard > Table Shuffleboard Powder
4712
+ Sporting Goods > Indoor Games > Table Shuffleboard > Table Shuffleboard Pucks
4713
+ Sporting Goods > Indoor Games > Throwing Darts
4714
+ Sporting Goods > Indoor Games > Throwing Darts > Dart Backboards
4715
+ Sporting Goods > Indoor Games > Throwing Darts > Dart Parts
4716
+ Sporting Goods > Indoor Games > Throwing Darts > Dart Parts > Dart Flights
4717
+ Sporting Goods > Indoor Games > Throwing Darts > Dart Parts > Dart Shafts
4718
+ Sporting Goods > Indoor Games > Throwing Darts > Dart Parts > Dart Tips
4719
+ Sporting Goods > Indoor Games > Throwing Darts > Dartboards
4720
+ Sporting Goods > Indoor Games > Throwing Darts > Darts
4721
+ Sporting Goods > Outdoor Recreation
4722
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports
4723
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting
4724
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Boating Gloves
4725
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Canoe Accessories
4726
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Canoes
4727
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Kayak Accessories
4728
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Kayaks
4729
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Paddle Leashes
4730
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Paddles & Oars
4731
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Pedal Boats
4732
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Row Boats
4733
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Whitewater Rafts
4734
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel
4735
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Drysuits
4736
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Life Jacket Accessories
4737
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Life Jackets
4738
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Rash Guards & Swim Shirts
4739
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Water Sport Helmets
4740
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces
4741
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces > Wetsuit Bottoms
4742
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces > Wetsuit Hoods, Gloves & Boots
4743
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces > Wetsuit Tops
4744
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuits
4745
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling
4746
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Buoyancy Compensators
4747
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Dive Computers
4748
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving & Snorkeling Equipment Sets
4749
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving & Snorkeling Fins
4750
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving & Snorkeling Masks
4751
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving Belts
4752
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving Knives & Shears
4753
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving Regulators
4754
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Snorkels
4755
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing
4756
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kiteboard Cases
4757
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kiteboard Parts
4758
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kiteboards
4759
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kitesurfing & Windsurfing Harnesses
4760
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kitesurfing Kites
4761
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing
4762
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Bodyboards
4763
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Paddleboards
4764
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Skimboards
4765
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surf Leashes
4766
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboard Cases & Bags
4767
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboard Fins
4768
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboard Wax
4769
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboards
4770
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfing Gloves
4771
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfing Tail Pads
4772
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming
4773
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Child Swimming Aids
4774
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Hand Paddles
4775
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Kickboards
4776
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Pull Buoys
4777
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Belts
4778
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Caps
4779
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Gloves
4780
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Goggle & Mask Accessories
4781
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Goggles & Masks
4782
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Weights
4783
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Fins
4784
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Fins > Monofins
4785
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Fins > Training Fins
4786
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Machines
4787
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Nose Clips
4788
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports
4789
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Kneeboarding
4790
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Kneeboarding > Kneeboards
4791
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Towable Rafts & Tubes
4792
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Towed Water Sport Gloves
4793
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding
4794
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding > Kiteboard & Wakeboard Bindings
4795
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding > Wakeboard Parts
4796
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding > Wakeboards
4797
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing
4798
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Sit-Down Hydrofoils
4799
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Water Ski Bindings
4800
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Water Ski Cases & Bags
4801
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Water Skis
4802
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Sport Tow Cables
4803
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Watercraft Storage Racks
4804
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Watercraft Storage Racks > Boat Storage Racks
4805
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Watercraft Storage Racks > Water Sport Board Storage Racks
4806
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing
4807
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Board Parts
4808
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Board Fins
4809
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Board Masts
4810
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Boards
4811
+ Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Sails
4812
+ Sporting Goods > Outdoor Recreation > Camping & Hiking
4813
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture
4814
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture > Air Mattress & Sleeping Pad Accessories
4815
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture > Air Mattresses
4816
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture > Cots
4817
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Cookware & Dinnerware
4818
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Lights & Lanterns
4819
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Tools
4820
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Tools > Hunting & Survival Knives
4821
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Tools > Multifunction Tools & Knives
4822
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Chemical Hand Warmers
4823
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Compression Sacks
4824
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Hiking Pole Accessories
4825
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Hiking Poles
4826
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Mosquito Nets & Insect Screens
4827
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Navigational Compasses
4828
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Toilets & Showers
4829
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Toilets & Showers > Portable Showers & Privacy Enclosures
4830
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Toilets & Showers > Portable Toilets & Urination Devices
4831
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Water Filters & Purifiers
4832
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Sleeping Bag Liners
4833
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Sleeping Bags
4834
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Sleeping Pads
4835
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories
4836
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Inner Tents
4837
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Tent Footprints
4838
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Tent Poles & Stakes
4839
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Tent Vestibules
4840
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Tents
4841
+ Sporting Goods > Outdoor Recreation > Camping & Hiking > Windbreaks
4842
+ Sporting Goods > Outdoor Recreation > Climbing
4843
+ Sporting Goods > Outdoor Recreation > Climbing > Belay Devices
4844
+ Sporting Goods > Outdoor Recreation > Climbing > Carabiners
4845
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories
4846
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories > Climbing Gloves
4847
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories > Climbing Helmets
4848
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories > Crampons
4849
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Ascenders & Descenders
4850
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Chalk Bags
4851
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Crash Pads
4852
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Harnesses
4853
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Protection Devices
4854
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Rope
4855
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Rope Bags
4856
+ Sporting Goods > Outdoor Recreation > Climbing > Climbing Webbing
4857
+ Sporting Goods > Outdoor Recreation > Climbing > Ice Climbing Tools
4858
+ Sporting Goods > Outdoor Recreation > Climbing > Ice Screws
4859
+ Sporting Goods > Outdoor Recreation > Climbing > Indoor Climbing Holds
4860
+ Sporting Goods > Outdoor Recreation > Climbing > Quickdraws
4861
+ Sporting Goods > Outdoor Recreation > Cycling
4862
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories
4863
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Bags & Panniers
4864
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Baskets
4865
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Bells & Horns
4866
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Cages
4867
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Child Seat Accessories
4868
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Child Seats
4869
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Computer Accessories
4870
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Computers
4871
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Covers
4872
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Fenders
4873
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Front & Rear Racks
4874
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Handlebar Grips & Decor
4875
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Locks
4876
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Mirrors
4877
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Pumps
4878
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Saddle Pads & Seat Covers
4879
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Shock Pumps
4880
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Spoke Beads
4881
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Stands & Storage
4882
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tire Repair Supplies & Kits
4883
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Toe Straps & Clips
4884
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tools
4885
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Trailers
4886
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Trainers
4887
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Training Wheels
4888
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Transport Bags & Cases
4889
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Water Sport Board Racks
4890
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Electric Bicycle Conversion Kits
4891
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts
4892
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts
4893
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Calipers
4894
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Levers
4895
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Rotors
4896
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Sets
4897
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Cable Housings
4898
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Cables
4899
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts
4900
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Bottom Brackets
4901
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Cassettes & Freewheels
4902
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Chainrings
4903
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Chains
4904
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Cranks
4905
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Derailleurs
4906
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Pedals
4907
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Shifters
4908
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Forks
4909
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Frames
4910
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Groupsets
4911
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Handlebar Extensions
4912
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Handlebars
4913
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts
4914
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts > Bicycle Headset Bearings
4915
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts > Bicycle Headset Spacers
4916
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headsets
4917
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Kickstands
4918
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Saddles
4919
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Seatpost Clamps
4920
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Seatposts
4921
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Small Parts
4922
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Stems
4923
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tire Valve Adapters
4924
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tire Valve Caps
4925
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tire Valves
4926
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tires
4927
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tubes
4928
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts
4929
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Foot Pegs
4930
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Hub Parts
4931
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Hubs
4932
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Rim Strips
4933
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Spokes
4934
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Axles & Skewers
4935
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Nipples
4936
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Rims
4937
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheels
4938
+ Sporting Goods > Outdoor Recreation > Cycling > Bicycles
4939
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories
4940
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories
4941
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories > Bicycle Cleat Bolts
4942
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories > Bicycle Cleat Covers
4943
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories > Bicycle Cleat Shims & Wedges
4944
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleats
4945
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Gloves
4946
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Helmet Parts & Accessories
4947
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Helmets
4948
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Protective Pads
4949
+ Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Shoe Covers
4950
+ Sporting Goods > Outdoor Recreation > Cycling > Tricycle Accessories
4951
+ Sporting Goods > Outdoor Recreation > Cycling > Tricycles
4952
+ Sporting Goods > Outdoor Recreation > Cycling > Unicycle Accessories
4953
+ Sporting Goods > Outdoor Recreation > Cycling > Unicycles
4954
+ Sporting Goods > Outdoor Recreation > Equestrian
4955
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care
4956
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Blankets & Sheets
4957
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Boots & Leg Wraps
4958
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Feed
4959
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Fly Masks
4960
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Grooming
4961
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Grooming > Horse Clippers & Trimmers
4962
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Grooming > Horse Grooming Combs, Brushes & Mitts
4963
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Treats
4964
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Vitamins & Supplements
4965
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Wormers
4966
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack
4967
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Bridle Bits
4968
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Bridles
4969
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Cinches
4970
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Halters
4971
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Harnesses
4972
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Leads
4973
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Reins
4974
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Saddles
4975
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Stirrups
4976
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories
4977
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Horse Tack Boxes
4978
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories
4979
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Bags & Panniers
4980
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Covers & Cases
4981
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Pads & Blankets
4982
+ Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Racks
4983
+ Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories
4984
+ Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Equestrian Gloves
4985
+ Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Equestrian Helmets
4986
+ Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Riding Crops & Whips
4987
+ Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Riding Pants
4988
+ Sporting Goods > Outdoor Recreation > Fishing
4989
+ Sporting Goods > Outdoor Recreation > Fishing > Bite Alarms
4990
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing & Hunting Waders
4991
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Bait & Chum Containers
4992
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Gaffs
4993
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Hook Removal Tools
4994
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Lines & Leaders
4995
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Nets
4996
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories
4997
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories > Fishing Reel Bags & Cases
4998
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories > Fishing Reel Lubricants
4999
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories > Fishing Reel Replacement Spools
5000
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Reels
5001
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Rod Accessories
5002
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Rod Accessories > Fishing Rod Bags & Cases
5003
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Rod Accessories > Fishing Rod Holders & Storage Racks
5004
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Rods
5005
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Spears
5006
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle
5007
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Baits & Lures
5008
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Floats
5009
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Hooks
5010
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Sinkers
5011
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Snaps & Swivels
5012
+ Sporting Goods > Outdoor Recreation > Fishing > Fishing Traps
5013
+ Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials
5014
+ Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials > Fishing Beads
5015
+ Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials > Fishing Yarn
5016
+ Sporting Goods > Outdoor Recreation > Fishing > Live Bait
5017
+ Sporting Goods > Outdoor Recreation > Fishing > Tackle Bags & Boxes
5018
+ Sporting Goods > Outdoor Recreation > Golf
5019
+ Sporting Goods > Outdoor Recreation > Golf > Divot Tools
5020
+ Sporting Goods > Outdoor Recreation > Golf > Golf Accessory Sets
5021
+ Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories
5022
+ Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories > Golf Bag Carts
5023
+ Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories > Golf Bag Covers & Cases
5024
+ Sporting Goods > Outdoor Recreation > Golf > Golf Bags
5025
+ Sporting Goods > Outdoor Recreation > Golf > Golf Ball Markers
5026
+ Sporting Goods > Outdoor Recreation > Golf > Golf Balls
5027
+ Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories
5028
+ Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Grips
5029
+ Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Headcovers
5030
+ Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Shafts
5031
+ Sporting Goods > Outdoor Recreation > Golf > Golf Clubs
5032
+ Sporting Goods > Outdoor Recreation > Golf > Golf Flags
5033
+ Sporting Goods > Outdoor Recreation > Golf > Golf Gloves
5034
+ Sporting Goods > Outdoor Recreation > Golf > Golf Tees
5035
+ Sporting Goods > Outdoor Recreation > Golf > Golf Towels
5036
+ Sporting Goods > Outdoor Recreation > Golf > Golf Training Aids
5037
+ Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving
5038
+ Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving > Air Suits
5039
+ Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving > Hang Gliders
5040
+ Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving > Parachutes
5041
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting
5042
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery
5043
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Archery Armguards
5044
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Archery Gloves & Releases
5045
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Archery Targets
5046
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories
5047
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories > Arrow Fletchings
5048
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories > Arrow Nocks
5049
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories > Broadheads & Field Points
5050
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrows & Bolts
5051
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bow & Crossbow Accessories
5052
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows
5053
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows > Compound Bows
5054
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows > Crossbows
5055
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows > Recurve & Longbows
5056
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Quivers
5057
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Clay Pigeon Shooting
5058
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Clay Pigeon Shooting > Clay Pigeon Throwers
5059
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Clay Pigeon Shooting > Clay Pigeons
5060
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting
5061
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting & Shooting Protective Gear
5062
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting & Shooting Protective Gear > Hunting & Shooting Gloves
5063
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting & Shooting Protective Gear > Hunting & Shooting Jackets
5064
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Animal Traps
5065
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Hearing Enhancers
5066
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Hunting Blinds & Screens
5067
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Hunting Dog Equipment
5068
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Tree Stands
5069
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wild Game Feeders
5070
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants
5071
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Cover Scents & Scent Attractants
5072
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Hunting & Wildlife Calls
5073
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Hunting & Wildlife Decoys
5074
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Wildlife Bait, Feed & Minerals
5075
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft
5076
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft
5077
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Gun Parts & Accessories
5078
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Gun Parts & Accessories > Airsoft Gun Batteries
5079
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Guns
5080
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Pellets
5081
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball
5082
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear
5083
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Gloves
5084
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Goggles & Masks
5085
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Pads
5086
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Vests
5087
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Grenade Launchers
5088
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Grenades
5089
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories
5090
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Air Tanks
5091
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Gun Barrels
5092
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Gun Drop Forwards
5093
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Hoppers
5094
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Guns
5095
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Harnesses & Packs
5096
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintballs
5097
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories
5098
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories > Shooting Rests
5099
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories > Shooting Sticks & Bipods
5100
+ Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories > Shooting Targets
5101
+ Sporting Goods > Outdoor Recreation > Hydration System Accessories
5102
+ Sporting Goods > Outdoor Recreation > Hydration Systems
5103
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating
5104
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline & Roller Skating Protective Gear
5105
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline & Roller Skating Protective Gear > Roller Skating Pads
5106
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline Skate Parts
5107
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline Skates
5108
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Roller Skate Parts
5109
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Roller Skates
5110
+ Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Roller Skis
5111
+ Sporting Goods > Outdoor Recreation > Kite Buggying
5112
+ Sporting Goods > Outdoor Recreation > Kite Buggying > Kite Buggies
5113
+ Sporting Goods > Outdoor Recreation > Kite Buggying > Kite Buggy Accessories
5114
+ Sporting Goods > Outdoor Recreation > Outdoor Games
5115
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton
5116
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton > Badminton Nets
5117
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton > Badminton Racquets & Sets
5118
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton > Shuttlecocks
5119
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Deck Shuffleboard
5120
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Deck Shuffleboard > Deck Shuffleboard Cues
5121
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Deck Shuffleboard > Deck Shuffleboard Pucks
5122
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Disc Golf
5123
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Disc Golf > Disc Golf Bags
5124
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Disc Golf > Disc Golf Baskets
5125
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Lawn Games
5126
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Paddle Ball Sets
5127
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Pickleball
5128
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Pickleball > Pickleball Paddles
5129
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Pickleball > Pickleballs
5130
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Platform & Paddle Tennis
5131
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Platform & Paddle Tennis > Platform & Paddle Tennis Paddles
5132
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Platform & Paddle Tennis > Platform Tennis Balls
5133
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball
5134
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball > Tetherball Poles
5135
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball > Tetherball Sets
5136
+ Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball > Tetherballs
5137
+ Sporting Goods > Outdoor Recreation > Riding Scooters
5138
+ Sporting Goods > Outdoor Recreation > Skateboarding
5139
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skate Rails
5140
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skate Ramps
5141
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts
5142
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Decks
5143
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Small Parts
5144
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Trucks
5145
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Wheels
5146
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear
5147
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear > Skate Helmets
5148
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear > Skateboarding Gloves
5149
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear > Skateboarding Pads
5150
+ Sporting Goods > Outdoor Recreation > Skateboarding > Skateboards
5151
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities
5152
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Avalanche Safety
5153
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Avalanche Safety > Avalanche Probes
5154
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Avalanche Safety > Avalanche Safety Airbags
5155
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding
5156
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Bags
5157
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Goggle Accessories
5158
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Goggle Accessories > Ski & Snowboard Goggle Lenses
5159
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Goggles
5160
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Helmets
5161
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Leashes
5162
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Storage Racks
5163
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Tuning Tools
5164
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Wax
5165
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Binding Parts
5166
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Bindings
5167
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Boots
5168
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Poles
5169
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Skis
5170
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Skis > Cross-Country Skis
5171
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Skis > Downhill Skis
5172
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboard Binding Parts
5173
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboard Bindings
5174
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboard Boots
5175
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboards
5176
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Sleds
5177
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Snowshoeing
5178
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Snowshoeing > Snowshoe Bindings
5179
+ Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Snowshoeing > Snowshoes
5180
+ Toys & Games
5181
+ Toys & Games > Game Timers
5182
+ Toys & Games > Games
5183
+ Toys & Games > Games > Battle Top Accessories
5184
+ Toys & Games > Games > Battle Tops
5185
+ Toys & Games > Games > Bingo Sets
5186
+ Toys & Games > Games > Blackjack & Craps Sets
5187
+ Toys & Games > Games > Board Games
5188
+ Toys & Games > Games > Card Game Accessories
5189
+ Toys & Games > Games > Card Games
5190
+ Toys & Games > Games > Dexterity Games
5191
+ Toys & Games > Games > Dice Sets & Games
5192
+ Toys & Games > Games > Poker Chip Accessories
5193
+ Toys & Games > Games > Poker Chip Accessories > Poker Chip Carriers & Trays
5194
+ Toys & Games > Games > Poker Chips & Sets
5195
+ Toys & Games > Games > Portable Electronic Games
5196
+ Toys & Games > Games > Roulette Wheels & Sets
5197
+ Toys & Games > Games > Slot Machines
5198
+ Toys & Games > Games > Tile Games
5199
+ Toys & Games > Outdoor Play Equipment
5200
+ Toys & Games > Outdoor Play Equipment > Inflatable Bouncer Accessories
5201
+ Toys & Games > Outdoor Play Equipment > Inflatable Bouncers
5202
+ Toys & Games > Outdoor Play Equipment > Play Swings
5203
+ Toys & Games > Outdoor Play Equipment > Play Tents & Tunnels
5204
+ Toys & Games > Outdoor Play Equipment > Playhouses
5205
+ Toys & Games > Outdoor Play Equipment > Pogo Sticks
5206
+ Toys & Games > Outdoor Play Equipment > Sandboxes
5207
+ Toys & Games > Outdoor Play Equipment > See Saws
5208
+ Toys & Games > Outdoor Play Equipment > Slides
5209
+ Toys & Games > Outdoor Play Equipment > Stilts
5210
+ Toys & Games > Outdoor Play Equipment > Swing Set & Playset Accessories
5211
+ Toys & Games > Outdoor Play Equipment > Swing Sets & Playsets
5212
+ Toys & Games > Outdoor Play Equipment > Trampoline Accessories
5213
+ Toys & Games > Outdoor Play Equipment > Trampolines
5214
+ Toys & Games > Outdoor Play Equipment > Water Play Equipment
5215
+ Toys & Games > Outdoor Play Equipment > Water Play Equipment > Play Sprinkers
5216
+ Toys & Games > Outdoor Play Equipment > Water Play Equipment > Water Parks & Slides
5217
+ Toys & Games > Outdoor Play Equipment > Water Play Equipment > Water Tables
5218
+ Toys & Games > Puzzles
5219
+ Toys & Games > Puzzles > Jigsaw Puzzle Accessories
5220
+ Toys & Games > Puzzles > Jigsaw Puzzles
5221
+ Toys & Games > Puzzles > Mechanical Puzzles
5222
+ Toys & Games > Puzzles > Wooden & Pegged Puzzles
5223
+ Toys & Games > Toys
5224
+ Toys & Games > Toys > Activity Toys
5225
+ Toys & Games > Toys > Activity Toys > Ball & Cup Games
5226
+ Toys & Games > Toys > Activity Toys > Bouncy Balls
5227
+ Toys & Games > Toys > Activity Toys > Bubble Blowing Solution
5228
+ Toys & Games > Toys > Activity Toys > Bubble Blowing Toys
5229
+ Toys & Games > Toys > Activity Toys > Coiled Spring Toys
5230
+ Toys & Games > Toys > Activity Toys > Marbles
5231
+ Toys & Games > Toys > Activity Toys > Paddle Ball Toys
5232
+ Toys & Games > Toys > Activity Toys > Ribbon & Streamer Toys
5233
+ Toys & Games > Toys > Activity Toys > Spinning Tops
5234
+ Toys & Games > Toys > Activity Toys > Toy Jacks
5235
+ Toys & Games > Toys > Activity Toys > Yo-Yo Parts & Accessories
5236
+ Toys & Games > Toys > Activity Toys > Yo-Yos
5237
+ Toys & Games > Toys > Art & Drawing Toys
5238
+ Toys & Games > Toys > Art & Drawing Toys > Play Dough & Putty
5239
+ Toys & Games > Toys > Art & Drawing Toys > Toy Drawing Tablets
5240
+ Toys & Games > Toys > Ball Pit Accessories
5241
+ Toys & Games > Toys > Ball Pit Accessories > Ball Pit Balls
5242
+ Toys & Games > Toys > Ball Pits
5243
+ Toys & Games > Toys > Bath Toys
5244
+ Toys & Games > Toys > Beach & Sand Toys
5245
+ Toys & Games > Toys > Building Toys
5246
+ Toys & Games > Toys > Building Toys > Construction Set Toys
5247
+ Toys & Games > Toys > Building Toys > Foam Blocks
5248
+ Toys & Games > Toys > Building Toys > Interlocking Blocks
5249
+ Toys & Games > Toys > Building Toys > Marble Track Sets
5250
+ Toys & Games > Toys > Building Toys > Wooden Blocks
5251
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures
5252
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures
5253
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Bobblehead Figures
5254
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Doll & Action Figure Accessories
5255
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dollhouse Accessories
5256
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dollhouses
5257
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dolls
5258
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Paper & Magnetic Dolls
5259
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppet & Puppet Theater Accessories
5260
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppet Theaters
5261
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppets & Marionettes
5262
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Stuffed Animals
5263
+ Toys & Games > Toys > Dolls, Playsets & Toy Figures > Toy Playsets
5264
+ Toys & Games > Toys > Educational Toys
5265
+ Toys & Games > Toys > Educational Toys > Ant Farms
5266
+ Toys & Games > Toys > Educational Toys > Astronomy Toys & Models
5267
+ Toys & Games > Toys > Educational Toys > Bug Collecting Kits
5268
+ Toys & Games > Toys > Educational Toys > Educational Flash Cards
5269
+ Toys & Games > Toys > Educational Toys > Reading Toys
5270
+ Toys & Games > Toys > Educational Toys > Science & Exploration Sets
5271
+ Toys & Games > Toys > Educational Toys > Toy Abacuses
5272
+ Toys & Games > Toys > Executive Toys
5273
+ Toys & Games > Toys > Executive Toys > Magnet Toys
5274
+ Toys & Games > Toys > Flying Toy Accessories
5275
+ Toys & Games > Toys > Flying Toy Accessories > Kite Accessories
5276
+ Toys & Games > Toys > Flying Toy Accessories > Kite Accessories > Kite Line Reels & Winders
5277
+ Toys & Games > Toys > Flying Toys
5278
+ Toys & Games > Toys > Flying Toys > Air & Water Rockets
5279
+ Toys & Games > Toys > Flying Toys > Kites
5280
+ Toys & Games > Toys > Flying Toys > Toy Gliders
5281
+ Toys & Games > Toys > Flying Toys > Toy Parachutes
5282
+ Toys & Games > Toys > Musical Toys
5283
+ Toys & Games > Toys > Musical Toys > Toy Instruments
5284
+ Toys & Games > Toys > Play Vehicle Accessories
5285
+ Toys & Games > Toys > Play Vehicle Accessories > Toy Race Car & Track Accessories
5286
+ Toys & Games > Toys > Play Vehicle Accessories > Toy Train Accessories
5287
+ Toys & Games > Toys > Play Vehicles
5288
+ Toys & Games > Toys > Play Vehicles > Toy Airplanes
5289
+ Toys & Games > Toys > Play Vehicles > Toy Boats
5290
+ Toys & Games > Toys > Play Vehicles > Toy Cars
5291
+ Toys & Games > Toys > Play Vehicles > Toy Helicopters
5292
+ Toys & Games > Toys > Play Vehicles > Toy Motorcycles
5293
+ Toys & Games > Toys > Play Vehicles > Toy Race Car & Track Sets
5294
+ Toys & Games > Toys > Play Vehicles > Toy Spaceships
5295
+ Toys & Games > Toys > Play Vehicles > Toy Trains & Train Sets
5296
+ Toys & Games > Toys > Play Vehicles > Toy Trucks & Construction Vehicles
5297
+ Toys & Games > Toys > Pretend Play
5298
+ Toys & Games > Toys > Pretend Play > Play Money & Banking
5299
+ Toys & Games > Toys > Pretend Play > Pretend Electronics
5300
+ Toys & Games > Toys > Pretend Play > Pretend Housekeeping
5301
+ Toys & Games > Toys > Pretend Play > Pretend Lawn & Garden
5302
+ Toys & Games > Toys > Pretend Play > Pretend Professions & Role Playing
5303
+ Toys & Games > Toys > Pretend Play > Pretend Shopping & Grocery
5304
+ Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food
5305
+ Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food > Play Food
5306
+ Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food > Toy Cookware
5307
+ Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food > Toy Kitchens
5308
+ Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food > Toy Tableware
5309
+ Toys & Games > Toys > Pretend Play > Toy Tools
5310
+ Toys & Games > Toys > Remote Control Toy Accessories
5311
+ Toys & Games > Toys > Remote Control Toys
5312
+ Toys & Games > Toys > Remote Control Toys > Remote Control Airships & Blimps
5313
+ Toys & Games > Toys > Remote Control Toys > Remote Control Boats & Watercraft
5314
+ Toys & Games > Toys > Remote Control Toys > Remote Control Cars & Trucks
5315
+ Toys & Games > Toys > Remote Control Toys > Remote Control Helicopters
5316
+ Toys & Games > Toys > Remote Control Toys > Remote Control Motorcycles
5317
+ Toys & Games > Toys > Remote Control Toys > Remote Control Planes
5318
+ Toys & Games > Toys > Remote Control Toys > Remote Control Robots
5319
+ Toys & Games > Toys > Remote Control Toys > Remote Control Tanks
5320
+ Toys & Games > Toys > Riding Toy Accessories
5321
+ Toys & Games > Toys > Riding Toys
5322
+ Toys & Games > Toys > Riding Toys > Electric Riding Vehicles
5323
+ Toys & Games > Toys > Riding Toys > Hobby Horses
5324
+ Toys & Games > Toys > Riding Toys > Push & Pedal Riding Vehicles
5325
+ Toys & Games > Toys > Riding Toys > Rocking & Spring Riding Toys
5326
+ Toys & Games > Toys > Riding Toys > Wagons
5327
+ Toys & Games > Toys > Robotic Toys
5328
+ Toys & Games > Toys > Sports Toy Accessories
5329
+ Toys & Games > Toys > Sports Toy Accessories > Fitness Toy Accessories
5330
+ Toys & Games > Toys > Sports Toy Accessories > Fitness Toy Accessories > Hula Hoop Accessories
5331
+ Toys & Games > Toys > Sports Toys
5332
+ Toys & Games > Toys > Sports Toys > Baseball Toys
5333
+ Toys & Games > Toys > Sports Toys > Basketball Toys
5334
+ Toys & Games > Toys > Sports Toys > Boomerangs
5335
+ Toys & Games > Toys > Sports Toys > Bowling Toys
5336
+ Toys & Games > Toys > Sports Toys > Fingerboards & Fingerboard Sets
5337
+ Toys & Games > Toys > Sports Toys > Fishing Toys
5338
+ Toys & Games > Toys > Sports Toys > Fitness Toys
5339
+ Toys & Games > Toys > Sports Toys > Fitness Toys > Hula Hoops
5340
+ Toys & Games > Toys > Sports Toys > Flying Discs
5341
+ Toys & Games > Toys > Sports Toys > Footbags
5342
+ Toys & Games > Toys > Sports Toys > Golf Toys
5343
+ Toys & Games > Toys > Sports Toys > Hockey Toys
5344
+ Toys & Games > Toys > Sports Toys > Playground Balls
5345
+ Toys & Games > Toys > Sports Toys > Racquet Sport Toys
5346
+ Toys & Games > Toys > Sports Toys > Toy Footballs
5347
+ Toys & Games > Toys > Toy Gift Baskets
5348
+ Toys & Games > Toys > Toy Weapon & Gadget Accessories
5349
+ Toys & Games > Toys > Toy Weapons & Gadgets
5350
+ Toys & Games > Toys > Visual Toys
5351
+ Toys & Games > Toys > Visual Toys > Kaleidoscopes
5352
+ Toys & Games > Toys > Visual Toys > Prisms
5353
+ Toys & Games > Toys > Wind-Up Toys
5354
+ Vehicles & Parts
5355
+ Vehicles & Parts > Vehicle Parts & Accessories
5356
+ Vehicles & Parts > Vehicle Parts & Accessories > Aircraft Parts & Accessories
5357
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics
5358
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle A/V Players & In-Dash Systems
5359
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Amplifiers
5360
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Cassette Adapters
5361
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Cassette Players
5362
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Equalizers & Crossovers
5363
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Parking Cameras
5364
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Speakerphones
5365
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Speakers
5366
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Subwoofers
5367
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Video Monitor Mounts
5368
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts
5369
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Braking
5370
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Carpet & Upholstery
5371
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control
5372
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Controls
5373
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Oil Circulation
5374
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts
5375
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engines
5376
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust
5377
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Frame & Body Parts
5378
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems
5379
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Interior Fittings
5380
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting
5381
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Mirrors
5382
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Power & Electrical Systems
5383
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Seating
5384
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Sensors & Gauges
5385
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Suspension Parts
5386
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Towing
5387
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Transmission & Drivetrain Parts
5388
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems
5389
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels
5390
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Automotive Rims & Wheels
5391
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Motorcycle Rims & Wheels
5392
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Off-Road and All-Terrain Vehicle Rims & Wheels
5393
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tire Accessories
5394
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires
5395
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Automotive Tires
5396
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Motorcycle Tires
5397
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Off-Road and All-Terrain Vehicle Tires
5398
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Wheel Parts
5399
+ Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Window Parts & Accessories
5400
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor
5401
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Portable Fuel Cans
5402
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning
5403
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Car Wash Brushes
5404
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Car Wash Solutions
5405
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Carpet & Upholstery Cleaners
5406
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Fuel Injection Cleaning Kits
5407
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Glass Cleaners
5408
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Waxes, Polishes & Protectants
5409
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers
5410
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Golf Cart Enclosures
5411
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Motor Vehicle Windshield Covers
5412
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Tonneau Covers
5413
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Hardtops
5414
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Soft Tops
5415
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers
5416
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Automotive Storage Covers
5417
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Golf Cart Storage Covers
5418
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Motorcycle Storage Covers
5419
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Recreational Vehicle Storage Covers
5420
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Watercraft Storage Covers
5421
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor
5422
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Bumper Stickers
5423
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Air Fresheners
5424
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Antenna Balls
5425
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Dashboard Accessories
5426
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Decals
5427
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Decor Accessory Sets
5428
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Display Flags
5429
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Emblems & Hood Ornaments
5430
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Hitch Covers
5431
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plate Covers
5432
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plate Frames
5433
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plate Mounts & Holders
5434
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plates
5435
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Magnets
5436
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Rear View Mirror Ornaments
5437
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Shift Boots
5438
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Shift Knobs
5439
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Steering Wheel Covers
5440
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Wraps
5441
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids
5442
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Antifreeze
5443
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Brake Fluid
5444
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Cooling System Additives
5445
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Engine Degreasers
5446
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Fuel System Cleaners
5447
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Greases
5448
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Hydraulic Clutch Fluid
5449
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Motor Oil
5450
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Performance Additives
5451
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Power Steering Fluid
5452
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Transmission Fluid
5453
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Windshield Fluid
5454
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Paint
5455
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Paint > Motor Vehicle Body Paint
5456
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Paint > Motor Vehicle Brake Caliper Paint
5457
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools
5458
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Motor Vehicle Brake Service Kits
5459
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Motor Vehicle Clutch Alignment & Removal Tools
5460
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Battery Chargers
5461
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Battery Testers
5462
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Body Filler
5463
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Diagnostic Scanners
5464
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Jump Starters
5465
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Jumper Cables
5466
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Tire Repair & Tire Changing Tools
5467
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Windshield Repair Kits
5468
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security
5469
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear
5470
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Chest & Back Protectors
5471
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Elbow & Wrist Guards
5472
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Gloves
5473
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Goggles
5474
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Hand Guards
5475
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Helmet Parts & Accessories
5476
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Helmets
5477
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Kidney Belts
5478
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Knee & Shin Guards
5479
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Neck Braces
5480
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Off-Road & All-Terrain Vehicle Protective Gear
5481
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Off-Road & All-Terrain Vehicle Protective Gear > ATV & UTV Bar Pads
5482
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks
5483
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Automotive Alarm Accessories
5484
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Automotive Alarm Systems
5485
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Motorcycle Alarms & Locks
5486
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts
5487
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts > Vehicle Door Lock Actuators
5488
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts > Vehicle Door Lock Knobs
5489
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts > Vehicle Door Locks & Locking Systems
5490
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Hitch Locks
5491
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Immobilizers
5492
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Remote Keyless Systems
5493
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Steering Wheel Locks
5494
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Wheel Clamps
5495
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment
5496
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Car Window Nets
5497
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Emergency Road Flares
5498
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Motor Vehicle Airbag Parts
5499
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Motor Vehicle Roll Cages & Bars
5500
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belt Buckles
5501
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belt Covers
5502
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belt Straps
5503
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belts
5504
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Warning Whips
5505
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Wheel Chocks
5506
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo
5507
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Cargo Nets
5508
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Rack Accessories
5509
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Rack Accessories > Vehicle Bicycle Rack Accessories
5510
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Rack Accessories > Vehicle Ski & Snowboard Rack Accessories
5511
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks
5512
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Base Rack Systems
5513
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Bicycle Racks
5514
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Boat Racks
5515
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Cargo Racks
5516
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Fishing Rod Racks
5517
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Gun Racks
5518
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Motorcycle & Scooter Racks
5519
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Ski & Snowboard Racks
5520
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Water Sport Board Racks
5521
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Loading Ramps
5522
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers
5523
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Boat Trailers
5524
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Horse & Livestock Trailers
5525
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Travel Trailers
5526
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Utility & Cargo Trailers
5527
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motorcycle Bags & Panniers
5528
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Truck Bed Storage Boxes & Organizers
5529
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Vehicle Headrest Hangers & Hooks
5530
+ Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Vehicle Organizers
5531
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories
5532
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring
5533
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Chains
5534
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Lines & Ropes
5535
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Windlasses
5536
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchors
5537
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Boat Hooks
5538
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Boat Ladders
5539
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Dock Cleats
5540
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Dock Steps
5541
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Sailboat Parts
5542
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care
5543
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Cleaners
5544
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Polishes
5545
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts
5546
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Alternators
5547
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Carburetors & Parts
5548
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Engine Controls
5549
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Ignition Parts
5550
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Impellers
5551
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Motor Locks
5552
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Motor Mounts
5553
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Pistons & Parts
5554
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Propellers
5555
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engines & Motors
5556
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts
5557
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts > Watercraft Manifolds
5558
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts > Watercraft Mufflers & Parts
5559
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems
5560
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Lines & Parts
5561
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Meters
5562
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Pumps & Parts
5563
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Tanks & Parts
5564
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Lighting
5565
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts
5566
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts > Watercraft Steering Cables
5567
+ Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts > Watercraft Steering Wheels
5568
+ Vehicles & Parts > Vehicles
5569
+ Vehicles & Parts > Vehicles > Aircraft
5570
+ Vehicles & Parts > Vehicles > Motor Vehicles
5571
+ Vehicles & Parts > Vehicles > Motor Vehicles > Cars, Trucks & Vans
5572
+ Vehicles & Parts > Vehicles > Motor Vehicles > Golf Carts
5573
+ Vehicles & Parts > Vehicles > Motor Vehicles > Motorcycles & Scooters
5574
+ Vehicles & Parts > Vehicles > Motor Vehicles > Off-Road and All-Terrain Vehicles
5575
+ Vehicles & Parts > Vehicles > Motor Vehicles > Off-Road and All-Terrain Vehicles > ATVs & UTVs
5576
+ Vehicles & Parts > Vehicles > Motor Vehicles > Off-Road and All-Terrain Vehicles > Go Karts & Dune Buggies
5577
+ Vehicles & Parts > Vehicles > Motor Vehicles > Recreational Vehicles
5578
+ Vehicles & Parts > Vehicles > Motor Vehicles > Snowmobiles
5579
+ Vehicles & Parts > Vehicles > Watercraft
5580
+ Vehicles & Parts > Vehicles > Watercraft > Motor Boats
5581
+ Vehicles & Parts > Vehicles > Watercraft > Personal Watercraft
5582
+ Vehicles & Parts > Vehicles > Watercraft > Sailboats
5583
+ Vehicles & Parts > Vehicles > Watercraft > Yachts
includes/application/google/tvc_google-source.js ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var _googleClothingAndAccessories = false;
2
+ var _googleNeedsProductCat = false;
3
+ var _googleRequiresBrand = true;
4
+
5
+ // ALERT! This function is equivalent for the woocommerce_to_feed_fields() function in class-data.php
6
+ function woocommerceToGoogleFields() {
7
+ return {
8
+ 'id': 'ID',
9
+ 'title': 'post_title',
10
+ 'google_product_category': 'category',
11
+ 'description': 'post_content',
12
+ 'link': 'permalink',
13
+ 'image_link': 'attachment_url',
14
+ 'additional_image_link': '_wp_attachement_metadata',
15
+ 'price': '_regular_price',
16
+ 'sale_price': '_sale_price',
17
+ 'sale_price_effective_date': '_sale_price_dates_from',
18
+ 'item_group_id': 'item_group_id',
19
+ 'mpn': 'ID',
20
+ 'tax': 'Use the settings in the Merchant Center',
21
+ 'shipping': 'Use the settings in the Merchant Center',
22
+ };
23
+ }
24
+
25
+ // ALERT! This function is equivalent for the set_google_output_attribute_levels() function in class-data.php
26
+ function setGoogleOutputAttributeLevels( feedHolder, targetCountry ) {
27
+ for ( var i = 0; i < feedHolder[ 'attributes' ].length; i ++ ) {
28
+
29
+ if ( feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] === '0' ) {
30
+
31
+ switch ( feedHolder[ 'attributes' ][ i ][ 'fieldName' ] ) {
32
+
33
+ case 'google_product_category':
34
+
35
+ if ( _googleNeedsProductCat === true ) {
36
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
37
+ } else {
38
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
39
+ }
40
+
41
+ break;
42
+
43
+ case 'is_bundle':
44
+ case 'multipack':
45
+
46
+ if ( jQuery.inArray( targetCountry, googleSpecialProductCountries() ) < 0 ) {
47
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
48
+ } else {
49
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
50
+ }
51
+
52
+ break;
53
+
54
+ case 'brand':
55
+
56
+ if ( _googleRequiresBrand === true ) {
57
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
58
+ } else {
59
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
60
+ }
61
+
62
+ break;
63
+
64
+ case 'item_group_id':
65
+
66
+ if ( jQuery.inArray( targetCountry, googleSpecialClothingGroupCountries() ) > - 1 ) {
67
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
68
+ } else {
69
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
70
+ }
71
+
72
+ break;
73
+
74
+ case 'gender':
75
+ case 'age_group':
76
+ case 'color':
77
+ case 'size':
78
+
79
+ if ( jQuery.inArray( targetCountry, googleSpecialClothingGroupCountries() ) > - 1 && _googleClothingAndAccessories === true ) {
80
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
81
+ } else {
82
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
83
+ }
84
+
85
+ break;
86
+
87
+ case 'tax':
88
+
89
+ // In accordance with the Google Feed Specifications update of september 2015
90
+ if ( targetCountry === 'US' ) {
91
+
92
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
93
+ } else {
94
+
95
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
96
+ }
97
+
98
+ break;
99
+
100
+ case 'shipping':
101
+
102
+ // In accordance with the Google Feed Specifications update of september 2015
103
+ if ( jQuery.inArray( targetCountry, googleSpecialShippingCountries() ) > - 1 ) {
104
+
105
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '1';
106
+ } else {
107
+
108
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
109
+ }
110
+
111
+ break;
112
+
113
+ case 'subscription_costs':
114
+ case 'subscription_cost-period':
115
+ case 'subscription_cost-period_length':
116
+ case 'subscription_cost-amount':
117
+
118
+ if ( jQuery.inArray( targetCountry, googleSpecialSubscriptionCountries()) > - 1 ) {
119
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '4';
120
+ } else {
121
+ feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] = '0';
122
+ }
123
+
124
+ break;
125
+
126
+ default:
127
+ break;
128
+
129
+ }
130
+
131
+ // set the attribute to active if it's a recommended or highly recommended attribute, or if it has a value
132
+ feedHolder[ 'attributes' ][ i ][ 'isActive' ] = setAttributeStatus( parseInt( feedHolder[ 'attributes' ][ i ][ 'fieldLevel' ] ), feedHolder[ 'attributes' ][ i ][ 'value' ] );
133
+ }
134
+ }
135
+
136
+ return feedHolder;
137
+ }
138
+
139
+ function setGooglePresets( field ) {
140
+ switch ( field ) {
141
+ case 'condition':
142
+ return '{"m":[{"s":{"static":"new"}}]}';
143
+
144
+ case 'availability':
145
+ return '{"m":[{"s":{"static":"in stock"},"c":[{"1":"0#_stock_status#0#instock"}]},{"s":{"static":"out of stock"}}]}';
146
+
147
+ case 'identifier_exists':
148
+ return '{"m":[{"s":{"static":"yes"}}]}';
149
+
150
+ case 'adult':
151
+ return '{"m":[{"s":{"static":"no"}}]}';
152
+
153
+ case 'price':
154
+ return '{"m":[{"s":{"source":"combined","f":"_regular_price|1#wc_currency"}}]}';
155
+
156
+ default:
157
+ break;
158
+ }
159
+ }
160
+
161
+ function fillGoogleCategoryVariables( selectedCategory, currentLevel ) {
162
+ switch ( currentLevel ) {
163
+ case 'lvl_0':
164
+ case 'lvl_1':
165
+ _googleClothingAndAccessories = false;
166
+ _googleNeedsProductCat = false;
167
+ _googleRequiresBrand = true;
168
+ break;
169
+ }
170
+
171
+ switch ( selectedCategory ) {
172
+ case 'Clothing':
173
+ _googleClothingAndAccessories = true;
174
+ _googleNeedsProductCat = true;
175
+ _googleRequiresBrand = true;
176
+ break;
177
+
178
+ case 'Software':
179
+ case 'Apparel & Accessories':
180
+ _googleClothingAndAccessories = true;
181
+ _googleNeedsProductCat = true;
182
+ _googleRequiresBrand = true;
183
+ break;
184
+
185
+ case 'Media':
186
+ _googleClothingAndAccessories = false;
187
+ _googleNeedsProductCat = true;
188
+ _googleRequiresBrand = false;
189
+ break;
190
+
191
+ default:
192
+ break;
193
+ }
194
+ }
195
+
196
+ function googleStaticFieldOptions( fieldName ) {
197
+ var options = [];
198
+
199
+ switch ( fieldName ) {
200
+ case 'condition':
201
+ options = [ 'new', 'used', 'refurbished' ];
202
+ break;
203
+
204
+ case 'availability':
205
+ options = [ 'in stock', 'out of stock', 'preorder' ];
206
+ break;
207
+
208
+ case 'identifier_exists':
209
+ options = [ 'yes', 'no' ];
210
+ break;
211
+
212
+ case 'gender':
213
+ options = [ 'unisex', 'male', 'female' ];
214
+ break;
215
+
216
+ case 'age_group':
217
+ options = [ 'adult', 'newborn', 'infant', 'toddler', 'kids' ];
218
+ break;
219
+
220
+ case 'size_type':
221
+ options = [ 'regular', 'petite', 'plus', 'big and tall', 'maternity' ];
222
+ break;
223
+
224
+ case 'size_system':
225
+ options = [ 'EU', 'US', 'UK', 'DE', 'FR', 'JP', 'CN', 'IT', 'BR', 'MEX', 'AU' ];
226
+ break;
227
+
228
+ case 'adult':
229
+ options = [ 'yes', 'no' ];
230
+ break;
231
+
232
+ case 'energy_efficiency_class':
233
+ case 'min_energy_efficiency_class':
234
+ case 'max_energy_efficiency_class':
235
+ options = [ 'A', 'A+', 'A++', 'A+++', 'B', 'C', 'D', 'E', 'F', 'G' ];
236
+ break;
237
+
238
+ case 'excluded_destination':
239
+ options = [ 'Shopping', 'ShoppingActions', 'DisplayAds' ];
240
+ break;
241
+
242
+ default:
243
+ options = [];
244
+ break;
245
+ }
246
+
247
+ return options;
248
+ }
249
+
250
+ function switchToGoogleFeedFormMainInputs( isNew, channel ) {
251
+ jQuery( '#country-list-row' ).show();
252
+ jQuery( '#category-list-row' ).show();
253
+ jQuery( '#google-feed-title-row' ).show();
254
+ jQuery( '#google-feed-description-row' ).show();
255
+ jQuery( '#aggregator-selector-row' ).hide();
256
+
257
+ appendCategoryLists( parseInt( channel ), 'en-US', isNew );
258
+ }
259
+
260
+ function googleInputChanged( feedId, categoryChanged ) {
261
+ var fileName = jQuery( '#file-name' ).val();
262
+ var selectedCountry = jQuery( '#countries' ).val();
263
+ var selectedMainCategory = jQuery( '#lvl_0' ).val();
264
+
265
+ // enable or disable the correct buttons for the google channel
266
+ if ( fileName && selectedCountry !== '0' && selectedMainCategory && selectedMainCategory !== '0' ) {
267
+ updateFeedFormAfterInputChanged( feedId, categoryChanged );
268
+ } else {
269
+ // keep the Generate and Save buttons disabled
270
+ disableFeedActionButtons();
271
+ }
272
+ }
273
+
274
+ // ALERT! This function is equivalent to the special_clothing_group_countries() function in class-feed.php in the google channels folder
275
+ function googleSpecialClothingGroupCountries() {
276
+ return [ 'US', 'GB', 'DE', 'FR', 'JP', 'BR' ]; // Brazil added based on the new Feed Specifications from september 2015
277
+ }
278
+
279
+ // ALERT! This function is equivalent to the special_shipping_countries() function in class-feed.php in the google channels folder
280
+ function googleSpecialShippingCountries() {
281
+ return [ 'US', 'GB', 'DE', 'AU', 'FR', 'CH', 'CZ', 'NL', 'IT', 'ES', 'JP' ];
282
+ }
283
+
284
+ // ALERT! This function is equivalent to the special_product_countries() function in class-feed.php in the google channels folder
285
+ function googleSpecialProductCountries() {
286
+ return [ 'US', 'GB', 'DE', 'AU', 'FR', 'CH', 'CZ', 'NL', 'IT', 'ES', 'JP', 'BR' ];
287
+ }
288
+
289
+ // ALERT! This function is equivalent to the special_subscription_countries() function in class-feed.php in the google channels folder
290
+ function googleSpecialSubscriptionCountries() {
291
+ return [ 'DE', 'FR', 'GB' ];
292
+ }
includes/application/js/tvc_channel-functions.js ADDED
@@ -0,0 +1,707 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ /**
3
+ * Switches the correct input fields on the feed form on or off depending on the selected channel
4
+ *
5
+ * @param {string} channel
6
+ * @param {boolean} isNew
7
+ * @returns nothing
8
+ */
9
+
10
+ // TVC_CHANNEL_RELATED
11
+ function tvc_showChannelInputs( channel, isNew ) {
12
+ var fName = {
13
+ '1': 'switchToGoogleFeedFormMainInputs',
14
+ '2': 'switchToBingFeedFormMainInputs',
15
+ '3': 'switchToBeslisFeedFormMainInputs',
16
+ '4': 'switchToPricegrabberFeedFormMainInputs',
17
+ '5': 'switchToShoppingFeedFormMainInputs',
18
+ '6': 'switchToAmazonFeedFormMainInputs',
19
+ '7': 'switchToConnexityFeedFormMainInputs',
20
+ '9': 'switchToNextagFeedFormMainInputs',
21
+ '10': 'switchToKieskeurigFeedFormMainInputs',
22
+ '11': 'switchToVergelijkFeedFormMainInputs',
23
+ '12': 'switchToKoopjespakkerFeedFormMainInputs',
24
+ '13': 'switchToAvantLinkFeedFormMainInputs',
25
+ '14': 'switchToZboziFeedFormMainInputs',
26
+ '15': 'switchToComconFeedFormMainInputs',
27
+ '16': 'switchToFacebookFeedFormMainInputs',
28
+ '17': 'switchToBolFeedFormMainInputs',
29
+ '18': 'switchToAdtractionFeedFormMainInputs',
30
+ '19': 'switchToRicardoFeedFormMainInputs',
31
+ '20': 'switchToEbayFeedFormMainInputs',
32
+ '21': 'switchToShopzillaFeedFormMainInputs',
33
+ '22': 'switchToConvertoFeedFormMainInputs',
34
+ '23': 'switchToIdealoFeedFormMainInputs',
35
+ '24': 'switchToHeurekaFeedFormMainInputs',
36
+ '25': 'switchToPepperjamFeedFormMainInputs',
37
+ '26': 'switchToGalaxusProductDataFeedFormMainInputs',
38
+ '27': 'switchToGalaxusProductPropertiesFeedFormMainInputs',
39
+ '28': 'switchToGalaxusProductStockPricingFeedFormMainInputs',
40
+ '996': 'switchToTsvFeedFormMainInputs',
41
+ '997': 'switchToTxtFeedFormMainInputs',
42
+ '998': 'switchToCsvFeedFormMainInputs',
43
+ '999': 'switchToFeedFormMainInputs',
44
+ };
45
+
46
+ // call the correct function
47
+ if ( fName.hasOwnProperty( channel ) ) {
48
+ window[ fName[ channel ] ]( isNew, channel );
49
+ }
50
+
51
+ // standard for all channels
52
+ jQuery( '#update-schedule-row' ).show();
53
+ jQuery( '#add-product-variations-row' ).show();
54
+
55
+ if ( (
56
+ null === jQuery( '#lvl_0' ).val() && '' === jQuery( '#selected-categories' ).html() ) || 0 === jQuery( '#tvc-countries-selector' ).val() ) {
57
+ tvc_show_or_hide_category_map( channel );
58
+ } else {
59
+ jQuery( '#tvc-category-map' ).show();
60
+ }
61
+ }
62
+
63
+ /**
64
+ * depending on channel show or hide the category map directly after channel selection
65
+ * Add the channel to the "show" part when it does not have an own category list
66
+ *
67
+ * @param {string} channel
68
+ * @returns nothing
69
+ */
70
+ function tvc_show_or_hide_category_map( channel ) {
71
+ var category_map_selector = jQuery( '#tvc-category-map' );
72
+
73
+ switch ( channel ) {
74
+ case '15': // Commerce Connector
75
+ case '17': // Bol.com
76
+ case '18': // Adtraction
77
+ case '22': // Converto
78
+ case '23': // Idealo
79
+ case '25': // Pepperjam
80
+ case '26': // Galaxus Product Data
81
+ case '27': // Galaxus Product Stock Pricing
82
+ case '28': // Galaxus Product Properties
83
+ category_map_selector.show();
84
+ break;
85
+
86
+ default:
87
+ category_map_selector.hide();
88
+ break;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Usually categories are separated by a > but some channels use other separators
94
+ *
95
+ * @since 2.2.0
96
+ *
97
+ * @param {string} channel
98
+ * @returns {string} separator
99
+ */
100
+ function tvc_category_separator( channel ) {
101
+ switch ( channel ) {
102
+ case '14': // Commerce Connector
103
+ case '24': // Commerce Connector
104
+ return ' | ';
105
+
106
+ default:
107
+ return ' > ';
108
+ }
109
+ }
110
+
111
+ /**
112
+ * calls the correct channel function that makes sure the correct input fields are shown after the user has changed the title or channel
113
+ *
114
+ * @param {string} channel
115
+ * @param {string} feedId
116
+ * @param {boolean} categoryChanged
117
+ * @returns nothing
118
+ */
119
+ function tvc_reactOnChannelInputChanged( channel, feedId, categoryChanged ) {
120
+ var functionName = '';
121
+ var tabId = tvc_getUrlVariable( 'tab' ); // identify the feed type
122
+
123
+ if ( 'product-feed' === tabId ) { // handle product feeds from different merchants
124
+ var fName = {
125
+ '1': 'googleInputChanged',
126
+ '2': 'bingInputChanged',
127
+ '3': 'beslisInputChanged',
128
+ '4': 'pricegrabberInputChanged',
129
+ '5': 'shoppingInputChanged',
130
+ '6': 'amazonInputChanged',
131
+ '7': 'connexityInputChanged',
132
+ '9': 'nextagInputChanged',
133
+ '10': 'kieskeurigInputChanged',
134
+ '11': 'vergelijkInputChanged',
135
+ '12': 'koopjespakkerInputChanged',
136
+ '13': 'avantlinkInputChanged',
137
+ '14': 'zboziInputChanged',
138
+ '15': 'comconInputChanged',
139
+ '16': 'facebookInputChanged',
140
+ '17': 'bolInputChanged',
141
+ '18': 'adtractionInputChanged',
142
+ '19': 'ricardoInputChanged',
143
+ '20': 'ebayInputChanged',
144
+ '21': 'shopzillaInputChanged',
145
+ '22': 'convertoInputChanged',
146
+ '23': 'idealoInputChanged',
147
+ '24': 'heurekaInputChanged',
148
+ '25': 'pepperjamInputChanged',
149
+ '26': 'galaxusProductDataInputChanged',
150
+ '27': 'galaxusProductStockPricingInputChanged',
151
+ '28': 'galaxusProductPropertiesInputChanged',
152
+ '996': 'TsvInputChanged',
153
+ '997': 'TxtInputChanged',
154
+ '998': 'CsvInputChanged',
155
+ '999': 'InputChanged',
156
+ };
157
+
158
+ functionName = fName[ channel ];
159
+ } else { // handle special feeds from add-ons
160
+ var functionString = tvc_convertToCamelCase( tabId.split( '-' ) );
161
+ functionName = functionString + 'Changed';
162
+ }
163
+
164
+ // call the correct function
165
+ if ( functionName ) {
166
+ window[ functionName ]( feedId, categoryChanged );
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Returns txt of xml depending on the feed type that needs to be made
172
+ *
173
+ * @param {string} channel
174
+ * @returns {string} with the channel feed type
175
+ */
176
+ function tvc_getChannelFeedType( channel ) {
177
+ switch ( channel ) {
178
+ case '2': // bing
179
+ case '4': // pricegrabber
180
+ case '6': // amazon
181
+ case '7': // connexity
182
+ case '9': // nextag
183
+ case '12': // koopjespakker.nl
184
+ case '21': // shopzilla
185
+ case '25': // pepperjam
186
+ case '997': // Custom TXT Feed
187
+ return 'txt';
188
+
189
+ case '15': // Commerce Connector
190
+ case '17': // Bol.com
191
+ case '19': // Ricardo.ch
192
+ case '22': // Converto
193
+ case '23': // Idealo
194
+ case '26': // Galaxus Product Data
195
+ case '27': // Galaxus Product Stock Pricing
196
+ case '28': // Galaxus Product Properties
197
+ case '998': // Custom CSV Feed
198
+ return 'csv';
199
+
200
+ case '996': // Custom TSV feed
201
+ return 'tsv';
202
+
203
+ default:
204
+ return 'xml';
205
+ }
206
+ }
207
+
208
+ /**
209
+ * returns the correct country code for the channel specific category text file
210
+ *
211
+ * @param {string} channel
212
+ * @returns {String} with the channels country code
213
+ */
214
+ function tvc_channelCountryCode( channel ) {
215
+ var language = 'en-US';
216
+
217
+ // TVC_CHANNEL_RELATED
218
+ switch ( channel ) {
219
+ case '3': // Beslist
220
+ case '10': // Kieskeurig
221
+ case '11': // Vergelijk
222
+ case '12': // Koopjespakker
223
+ case '17': // Bol.com
224
+ language = 'nl-NL';
225
+ break;
226
+
227
+ case '14': // Zbozi
228
+ case '24': // Heureka
229
+ language = 'cs-CZ';
230
+ break;
231
+
232
+ case '19': // Ricardo.ch
233
+ language = 'de-CH';
234
+ break;
235
+
236
+ case '23': // Idealo
237
+ language = 'de-DE';
238
+ break;
239
+ }
240
+
241
+ return language;
242
+ }
243
+
244
+ /**
245
+ * Returns true if the specified channel does not have its own categories but uses the users shop
246
+ * categories instead
247
+ *
248
+ * @param {string} channel
249
+ * @returns {Boolean} true when this channel uses categories from the shop
250
+ */
251
+ function tvc_channelUsesOwnCategories( channel ) {
252
+ // only add the channel when it uses the shop categories in stead of specific channel categories
253
+ switch ( channel ) {
254
+ case '10': // kieskeurig.nl
255
+ case '15': // Commerce Connector
256
+ case '17': // Bol.com
257
+ case '18': // Adtraction
258
+ case '22': // Converto
259
+ case '23': // Idealo
260
+ case '25': // Pepperjam
261
+ case '26': // Galaxus Product Data
262
+ case '27': // Galaxus Product Stock Pricing
263
+ case '28': // Galaxus Product Properties
264
+ return true;
265
+
266
+ default:
267
+ return false;
268
+ }
269
+ }
270
+
271
+ /**
272
+ * If required for that channel, this function activates the correct function that will prepare the global category
273
+ * variables in the channel specific javascript file. Does nothing when not required for the channel
274
+ *
275
+ * @param {string} channel
276
+ * @param {string} selectedCategory
277
+ * @param {string} currentLevelId
278
+ * @returns nothing
279
+ */
280
+ function tvc_fillCategoryVariables(
281
+ channel, selectedCategory, currentLevelId ) {
282
+ var fName = {
283
+ '1': 'fillGoogleCategoryVariables',
284
+ '4': 'fillPricegrabberCategoryVariables',
285
+ '5': 'fillShoppingCategoryVariables',
286
+ '6': 'fillAmazonCategoryVariables',
287
+ '7': 'fillConnexityCategoryVariables',
288
+ '9': 'fillNextagCategoryVariables',
289
+ '13': 'fillAvantLinkCategoryVariables',
290
+ '14': 'fillZboziCategoryVariables',
291
+ };
292
+
293
+ // call the correct function
294
+ if ( fName.hasOwnProperty( channel ) ) {
295
+ // call the correct switch main form inputs function
296
+ window[ fName[ channel ] ]( selectedCategory, currentLevelId );
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Some fields require specific allowed inputs. This function gets the correct options for given field
302
+ *
303
+ * @param {string} rowId
304
+ * @param {string} queryLevel
305
+ * @param {string} combinationLevel
306
+ * @param {string} channel
307
+ * @param {string} fieldName
308
+ * @param {string} selectedValue
309
+ * @returns {String} containing the allowed options
310
+ */
311
+ function tvc_displayCorrectStaticField(
312
+ rowId, queryLevel, combinationLevel, channel, fieldName, selectedValue ) {
313
+ var html = '';
314
+ var options = tvc_restrictedStaticFields( channel, fieldName );
315
+
316
+ if ( options !== undefined ) {
317
+ if ( options.length === 0 ) {
318
+ // show the standard text type input field
319
+ html = tvc_staticInputField( rowId, queryLevel, combinationLevel, selectedValue );
320
+ } else {
321
+ // show the standard selector with the correct allowed options
322
+ html = tvc_staticInputSelect( rowId, queryLevel, combinationLevel, options, selectedValue );
323
+ }
324
+ }
325
+
326
+ return html;
327
+ }
328
+
329
+ /**
330
+ * Gets the advised input fields
331
+ *
332
+ * @param {string} channel
333
+ * @returns {array} array containing the advised inputs
334
+ */
335
+ function tvc_getAdvisedInputs( channel ) {
336
+ var fName = {
337
+ '1': 'woocommerceToGoogleFields',
338
+ '2': 'woocommerceToBingFields',
339
+ '3': 'woocommerceToBeslisFields',
340
+ '4': 'woocommerceToPricegrabberFields',
341
+ '5': 'woocommerceToShoppingFields',
342
+ '6': 'woocommerceToAmazonFields',
343
+ '7': 'woocommerceToConnexityFields',
344
+ '9': 'woocommerceToNextagFields',
345
+ '10': 'woocommerceToKieskeurigFields',
346
+ '11': 'woocommerceToVergelijkFields',
347
+ '12': 'woocommerceToKoopjespakkerFields',
348
+ '13': 'woocommerceToAvantLinkFields',
349
+ '14': 'woocommerceToZboziFields',
350
+ '15': 'woocommerceToComconFields',
351
+ '16': 'woocommerceToFacebookFields',
352
+ '17': 'woocommerceToBolFields',
353
+ '18': 'woocommerceToAdtractionFields',
354
+ '19': 'woocommerceToRicardoFields',
355
+ '20': 'woocommerceToeBayFields',
356
+ '21': 'woocommerceToShopzillaFields',
357
+ '22': 'woocommerceToConvertoFields',
358
+ '23': 'woocommerceToIdealoFields',
359
+ '24': 'woocommerceToHeurekaFields',
360
+ '25': 'woocommerceToPepperjamFields',
361
+ '26': 'woocommerceToGalaxusProductDataFields',
362
+ '27': 'woocommerceToGalaxusProductStockPricingFields',
363
+ '28': 'woocommerceToGalaxusProductPropertiesFields',
364
+ };
365
+
366
+ if ( fName.hasOwnProperty( channel ) ) {
367
+ // call the correct function
368
+ return window[ fName[ channel ] ]();
369
+ } else {
370
+ return [];
371
+ }
372
+ }
373
+
374
+ /**
375
+ * Sets the attributes to the correct levels depending on several variables.
376
+ *
377
+ * @param {string} channel Channel id.
378
+ * @param {object} feedHolder Feed Holder containing feed data items.
379
+ * @param {string} selectArgument
380
+ *
381
+ * @returns {object} feed holder with the correct attribute levels
382
+ */
383
+ // ALERT has a relation with the set_output_attribute_levels() function in the class-tvc-data.php file
384
+ function tvc_setOutputAttributeLevels( channel, feedHolder, selectArgument ) {
385
+ switch ( channel ) {
386
+ case '1':
387
+ return setGoogleOutputAttributeLevels( feedHolder, selectArgument );
388
+
389
+ case '2':
390
+ return setBingOutputAttributeLevels( feedHolder );
391
+
392
+ case '3':
393
+ return setBeslisOutputAttributeLevels( feedHolder );
394
+
395
+ case '4':
396
+ return setPricegrabberOutputAttributeLevels( feedHolder );
397
+
398
+ case '5':
399
+ return setShoppingOutputAttributeLevels( feedHolder );
400
+
401
+ case '6':
402
+ return setAmazonOutputAttributeLevels( feedHolder );
403
+
404
+ case '7':
405
+ return setConnexityOutputAttributeLevels( feedHolder );
406
+
407
+ case '9':
408
+ return setNextagOutputAttributeLevels( feedHolder );
409
+
410
+ case '10':
411
+ return setKieskeurigOutputAttributeLevels( feedHolder );
412
+
413
+ case '11':
414
+ return setVergelijkOutputAttributeLevels( feedHolder );
415
+
416
+ case '13':
417
+ return setAvantLinkOutputAttributeLevels( feedHolder,
418
+ selectArgument );
419
+
420
+ case '14':
421
+ return setZboziOutputAttributeLevels( feedHolder, selectArgument );
422
+
423
+ case '26':
424
+ return setGalaxusProductDataAttributeLevels( feedHolder,
425
+ selectArgument );
426
+
427
+ case '27':
428
+ return setGalaxusProductStockPricingAttributeLevels( feedHolder );
429
+
430
+ case '28':
431
+ return setGalaxusProductPropertiesAttributeLevels( feedHolder );
432
+
433
+ case '996':
434
+ return setTsvOutputAttributeLevels( feedHolder );
435
+
436
+ case '997':
437
+ return setTxtOutputAttributeLevels( feedHolder );
438
+
439
+ case '998':
440
+ return setCsvOutputAttributeLevels( feedHolder );
441
+
442
+ case '999':
443
+ return setOutputAttributeLevels( feedHolder );
444
+
445
+ default:
446
+ return feedHolder;
447
+ }
448
+ }
449
+
450
+ /**
451
+ * returns an array with the channel specific fields with restricted input options
452
+ *
453
+ * @param {string} channel
454
+ * @param {string} fieldName
455
+ * @returns {array}
456
+ */
457
+ function tvc_restrictedStaticFields( channel, fieldName ) {
458
+ var fName = {
459
+ '1': 'googleStaticFieldOptions',
460
+ '2': 'bingStaticFieldOptions',
461
+ '3': 'beslisStaticFieldOptions',
462
+ '4': 'pricegrabberStaticFieldOptions',
463
+ '5': 'shoppingStaticFieldOptions',
464
+ '6': 'amazonStaticFieldOptions',
465
+ '7': 'connexityStaticFieldOptions',
466
+ '9': 'nextagStaticFieldOptions',
467
+ '10': 'kieskeurigStaticFieldOptions',
468
+ '11': 'vergelijkStaticFieldOptions',
469
+ '12': 'koopjespakkerStaticFieldOptions',
470
+ '13': 'avantlinkStaticFieldOptions',
471
+ '14': 'zboziStaticFieldOptions',
472
+ '15': 'comconStaticFieldOptions',
473
+ '16': 'facebookStaticFieldOptions',
474
+ '17': 'bolStaticFieldOptions',
475
+ '18': 'adtractionStaticFieldOptions',
476
+ '19': 'ricardoStaticFieldOptions',
477
+ '20': 'ebayStaticFieldOptions',
478
+ '21': 'shopzillaStaticFieldOptions',
479
+ '23': 'idealoStaticFieldOptions',
480
+ '25': 'pepperjamStaticFieldOptions',
481
+ '26': 'galaxusProductDataStaticFieldOptions',
482
+ '27': 'galaxusProductStockPricingStaticFieldOptions',
483
+ '28': 'galaxusProductPropertiesStaticFieldOptions',
484
+ };
485
+
486
+ if ( fName.hasOwnProperty( channel ) ) {
487
+ // call the correct function
488
+ return window[ fName[ channel ] ]( fieldName );
489
+ } else {
490
+
491
+ return [];
492
+ }
493
+ }
494
+
495
+ /**
496
+ * set a preset condition, other than the advised input, for fields for a specific channel (eg. condition = static field with 'new' selected
497
+ *
498
+ * @param {array} outputsField
499
+ * @param {string} channel
500
+ * @returns {array}
501
+ */
502
+ function tvc_setChannelRelatedPresets( outputsField, channel ) {
503
+ // TVC_CHANNEL_RELATED
504
+ switch ( channel ) {
505
+
506
+ case '1': // Google
507
+ if ( outputsField[ 'field_label' ] === 'condition' || outputsField[ 'field_label' ] === 'availability' || outputsField[ 'field_label' ] === 'identifier_exists' || outputsField[ 'field_label' ] === 'adult' || outputsField[ 'field_label' ] === 'price' ) {
508
+
509
+ // only switch to the 'preset' value if no user value is set
510
+ if ( ! outputsField[ 'value' ] ) {
511
+ outputsField[ 'value' ] = setGooglePresets( outputsField[ 'field_label' ] );
512
+ }
513
+ }
514
+ break;
515
+
516
+ case '2': // Bing
517
+ if ( outputsField[ 'field_label' ] === 'seller_name' ) {
518
+ // only switch to the 'preset' value if no user value is set
519
+ if ( ! outputsField[ 'value' ] ) {
520
+ outputsField[ 'value' ] = setBingPresets( outputsField[ 'field_label' ] );
521
+ }
522
+ }
523
+ break;
524
+
525
+ case '3': // Beslist
526
+ if ( outputsField[ 'field_label' ] === 'Conditie' || outputsField[ 'field_label' ] === 'Levertijd' ) {
527
+ // only switch to the 'preset' value if no user value is set
528
+ if ( ! outputsField[ 'value' ] ) {
529
+ outputsField[ 'value' ] = setBeslisPresets( outputsField[ 'field_label' ] );
530
+ }
531
+ }
532
+ break;
533
+
534
+ case '13': // Avant Link
535
+ if ( outputsField[ 'field_label' ] === 'condition' || outputsField[ 'field_label' ] === 'availability' || outputsField[ 'field_label' ] === 'identifier_exists' ) {
536
+
537
+ // only switch to the 'preset' value if no user value is set
538
+ if ( ! outputsField[ 'value' ] ) {
539
+ outputsField[ 'value' ] = setAvantLinkPresets( outputsField[ 'field_label' ] );
540
+ }
541
+ }
542
+ break;
543
+
544
+ case '14': // Zbozi
545
+ if ( outputsField[ 'field_label' ] === 'EROTIC' || outputsField[ 'field_label' ] === 'VISIBILITY' ) {
546
+ // only switch to the 'preset' value if no user value is set
547
+ if ( ! outputsField[ 'value' ] ) {
548
+ outputsField[ 'value' ] = setZboziPresets( outputsField[ 'field_label' ] );
549
+ }
550
+ }
551
+ break;
552
+
553
+ case '15': // Commerce Connector
554
+ if ( outputsField[ 'field_label' ] === 'Delivery time' ) {
555
+ // only switch to the 'preset' value if no user value is set
556
+ if ( ! outputsField[ 'value' ] ) {
557
+ outputsField[ 'value' ] = setComconPresets( outputsField[ 'field_label' ] );
558
+ }
559
+ }
560
+ break;
561
+
562
+ case '16': // Facebook
563
+ if ( outputsField[ 'field_label' ] === 'condition' || outputsField[ 'field_label' ] === 'availability' || outputsField[ 'field_label' ] === 'price' ) {
564
+
565
+ // only switch to the 'preset' value if no user value is set
566
+ if ( ! outputsField[ 'value' ] ) {
567
+ outputsField[ 'value' ] = setFacebookPresets( outputsField[ 'field_label' ] );
568
+ }
569
+ }
570
+ break;
571
+
572
+ case '17': // Bol.com
573
+ if ( outputsField[ 'field_label' ] === 'Condition' || outputsField[ 'field_label' ] === 'Deliverycode' ) {
574
+ // only switch to the 'preset' value if no user value is set
575
+ if ( ! outputsField[ 'value' ] ) {
576
+ outputsField[ 'value' ] = setBolPresets( outputsField[ 'field_label' ] );
577
+ }
578
+ }
579
+ break;
580
+
581
+ case '18': // Adtraction
582
+ if ( outputsField[ 'field_label' ] === 'instock' ) {
583
+ // only switch to the 'preset' value if no user value is set
584
+ if ( ! outputsField[ 'value' ] ) {
585
+ outputsField[ 'value' ] = setAdtractionPresets( outputsField[ 'field_label' ] );
586
+ }
587
+ }
588
+ break;
589
+
590
+ case '19': // Ricardo
591
+ if ( outputsField[ 'field_label' ] === 'Descriptions[0].LanguageNr' || outputsField[ 'field_label' ] === 'Increment' || outputsField[ 'field_label' ] === 'AvailabilityId' || outputsField[ 'field_label' ] === 'Condition' ) {
592
+
593
+ // only switch to the 'preset' value if no user value is set
594
+ if ( ! outputsField[ 'value' ] ) {
595
+ outputsField[ 'value' ] = setRicardoPresets( outputsField[ 'field_label' ] );
596
+ }
597
+ }
598
+ break;
599
+
600
+ case '20': // eBay
601
+ break;
602
+
603
+ case '21': // Shopzilla
604
+ if ( outputsField[ 'field_label' ] === 'Availability' || outputsField[ 'field_label' ] === 'Condition' ) {
605
+ // only switch to the 'preset' value if no user value is set
606
+ if ( ! outputsField[ 'value' ] ) {
607
+ outputsField[ 'value' ] = setShopzillaPresets( outputsField[ 'field_label' ] );
608
+ }
609
+ }
610
+ break;
611
+
612
+ case '22': // Converto
613
+ if ( outputsField[ 'field_label' ] === 'Availability' || outputsField[ 'field_label' ] === 'Condition' ) {
614
+ // only switch to the 'preset' value if no user value is set
615
+ if ( ! outputsField[ 'value' ] ) {
616
+ outputsField[ 'value' ] = setShopzillaPresets( outputsField[ 'field_label' ] );
617
+ }
618
+ }
619
+ break;
620
+
621
+ case '24': // Heureka
622
+ if ( 'ITEM_TYPE' === outputsField[ 'field_label' ] ) {
623
+ if ( ! outputsField[ 'value' ] ) {
624
+ outputsField[ 'value' ] = setHeurekaPresets( outputsField[ 'field_label' ] );
625
+ }
626
+ }
627
+ break;
628
+
629
+ case '25': // Pepperjam
630
+ if ( 'ITEM_TYPE' === outputsField[ 'discontinued' ] ) {
631
+ if ( ! outputsField[ 'value' ] ) {
632
+ outputsField[ 'value' ] = setPepperjamPresets( outputsField[ 'field_label' ] );
633
+ }
634
+ }
635
+ break;
636
+
637
+ case '26': // Galaxus Product Data
638
+ if ( 'ITEM_TYPE' === outputsField[ 'discontinued' ] ) {
639
+ if ( ! outputsField[ 'value' ] ) {
640
+ outputsField[ 'value' ] = setGalaxusProductDataPresets( outputsField[ 'field_label' ] );
641
+ }
642
+ }
643
+ break;
644
+
645
+ case '27': // Galaxus Product Stock Pricing
646
+ if ( 'ITEM_TYPE' === outputsField[ 'discontinued' ] ) {
647
+ if ( ! outputsField[ 'value' ] ) {
648
+ outputsField[ 'value' ] = setGalaxusProductStockPricingPresets( outputsField[ 'field_label' ] );
649
+ }
650
+ }
651
+ break;
652
+
653
+ case '28': // Galaxus Product Properties
654
+ if ( 'ITEM_TYPE' === outputsField[ 'discontinued' ] ) {
655
+ if ( ! outputsField[ 'value' ] ) {
656
+ outputsField[ 'value' ] = setGalaxusProductPropertiesPresets( outputsField[ 'field_label' ] );
657
+ }
658
+ }
659
+ break;
660
+
661
+ default:
662
+ break;
663
+ }
664
+ }
665
+
666
+ function tvc_requiresLanguageInput( channel ) {
667
+ switch ( channel ) {
668
+ case '26':
669
+ return true; // Galaxus Product Data
670
+
671
+ default:
672
+ return false;
673
+ }
674
+ }
675
+
676
+ /**
677
+ * returns if a channel is a custom feed channel
678
+ *
679
+ * @param {string} channel
680
+ * @returns {boolean}
681
+ */
682
+ function tvc_isCustomChannel( channel ) {
683
+ switch ( channel ) {
684
+ case '996': // Custom TSV Feed
685
+ case '997': // Custom TXT Feed
686
+ case '998': // Custom CSV Feed
687
+ case '999': // Custom XML Feed
688
+ return true;
689
+
690
+ default:
691
+ return false;
692
+ }
693
+ }
694
+
695
+ // ALERT! has a php equivalent in class-feed-master.php called set_attribute_status();
696
+ function setAttributeStatus( fieldLevel, fieldValue ) {
697
+ if ( fieldLevel > 0 && fieldLevel < 3 ) {
698
+ return true;
699
+ }
700
+
701
+ if ( fieldValue ) {
702
+ return true;
703
+ }
704
+
705
+ return false;
706
+ }
707
+
includes/application/js/tvc_channel-functions.min.js ADDED
@@ -0,0 +1,498 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function tvc_showChannelInputs(b, a) {
2
+ var c = {
3
+ "1": "switchToGoogleFeedFormMainInputs",
4
+ "2": "switchToBingFeedFormMainInputs",
5
+ "3": "switchToBeslisFeedFormMainInputs",
6
+ "4": "switchToPricegrabberFeedFormMainInputs",
7
+ "5": "switchToShoppingFeedFormMainInputs",
8
+ "6": "switchToAmazonFeedFormMainInputs",
9
+ "7": "switchToConnexityFeedFormMainInputs",
10
+ "9": "switchToNextagFeedFormMainInputs",
11
+ "10": "switchToKieskeurigFeedFormMainInputs",
12
+ "11": "switchToVergelijkFeedFormMainInputs",
13
+ "12": "switchToKoopjespakkerFeedFormMainInputs",
14
+ "13": "switchToAvantLinkFeedFormMainInputs",
15
+ "14": "switchToZboziFeedFormMainInputs",
16
+ "15": "switchToComconFeedFormMainInputs",
17
+ "16": "switchToFacebookFeedFormMainInputs",
18
+ "17": "switchToBolFeedFormMainInputs",
19
+ "18": "switchToAdtractionFeedFormMainInputs",
20
+ "19": "switchToRicardoFeedFormMainInputs",
21
+ "20": "switchToEbayFeedFormMainInputs",
22
+ "21": "switchToShopzillaFeedFormMainInputs",
23
+ "22": "switchToConvertoFeedFormMainInputs",
24
+ "23": "switchToIdealoFeedFormMainInputs",
25
+ "24": "switchToHeurekaFeedFormMainInputs",
26
+ "25": "switchToPepperjamFeedFormMainInputs",
27
+ "26": "switchToGalaxusProductDataFeedFormMainInputs",
28
+ "27": "switchToGalaxusProductPropertiesFeedFormMainInputs",
29
+ "28": "switchToGalaxusProductStockPricingFeedFormMainInputs",
30
+ "996": "switchToTsvFeedFormMainInputs",
31
+ "997": "switchToTxtFeedFormMainInputs",
32
+ "998": "switchToCsvFeedFormMainInputs",
33
+ "999": "switchToFeedFormMainInputs"
34
+ };
35
+ if (c.hasOwnProperty(b)) {
36
+ window[c[b]](a, b)
37
+ }
38
+ jQuery("#update-schedule-row").show();
39
+ jQuery("#add-product-variations-row").show();
40
+ if ((null === jQuery("#lvl_0").val() && "" === jQuery("#selected-categories").html()) || 0 === jQuery("#tvc-countries-selector").val()) {
41
+ tvc_show_or_hide_category_map(b)
42
+ } else {
43
+ jQuery("#tvc-category-map").show()
44
+ }
45
+ }
46
+
47
+ function tvc_show_or_hide_category_map(b) {
48
+ var a = jQuery("#tvc-category-map");
49
+ switch (b) {
50
+ case"15":
51
+ case"17":
52
+ case"18":
53
+ case"22":
54
+ case"23":
55
+ case"25":
56
+ case"26":
57
+ case"27":
58
+ case"28":
59
+ a.show();
60
+ break;
61
+ default:
62
+ a.hide();
63
+ break
64
+ }
65
+ }
66
+
67
+ function tvc_category_separator(a) {
68
+ switch (a) {
69
+ case"14":
70
+ case"24":
71
+ return " | ";
72
+ default:
73
+ return " > "
74
+ }
75
+ }
76
+
77
+ function tvc_reactOnChannelInputChanged(d, b, g) {
78
+ var f = "";
79
+ var c = tvc_getUrlVariable("tab");
80
+ if ("product-feed" === c) {
81
+ var e = {
82
+ "1": "googleInputChanged",
83
+ "2": "bingInputChanged",
84
+ "3": "beslisInputChanged",
85
+ "4": "pricegrabberInputChanged",
86
+ "5": "shoppingInputChanged",
87
+ "6": "amazonInputChanged",
88
+ "7": "connexityInputChanged",
89
+ "9": "nextagInputChanged",
90
+ "10": "kieskeurigInputChanged",
91
+ "11": "vergelijkInputChanged",
92
+ "12": "koopjespakkerInputChanged",
93
+ "13": "avantlinkInputChanged",
94
+ "14": "zboziInputChanged",
95
+ "15": "comconInputChanged",
96
+ "16": "facebookInputChanged",
97
+ "17": "bolInputChanged",
98
+ "18": "adtractionInputChanged",
99
+ "19": "ricardoInputChanged",
100
+ "20": "ebayInputChanged",
101
+ "21": "shopzillaInputChanged",
102
+ "22": "convertoInputChanged",
103
+ "23": "idealoInputChanged",
104
+ "24": "heurekaInputChanged",
105
+ "25": "pepperjamInputChanged",
106
+ "26": "galaxusProductDataInputChanged",
107
+ "27": "galaxusProductStockPricingInputChanged",
108
+ "28": "galaxusProductPropertiesInputChanged",
109
+ "996": "TsvInputChanged",
110
+ "997": "TxtInputChanged",
111
+ "998": "CsvInputChanged",
112
+ "999": "InputChanged"
113
+ };
114
+ f = e[d]
115
+ } else {
116
+ var a = tvc_convertToCamelCase(c.split("-"));
117
+ f = a + "Changed"
118
+ }
119
+ if (f) {
120
+ window[f](b, g)
121
+ }
122
+ }
123
+
124
+ function tvc_getChannelFeedType(a) {
125
+ switch (a) {
126
+ case"2":
127
+ case"4":
128
+ case"6":
129
+ case"7":
130
+ case"9":
131
+ case"12":
132
+ case"21":
133
+ case"25":
134
+ case"997":
135
+ return "txt";
136
+ case"15":
137
+ case"17":
138
+ case"19":
139
+ case"22":
140
+ case"23":
141
+ case"26":
142
+ case"27":
143
+ case"28":
144
+ case"998":
145
+ return "csv";
146
+ case"996":
147
+ return "tsv";
148
+ default:
149
+ return "xml"
150
+ }
151
+ }
152
+
153
+ function tvc_channelCountryCode(a) {
154
+ var b = "en-US";
155
+ switch (a) {
156
+ case"3":
157
+ case"10":
158
+ case"11":
159
+ case"12":
160
+ case"17":
161
+ b = "nl-NL";
162
+ break;
163
+ case"14":
164
+ case"24":
165
+ b = "cs-CZ";
166
+ break;
167
+ case"19":
168
+ b = "de-CH";
169
+ break;
170
+ case"23":
171
+ b = "de-DE";
172
+ break
173
+ }
174
+ return b
175
+ }
176
+
177
+ function tvc_channelUsesOwnCategories(a) {
178
+ switch (a) {
179
+ case"10":
180
+ case"15":
181
+ case"17":
182
+ case"18":
183
+ case"22":
184
+ case"23":
185
+ case"25":
186
+ case"26":
187
+ case"27":
188
+ case"28":
189
+ return true;
190
+ default:
191
+ return false
192
+ }
193
+ }
194
+
195
+ function tvc_fillCategoryVariables(b, d, a) {
196
+ var c = {
197
+ "1": "fillGoogleCategoryVariables",
198
+ "4": "fillPricegrabberCategoryVariables",
199
+ "5": "fillShoppingCategoryVariables",
200
+ "6": "fillAmazonCategoryVariables",
201
+ "7": "fillConnexityCategoryVariables",
202
+ "9": "fillNextagCategoryVariables",
203
+ "13": "fillAvantLinkCategoryVariables",
204
+ "14": "fillZboziCategoryVariables"
205
+ };
206
+ if (c.hasOwnProperty(b)) {
207
+ window[c[b]](d, a)
208
+ }
209
+ }
210
+
211
+ function tvc_displayCorrectStaticField(f, e, g, d, h, c) {
212
+ var b = "";
213
+ var a = tvc_restrictedStaticFields(d, h);
214
+ if (a !== undefined) {
215
+ if (a.length === 0) {
216
+ b = tvc_staticInputField(f, e, g, c)
217
+ } else {
218
+ b = tvc_staticInputSelect(f, e, g, a, c)
219
+ }
220
+ }
221
+ return b
222
+ }
223
+
224
+ function tvc_getAdvisedInputs(a) {
225
+ var b = {
226
+ "1": "woocommerceToGoogleFields",
227
+ "2": "woocommerceToBingFields",
228
+ "3": "woocommerceToBeslisFields",
229
+ "4": "woocommerceToPricegrabberFields",
230
+ "5": "woocommerceToShoppingFields",
231
+ "6": "woocommerceToAmazonFields",
232
+ "7": "woocommerceToConnexityFields",
233
+ "9": "woocommerceToNextagFields",
234
+ "10": "woocommerceToKieskeurigFields",
235
+ "11": "woocommerceToVergelijkFields",
236
+ "12": "woocommerceToKoopjespakkerFields",
237
+ "13": "woocommerceToAvantLinkFields",
238
+ "14": "woocommerceToZboziFields",
239
+ "15": "woocommerceToComconFields",
240
+ "16": "woocommerceToFacebookFields",
241
+ "17": "woocommerceToBolFields",
242
+ "18": "woocommerceToAdtractionFields",
243
+ "19": "woocommerceToRicardoFields",
244
+ "20": "woocommerceToeBayFields",
245
+ "21": "woocommerceToShopzillaFields",
246
+ "22": "woocommerceToConvertoFields",
247
+ "23": "woocommerceToIdealoFields",
248
+ "24": "woocommerceToHeurekaFields",
249
+ "25": "woocommerceToPepperjamFields",
250
+ "26": "woocommerceToGalaxusProductDataFields",
251
+ "27": "woocommerceToGalaxusProductStockPricingFields",
252
+ "28": "woocommerceToGalaxusProductPropertiesFields"
253
+ };
254
+ if (b.hasOwnProperty(a)) {
255
+ return window[b[a]]()
256
+ } else {
257
+ return []
258
+ }
259
+ }
260
+
261
+ function tvc_setOutputAttributeLevels(b, c, a) {
262
+ switch (b) {
263
+ case"1":
264
+ return setGoogleOutputAttributeLevels(c, a);
265
+ case"2":
266
+ return setBingOutputAttributeLevels(c);
267
+ case"3":
268
+ return setBeslisOutputAttributeLevels(c);
269
+ case"4":
270
+ return setPricegrabberOutputAttributeLevels(c);
271
+ case"5":
272
+ return setShoppingOutputAttributeLevels(c);
273
+ case"6":
274
+ return setAmazonOutputAttributeLevels(c);
275
+ case"7":
276
+ return setConnexityOutputAttributeLevels(c);
277
+ case"9":
278
+ return setNextagOutputAttributeLevels(c);
279
+ case"10":
280
+ return setKieskeurigOutputAttributeLevels(c);
281
+ case"11":
282
+ return setVergelijkOutputAttributeLevels(c);
283
+ case"13":
284
+ return setAvantLinkOutputAttributeLevels(c, a);
285
+ case"14":
286
+ return setZboziOutputAttributeLevels(c, a);
287
+ case"26":
288
+ return setGalaxusProductDataAttributeLevels(c, a);
289
+ case"27":
290
+ return setGalaxusProductStockPricingAttributeLevels(c);
291
+ case"28":
292
+ return setGalaxusProductPropertiesAttributeLevels(c);
293
+ case"996":
294
+ return setTsvOutputAttributeLevels(c);
295
+ case"997":
296
+ return setTxtOutputAttributeLevels(c);
297
+ case"998":
298
+ return setCsvOutputAttributeLevels(c);
299
+ case"999":
300
+ return setOutputAttributeLevels(c);
301
+ default:
302
+ return c
303
+ }
304
+ }
305
+
306
+ function tvc_restrictedStaticFields(a, c) {
307
+ var b = {
308
+ "1": "googleStaticFieldOptions",
309
+ "2": "bingStaticFieldOptions",
310
+ "3": "beslisStaticFieldOptions",
311
+ "4": "pricegrabberStaticFieldOptions",
312
+ "5": "shoppingStaticFieldOptions",
313
+ "6": "amazonStaticFieldOptions",
314
+ "7": "connexityStaticFieldOptions",
315
+ "9": "nextagStaticFieldOptions",
316
+ "10": "kieskeurigStaticFieldOptions",
317
+ "11": "vergelijkStaticFieldOptions",
318
+ "12": "koopjespakkerStaticFieldOptions",
319
+ "13": "avantlinkStaticFieldOptions",
320
+ "14": "zboziStaticFieldOptions",
321
+ "15": "comconStaticFieldOptions",
322
+ "16": "facebookStaticFieldOptions",
323
+ "17": "bolStaticFieldOptions",
324
+ "18": "adtractionStaticFieldOptions",
325
+ "19": "ricardoStaticFieldOptions",
326
+ "20": "ebayStaticFieldOptions",
327
+ "21": "shopzillaStaticFieldOptions",
328
+ "23": "idealoStaticFieldOptions",
329
+ "25": "pepperjamStaticFieldOptions",
330
+ "26": "galaxusProductDataStaticFieldOptions",
331
+ "27": "galaxusProductStockPricingStaticFieldOptions",
332
+ "28": "galaxusProductPropertiesStaticFieldOptions"
333
+ };
334
+ if (b.hasOwnProperty(a)) {
335
+ return window[b[a]](c)
336
+ } else {
337
+ return []
338
+ }
339
+ }
340
+
341
+ function tvc_setChannelRelatedPresets(a, b) {
342
+ switch (b) {
343
+ case"1":
344
+ if (a.field_label === "condition" || a.field_label === "availability" || a.field_label === "identifier_exists" || a.field_label === "adult" || a.field_label === "price") {
345
+ if (!a.value) {
346
+ a.value = setGooglePresets(a.field_label)
347
+ }
348
+ }
349
+ break;
350
+ case"2":
351
+ if (a.field_label === "seller_name") {
352
+ if (!a.value) {
353
+ a.value = setBingPresets(a.field_label)
354
+ }
355
+ }
356
+ break;
357
+ case"3":
358
+ if (a.field_label === "Conditie" || a.field_label === "Levertijd") {
359
+ if (!a.value) {
360
+ a.value = setBeslisPresets(a.field_label)
361
+ }
362
+ }
363
+ break;
364
+ case"13":
365
+ if (a.field_label === "condition" || a.field_label === "availability" || a.field_label === "identifier_exists") {
366
+ if (!a.value) {
367
+ a.value = setAvantLinkPresets(a.field_label)
368
+ }
369
+ }
370
+ break;
371
+ case"14":
372
+ if (a.field_label === "EROTIC" || a.field_label === "VISIBILITY") {
373
+ if (!a.value) {
374
+ a.value = setZboziPresets(a.field_label)
375
+ }
376
+ }
377
+ break;
378
+ case"15":
379
+ if (a.field_label === "Delivery time") {
380
+ if (!a.value) {
381
+ a.value = setComconPresets(a.field_label)
382
+ }
383
+ }
384
+ break;
385
+ case"16":
386
+ if (a.field_label === "condition" || a.field_label === "availability" || a.field_label === "price") {
387
+ if (!a.value) {
388
+ a.value = setFacebookPresets(a.field_label)
389
+ }
390
+ }
391
+ break;
392
+ case"17":
393
+ if (a.field_label === "Condition" || a.field_label === "Deliverycode") {
394
+ if (!a.value) {
395
+ a.value = setBolPresets(a.field_label)
396
+ }
397
+ }
398
+ break;
399
+ case"18":
400
+ if (a.field_label === "instock") {
401
+ if (!a.value) {
402
+ a.value = setAdtractionPresets(a.field_label)
403
+ }
404
+ }
405
+ break;
406
+ case"19":
407
+ if (a.field_label === "Descriptions[0].LanguageNr" || a.field_label === "Increment" || a.field_label === "AvailabilityId" || a.field_label === "Condition") {
408
+ if (!a.value) {
409
+ a.value = setRicardoPresets(a.field_label)
410
+ }
411
+ }
412
+ break;
413
+ case"20":
414
+ break;
415
+ case"21":
416
+ if (a.field_label === "Availability" || a.field_label === "Condition") {
417
+ if (!a.value) {
418
+ a.value = setShopzillaPresets(a.field_label)
419
+ }
420
+ }
421
+ break;
422
+ case"22":
423
+ if (a.field_label === "Availability" || a.field_label === "Condition") {
424
+ if (!a.value) {
425
+ a.value = setShopzillaPresets(a.field_label)
426
+ }
427
+ }
428
+ break;
429
+ case"24":
430
+ if ("ITEM_TYPE" === a.field_label) {
431
+ if (!a.value) {
432
+ a.value = setHeurekaPresets(a.field_label)
433
+ }
434
+ }
435
+ break;
436
+ case"25":
437
+ if ("ITEM_TYPE" === a.discontinued) {
438
+ if (!a.value) {
439
+ a.value = setPepperjamPresets(a.field_label)
440
+ }
441
+ }
442
+ break;
443
+ case"26":
444
+ if ("ITEM_TYPE" === a.discontinued) {
445
+ if (!a.value) {
446
+ a.value = setGalaxusProductDataPresets(a.field_label)
447
+ }
448
+ }
449
+ break;
450
+ case"27":
451
+ if ("ITEM_TYPE" === a.discontinued) {
452
+ if (!a.value) {
453
+ a.value = setGalaxusProductStockPricingPresets(a.field_label)
454
+ }
455
+ }
456
+ break;
457
+ case"28":
458
+ if ("ITEM_TYPE" === a.discontinued) {
459
+ if (!a.value) {
460
+ a.value = setGalaxusProductPropertiesPresets(a.field_label)
461
+ }
462
+ }
463
+ break;
464
+ default:
465
+ break
466
+ }
467
+ }
468
+
469
+ function tvc_requiresLanguageInput(a) {
470
+ switch (a) {
471
+ case"26":
472
+ return true;
473
+ default:
474
+ return false
475
+ }
476
+ }
477
+
478
+ function tvc_isCustomChannel(a) {
479
+ switch (a) {
480
+ case"996":
481
+ case"997":
482
+ case"998":
483
+ case"999":
484
+ return true;
485
+ default:
486
+ return false
487
+ }
488
+ }
489
+
490
+ function setAttributeStatus(b, a) {
491
+ if (b > 0 && b < 3) {
492
+ return true
493
+ }
494
+ if (a) {
495
+ return true
496
+ }
497
+ return false
498
+ };
includes/application/js/tvc_feedhandling.js ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var _feedHolder;
3
+
4
+ function tvc_getFeedAttributes( feedId, channel, callback ) {
5
+ tvc_getOutputFields(
6
+ feedId,
7
+ channel,
8
+ function( fields ) {
9
+ if ( fields !== '0' ) {
10
+ callback( JSON.parse( fields ) );
11
+ } else {
12
+ callback( [] ); // free feed format selected
13
+ }
14
+ }
15
+ );
16
+ }
17
+
18
+ function tvc_customSourceFields( sourceId, callback ) {
19
+ tvc_getSourceFields(
20
+ sourceId,
21
+ function( fields ) {
22
+ callback( fields && fields !== '0' ? JSON.parse( fields ) : '0' );
23
+ }
24
+ );
25
+ }
26
+
27
+ function tvc_mainFeedFilters( feedId, callback ) {
28
+
29
+ tvc_getMainFeedFilters(
30
+ feedId,
31
+ function( filters ) {
32
+ callback( filters !== '0' ? JSON.parse( filters ) : null );
33
+ }
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Fills the attributes of the current _feed object with data from the outputs var
39
+ *
40
+ * @param {array} outputs containing output strings outputs
41
+ * @param {string} channel id
42
+ * @param {int} source id
43
+ */
44
+ function tvc_addFeedAttributes( outputs, channel, source ) {
45
+
46
+ var inputs = tvc_getAdvisedInputs( channel );
47
+ var i = 0;
48
+
49
+ _feedHolder.clearAllAttributes();
50
+
51
+ for ( var field in outputs ) {
52
+
53
+ var outputTitle = outputs[ field ][ 'field_label' ];
54
+ var activity = true;
55
+
56
+ /**
57
+ * deactivate if this attribute is not required and has no value
58
+ */
59
+ if ( parseInt( outputs[ field ][ 'category_id' ] ) > 2 && outputs[ field ][ 'value' ] === '' ) {
60
+ activity = false;
61
+ } else if ( outputs[ field ][ 'category_id' ] === '0' ) {
62
+ activity = false;
63
+ } else if ( parseInt( outputs[ field ][ 'category_id' ] ) > 2 && outputs[ field ][ 'value' ] === undefined ) {
64
+ activity = false;
65
+ }
66
+
67
+ tvc_setChannelRelatedPresets( outputs[ field ], channel );
68
+
69
+ _feedHolder.addAttribute( i, outputTitle, inputs[ outputTitle ], outputs[ field ][ 'value' ], outputs[ field ][ 'category_id' ], activity, 0, 0, 0 );
70
+
71
+ i ++;
72
+ }
73
+ }
74
+
75
+ function tvc_saveFeedToDb( feed, callback ) {
76
+
77
+ /**
78
+ * store the feed in a local variable
79
+ */
80
+ _feedHolder = feed;
81
+
82
+ var feedDataSelectorTable = jQuery( '#tvc-ajax-feed-data-to-database-conversion-array' ).text(); // get the data from the edit feed form code
83
+ var feedDataToStore = tvc_getFeedDataToStore( feedDataSelectorTable );
84
+ var metaToStore = tvc_filterActiveMetaData( _feedHolder[ 'attributes' ], _feedHolder[ 'categoryMapping' ] );
85
+ var feedFilter = _feedHolder[ 'feedFilter' ];
86
+
87
+ tvc_updateFeedToDb(
88
+ feedDataToStore,
89
+ metaToStore,
90
+ feedFilter,
91
+ function( response ) {
92
+ callback( response.trim() );
93
+ }
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Gets the full metaData array from the _feedHolder and returns a tvc_attributeMeta object with keys and values from only the active ones.
99
+ * Also stores the category mapping array in a tvc_attributeMeta object.
100
+ *
101
+ * @param {Array} metaData
102
+ * @param {Array} categoryMapping
103
+ * @returns {Array} array with tvc_attributeMeta objects containing meta keys and meta values
104
+ */
105
+ function tvc_filterActiveMetaData( metaData, categoryMapping ) {
106
+
107
+ // make a storage place to store the changed attributes
108
+ var activeMeta = [];
109
+
110
+ for ( var i = 0; i < metaData.length; i ++ ) {
111
+
112
+ // if the advised source is not equal to the advised inputs, the user has selected his own input so this needs to be stored
113
+ if ( metaData[ i ][ 'value' ] !== undefined && metaData[ i ][ 'value' ] !== '' && metaData[ i ][ 'isActive' ] === true ) {
114
+
115
+ // store the meta data in a Tvc_AttributeMeta object
116
+ activeMeta.push( new Tvc_AttributeMeta( metaData[ i ][ 'fieldName' ], metaData[ i ][ 'value' ] ) );
117
+ }
118
+ }
119
+
120
+ // also store the category mapping as meta data
121
+ if ( categoryMapping.length > 0 ) {
122
+
123
+ activeMeta.push( new Tvc_AttributeMeta( 'category_mapping', categoryMapping ) );
124
+ }
125
+
126
+ return activeMeta;
127
+ }
128
+
129
+ function tvc_getFeedDataToStore( feedDataSelector ) {
130
+ var selector = JSON.parse( feedDataSelector );
131
+ var result = [];
132
+
133
+ for (var i = 0; i < selector.length; i++) {
134
+ var dataItem = {
135
+ 'name' : selector[i]['db'],
136
+ 'value' : undefined !== _feedHolder[ selector[i]['feed'] ] ? _feedHolder[ selector[i]['feed'] ] : '',
137
+ 'type' : selector[i]['type']
138
+ };
139
+
140
+ result.push( dataItem );
141
+ }
142
+
143
+ return result;
144
+ }
includes/application/js/tvc_feedhandling.min.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var _feedHolder;
2
+
3
+ function tvc_getFeedAttributes(a, b, c) {
4
+ tvc_getOutputFields(a, b, function (d) {
5
+ if (d !== "0") {
6
+ c(JSON.parse(d))
7
+ } else {
8
+ c([])
9
+ }
10
+ })
11
+ }
12
+
13
+ function tvc_customSourceFields(a, b) {
14
+ tvc_getSourceFields(a, function (c) {
15
+ b(c && c !== "0" ? JSON.parse(c) : "0")
16
+ })
17
+ }
18
+
19
+ function tvc_mainFeedFilters(a, b) {
20
+ tvc_getMainFeedFilters(a, function (c) {
21
+ b(c !== "0" ? JSON.parse(c) : null)
22
+ })
23
+ }
24
+
25
+ function tvc_addFeedAttributes(h, d, e) {
26
+ var a = tvc_getAdvisedInputs(d);
27
+ var c = 0;
28
+ _feedHolder.clearAllAttributes();
29
+ for (var g in h) {
30
+ var b = h[g]["field_label"];
31
+ var f = true;
32
+ if (parseInt(h[g]["category_id"]) > 2 && h[g]["value"] === "") {
33
+ f = false
34
+ } else {
35
+ if (h[g]["category_id"] === "0") {
36
+ f = false
37
+ } else {
38
+ if (parseInt(h[g]["category_id"]) > 2 && h[g]["value"] === undefined) {
39
+ f = false
40
+ }
41
+ }
42
+ }
43
+ tvc_setChannelRelatedPresets(h[g], d);
44
+ _feedHolder.addAttribute(c, b, a[b], h[g]["value"], h[g]["category_id"], f, 0, 0, 0);
45
+ c++
46
+ }
47
+ }
48
+
49
+ function tvc_saveFeedToDb(d, f) {
50
+ _feedHolder = d;
51
+ var c = jQuery("#tvc-ajax-feed-data-to-database-conversion-array").text();
52
+ var a = tvc_getFeedDataToStore(c);
53
+ var b = tvc_filterActiveMetaData(_feedHolder.attributes, _feedHolder.categoryMapping);
54
+ var e = _feedHolder.feedFilter;
55
+ tvc_updateFeedToDb(a, b, e, function (g) {
56
+ f(g.trim())
57
+ })
58
+ }
59
+
60
+ function tvc_filterActiveMetaData(b, d) {
61
+ var a = [];
62
+ for (var c = 0; c < b.length; c++) {
63
+ if (b[c]["value"] !== undefined && b[c]["value"] !== "" && b[c]["isActive"] === true) {
64
+ a.push(new Tvc_AttributeMeta(b[c]["fieldName"], b[c]["value"]))
65
+ }
66
+ }
67
+ if (d.length > 0) {
68
+ a.push(new Tvc_AttributeMeta("category_mapping", d))
69
+ }
70
+ return a
71
+ }
72
+
73
+ function tvc_getFeedDataToStore(e) {
74
+ var b = JSON.parse(e);
75
+ var a = [];
76
+ for (var d = 0; d < b.length; d++) {
77
+ var c = {
78
+ name: b[d]["db"],
79
+ value: undefined !== _feedHolder[b[d]["feed"]] ? _feedHolder[b[d]["feed"]] : "",
80
+ type: b[d]["type"]
81
+ };
82
+ a.push(c)
83
+ }
84
+ return a
85
+ };
includes/application/js/tvc_general-functions.js ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ /**
3
+ * Finds the index of an object with a specific value in an array of objects
4
+ *
5
+ * @param {array} theArray with objects
6
+ * @param {string} searchTerm
7
+ * @param {string} arrayProperty
8
+ * @returns {int} the index of the object or false of its not in the array
9
+ */
10
+ function tvc_arrayObjectIndexOf( theArray, searchTerm, arrayProperty ) {
11
+ for ( var i = 0, len = theArray.length; i < len; i ++ ) {
12
+ if ( theArray[ i ][ arrayProperty ] === searchTerm ) {
13
+ return i; // return the index
14
+ }
15
+ }
16
+
17
+ return - 1; // return false if object could not be found
18
+ }
19
+
20
+ /**
21
+ * Get a specific variable from the current url
22
+ *
23
+ * @param {string} key
24
+ * @returns {String}
25
+ */
26
+ function tvc_getUrlVariable( key ) {
27
+ var result = '';
28
+ var url = window.location.search.substring( 1 );
29
+ var params = url.split( '&' );
30
+
31
+ for ( var i = 0; i < params.length; i ++ ) {
32
+ var param = params[ i ].split( '=' );
33
+
34
+ if ( param[ 0 ] === key ) {
35
+ result = param[ 1 ];
36
+ }
37
+ }
38
+
39
+ return result;
40
+ }
41
+
42
+ /**
43
+ * Counts the number of items in an object
44
+ *
45
+ * @param {object} object
46
+ * @returns {int} number of items in object
47
+ */
48
+ function tvc_countObjectItems( object ) {
49
+ var count = 0;
50
+
51
+ for ( var k in object ) {
52
+ if ( object.hasOwnProperty( k ) ) {
53
+ count ++;
54
+ }
55
+ }
56
+
57
+ return count;
58
+ }
59
+
60
+ /**
61
+ * Returns true if the object is empty
62
+ *
63
+ * @param {object} object
64
+ * @returns {Boolean} true if object is empty
65
+ */
66
+ // TODO: Er bestaat ook een jQuery.isEmptyObject() functie. In hoeverre is die bruikbaar ter vervanging van onderstaande functie?
67
+ function tvc_isEmptyQueryObject( object ) {
68
+ // null and undefined are "empty"
69
+ if ( object === null ) {
70
+ return true;
71
+ }
72
+
73
+ // Assume if it has a length property with a non-zero value
74
+ // that that property is correct.
75
+ if ( object.length > 0 ) {
76
+ return false;
77
+ }
78
+ if ( object.length === 0 ) {
79
+ return true;
80
+ }
81
+
82
+ // Otherwise, does it have any properties of its own?
83
+ // Note that this doesn't handle
84
+ // toString and valueOf enumeration bugs in IE < 9
85
+ for ( var key in object ) {
86
+ //if ( hasOwnProperty.call( object, key ) )
87
+ if ( object.hasOwnProperty( key ) ) {
88
+ return false;
89
+ }
90
+ }
91
+ return true;
92
+ }
93
+
94
+ /**
95
+ * Takes a string with a number at the end and increments the number
96
+ *
97
+ * @param {String} stringWithNumber
98
+ * @returns {String} with incremented number
99
+ */
100
+ function tvc_incrementLast( stringWithNumber ) {
101
+ return stringWithNumber.replace( /[0-9]+(?!.*[0-9])/, parseInt( stringWithNumber.match( /[0-9]+(?!.*[0-9])/ ), 10 ) + 1 );
102
+ }
includes/application/js/tvc_general-functions.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function tvc_arrayObjectIndexOf(d,c,b){for(var e=0,a=d.length;e<a;e++){if(d[e][b]===c){return e}}return -1}function tvc_getUrlVariable(d){var a="";var b=window.location.search.substring(1);var f=b.split("&");for(var c=0;c<f.length;c++){var e=f[c].split("=");if(e[0]===d){a=e[1]}}return a}function tvc_countObjectItems(b){var c=0;for(var a in b){if(b.hasOwnProperty(a)){c++}}return c}function tvc_isEmptyQueryObject(a){if(a===null){return true}if(a.length>0){return false}if(a.length===0){return true}for(var b in a){if(a.hasOwnProperty(b)){return false}}return true}function tvc_incrementLast(a){return a.replace(/[0-9]+(?!.*[0-9])/,parseInt(a.match(/[0-9]+(?!.*[0-9])/),10)+1)};
includes/application/js/tvc_logic.js ADDED
@@ -0,0 +1,454 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ "use strict";
3
+ /*global tvc_feed_settings_form_vars, tvc_manage_channels_vars, tvc_feed_list_form_vars */
4
+ var _feedHolder;
5
+
6
+ function tvc_editCategories() {
7
+ var cat_lvl_selector = jQuery( '#category-selector-lvl' );
8
+
9
+ if ( ! tvc_isCustomChannel( _feedHolder[ 'channel' ] ) ) {
10
+ var currentCategories = _feedHolder[ 'mainCategory' ].split( ' > ' );
11
+ var cat_length = currentCategories.length;
12
+ var cat_selectors = jQuery( '#lvl_' + ( cat_length ) ).html() !== '' ? cat_length + 1 : cat_length;
13
+
14
+ jQuery( '#selected-categories' ).hide();
15
+ jQuery( '#lvl_0' ).prop( 'disabled', false );
16
+
17
+ for ( var i = 0; i < cat_selectors; i ++ ) {
18
+ var levelElement = jQuery( '#lvl_' + i );
19
+
20
+ if ( ! currentCategories[ i ] ) {
21
+ levelElement.val( '0' );
22
+ }
23
+ levelElement.show();
24
+ }
25
+ } else {
26
+ // as the user selected a free format, just show a text input control
27
+ cat_lvl_selector.html(
28
+ tvc_freeCategoryInputCntrl(
29
+ 'default',
30
+ _feedHolder[ 'feedId' ],
31
+ _feedHolder[ 'mainCategory' ]
32
+ )
33
+ );
34
+ cat_lvl_selector.prop( 'disabled', false );
35
+ }
36
+ }
37
+
38
+ function tvc_generateFeed() {
39
+ if ( jQuery( '#file-name' ).val() !== '' ) {
40
+ if ( _feedHolder[ 'categoryMapping' ] && _feedHolder[ 'categoryMapping' ].length > 0 ) {
41
+ disableFeedActionButtons();
42
+ tvc_generateAndSaveFeed();
43
+ } else {
44
+ var userInput = confirm(
45
+ tvc_feed_settings_form_vars.no_category_selected
46
+ );
47
+
48
+ if ( userInput === true ) {
49
+ disableFeedActionButtons();
50
+ tvc_generateAndSaveFeed();
51
+ }
52
+ }
53
+ } else {
54
+ jQuery( '#alert-message' ).
55
+ html( '<p>' + tvc_feed_settings_form_vars.file_name_required + '</p>' );
56
+ jQuery( '#success-message' ).show();
57
+ }
58
+ }
59
+
60
+ function tvc_saveFeedData() {
61
+ if ( jQuery( '#file-name' ).val() !== '' ) {
62
+ tvc_saveFeed();
63
+ } else {
64
+ jQuery( '#alert-message' ).
65
+ html( '<p>' + tvc_feed_settings_form_vars.file_name_required + '</p>' );
66
+ jQuery( '#success-message' ).show();
67
+ }
68
+ }
69
+
70
+ function getCombinedValue( rowId, sourceLevel ) {
71
+ var c = 1;
72
+ var combinedValue = '';
73
+ var oldValue = _feedHolder.getCombinedOutputValue( rowId, sourceLevel );
74
+
75
+ while ( jQuery( '#combined-input-field-cntrl-' + rowId + '-' + sourceLevel + '-' + c ).
76
+ val() ) {
77
+ var idString = rowId + '-' + sourceLevel + '-' + c;
78
+
79
+ var selectedValue = jQuery( '#combined-input-field-cntrl-' + idString ).
80
+ val();
81
+
82
+ combinedValue += c > 1 ?
83
+ jQuery( '#combined-separator-cntrl-' + idString ).val() + '#' :
84
+ '';
85
+
86
+ if ( selectedValue !== 'static' ) {
87
+ combinedValue += selectedValue !== 'select' ?
88
+ selectedValue + '|' :
89
+ '';
90
+ } else if ( jQuery( '#static-input-field-' + idString ).val() ) {
91
+ combinedValue += selectedValue + '#' + jQuery( '#static-input-field-' + idString ).val() + '|';
92
+ } else {
93
+ combinedValue = oldValue + '|';
94
+ break; // if one of the static input fields is still empty, return the old value
95
+ }
96
+
97
+ c ++;
98
+ }
99
+
100
+ combinedValue = combinedValue.substring( 0, combinedValue.length - 1 ); // remove the last |
101
+
102
+ return c > 1 ? combinedValue : false; // need at least two fields to be valid
103
+ }
104
+
105
+ function tvc_staticValueChanged( id, level, combinationLevel ) {
106
+ if ( combinationLevel > 0 ) { // the static field resides in a combination source
107
+ tvc_changedCombinedOutput( id, level, combinationLevel );
108
+ } else {
109
+ // store the change in the feed
110
+ tvc_setStaticValue( id, level, combinationLevel );
111
+
112
+ // when the identifier_exists static value has changed, the level of a few attributes should be changed
113
+ if ( id === 34 ) {
114
+ tvc_setIdentifierExistsDependancies();
115
+ }
116
+ }
117
+ }
118
+
119
+ function tvc_changedOutputSelection( level ) {
120
+ var outputFieldControlElement = jQuery( '#output-field-cntrl-' + level );
121
+
122
+ if ( outputFieldControlElement.val() !== 'no-value' ) {
123
+ tvc_activateOptionalFieldRow( level, outputFieldControlElement.val() );
124
+ }
125
+ }
126
+
127
+ function tvc_hasExtraSourceRow( nrOfSources, value ) {
128
+ if ( value.length > 0 ) {
129
+ return value[ nrOfSources - 1 ].hasOwnProperty( 'c' );
130
+ } else {
131
+ return false;
132
+ }
133
+ }
134
+
135
+ function tvc_changedCustomOutputTitle() {
136
+ var title = jQuery( '#custom-output-title-input' ).val();
137
+
138
+ if ( title ) {
139
+ tvc_activateCustomFieldRow( title );
140
+ }
141
+ }
142
+
143
+ function tvc_deleteSpecificFeed( id, title ) {
144
+ var userInput = confirm( tvc_feed_list_form_vars.confirm_delete_feed.replace( '%feedname%', title ) );
145
+
146
+ if ( userInput === true ) {
147
+ tvc_deleteFeed( id, title );
148
+ console.log( 'File ' + title + ' removed from server.' );
149
+ tvc_show_success_message( tvc_feed_list_form_vars.feed_removed.replace( '%feedname%', title ) );
150
+ parent.location='admin.php?page=tvc-product-feed-manager&tab=feed-list';
151
+ }
152
+ }
153
+
154
+ function tvc_alertRemoveChannel() {
155
+ var userInput = confirm( tvc_manage_channels_vars.confirm_removing_channel );
156
+ if ( true !== userInput ) {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ function tvc_valueOptionChanged( rowId, sourceLevel, valueEditorLevel ) {
162
+ var type = jQuery( '#value-options-' + rowId + '-' + sourceLevel + '-' + valueEditorLevel ).val();
163
+
164
+ //var selectorCode = tvc_getCorrectValueSelector( rowId, sourceLevel, valueEditorLevel, type, '', '' );
165
+ var selectorCode = tvc_getCorrectValueSelector( rowId, sourceLevel, 0, type, '', '' );
166
+
167
+ jQuery( '#value-editor-input-span-' + rowId + '-' + sourceLevel + '-' + valueEditorLevel ).html( selectorCode );
168
+ }
169
+
170
+ function tvc_getCorrectValueSelector(
171
+ rowId, sourceLevel, valueEditorLevel, type, value, endValue ) {
172
+ var selectorCode = '';
173
+
174
+ // TODO: the type is now based on the value and on the text. Should be only value as this makes it
175
+ // easier to work with different languages
176
+ switch ( type ) {
177
+ case '0':
178
+ case 'change nothing':
179
+ tvc_valueInputOptionsChanged( rowId, sourceLevel, valueEditorLevel ); // save the value in meta as there is no input field required
180
+ selectorCode = '';
181
+ break;
182
+
183
+ case '1':
184
+ case 'overwrite':
185
+ selectorCode = tvc_valueOptionsSingleInput( rowId, sourceLevel, valueEditorLevel, value );
186
+ break;
187
+
188
+ case '2':
189
+ case 'replace':
190
+ selectorCode = tvc_valueOptionsReplaceInput( rowId, sourceLevel, valueEditorLevel, value, endValue );
191
+ break;
192
+
193
+ case '3':
194
+ case 'remove':
195
+ case '4':
196
+ case 'add prefix':
197
+ case '5':
198
+ case 'add suffix':
199
+ selectorCode = tvc_valueOptionsSingleInputValue( rowId, sourceLevel, valueEditorLevel, value );
200
+ break;
201
+
202
+ case '6':
203
+ case 'recalculate':
204
+ selectorCode = tvc_valueOptionsRecalculate( rowId, sourceLevel, valueEditorLevel, value, endValue );
205
+ break;
206
+
207
+ case '7':
208
+ case 'convert to child-element':
209
+ selectorCode = tvc_valueOptionsElementInput( rowId, sourceLevel, valueEditorLevel, value );
210
+ break;
211
+
212
+ default:
213
+ selectorCode = tvc_valueOptionsSingleInput( rowId, sourceLevel, valueEditorLevel, value );
214
+ break;
215
+ }
216
+
217
+ return selectorCode;
218
+ }
219
+
220
+ function tvc_deactivateFeed( id ) {
221
+ tvc_switchFeedStatus(
222
+ id,
223
+ function( result ) {
224
+ tvc_updateFeedRowStatus( id, parseInt( result ) );
225
+ }
226
+ );
227
+ }
228
+
229
+ function tvc_duplicateFeed( id, feedName ) {
230
+ tvc_duplicateExistingFeed(
231
+ id,
232
+ function( result ) {
233
+ if ( result ) {
234
+ tvc_show_success_message( tvc_feed_list_form_vars.added_feed_copy.replace( '%feedname%', feedName ) );
235
+ }
236
+ }
237
+ );
238
+ }
239
+
240
+ function tvc_regenerateFeed( feedId ) {
241
+ // when there's already a feed processing, then the status should be "in queue", else status should set to "processing"
242
+ var feedStatus = tvcQueueStringIsEmpty() ? 3 : 4;
243
+
244
+ tvcAddToQueueString( feedId );
245
+
246
+ tvc_showFeedSpinner();
247
+
248
+ tvc_updateFeedRowStatus( feedId, feedStatus );
249
+
250
+ console.log( 'Started regenerating feed ' + feedId );
251
+
252
+ tvc_updateFeedFile( feedId, function( xmlResult ) {
253
+
254
+ tvc_hideFeedSpinner();
255
+
256
+ console.log(xmlResult);
257
+
258
+ // activate the feed list status checker to update the feed list when a status changes
259
+ var checkStatus = setInterval( function(){
260
+ tvc_getCurrentFeedStatus( feedId, function( statResult ) {
261
+ var data = JSON.parse( statResult );
262
+ if ('3' !== data[ 'status_id' ] && '4' !== data[ 'status_id' ]) {
263
+ console.log( data );
264
+ tvc_resetFeedStatus( data );
265
+ tvc_resetFeedList();
266
+ clearInterval( checkStatus );
267
+ tvcRemoveFromQueueString( feedId );
268
+ }
269
+ } );
270
+ }, 10000 );
271
+ })
272
+ }
273
+
274
+ function tvc_viewFeed( url ) {
275
+ if ( -1 !== url.indexOf( 'http' ) ) { // Filter out duplicate feeds that have not been generated yet.
276
+ window.open(url);
277
+ } else {
278
+ alert( tvc_feed_list_form_vars.feed_not_generated );
279
+ }
280
+ }
281
+
282
+ function tvc_addRowValueEditor(
283
+ rowId, sourceLevel, valueEditorLevel, values ) {
284
+ // add the change values controls
285
+ jQuery( '#end-row-id-' + rowId ).remove();
286
+ jQuery( '#row-' + rowId ).
287
+ append( tvc_valueEditor( rowId, sourceLevel, valueEditorLevel, values ) + tvc_endrow( rowId ) );
288
+
289
+ // and remove the edit values control
290
+ jQuery( '#value-editor-input-query-add-span-' + rowId + '-' + sourceLevel + '-' + valueEditorLevel ).remove();
291
+ }
292
+
293
+ /**
294
+ * Takes an array of words and puts them together in a camel structure way.
295
+ *
296
+ * @param {array} stringArray contains the words from which the string should be generated
297
+ *
298
+ * @returns {string} camel structured string
299
+ */
300
+ function tvc_convertToCamelCase( stringArray ) {
301
+ // first word should remain lowercase
302
+ var result = stringArray[ 0 ].toLowerCase();
303
+
304
+ for ( var i = 1; i < stringArray.length; i++ ) {
305
+ result += stringArray[ i ].charAt( 0 ).toUpperCase() + stringArray[ i ].slice( 1 );
306
+ }
307
+
308
+ return result;
309
+ }
310
+
311
+ function tvc_addValueEditorQuery( rowId, sourceLevel, conditionLevel ) {
312
+ if ( tvc_changeValueIsFilled( rowId, sourceLevel, conditionLevel ) ) {
313
+ if ( tvc_queryIsFilled(
314
+ rowId,
315
+ (
316
+ sourceLevel - 1
317
+ ),
318
+ 1
319
+ )
320
+ ) {
321
+ tvc_showEditValueQuery( rowId, sourceLevel, conditionLevel, true );
322
+ } else {
323
+ alert( tvc_feed_settings_form_vars.query_requirements );
324
+ }
325
+ } else {
326
+ alert( tvc_feed_settings_form_vars.first_fill_in_change_value );
327
+ }
328
+ }
329
+
330
+ function tvc_queryStringToQueryObject( queryString ) {
331
+ var queryObject = {};
332
+
333
+ if ( queryString ) {
334
+ for ( var key in queryString ) {
335
+ queryObject = tvc_convertQueryStringToQueryObject( queryString[ key ] );
336
+ }
337
+ }
338
+
339
+ return queryObject;
340
+ }
341
+
342
+ function tvc_valueStringToValueObject( valueString ) {
343
+ var valueObject = {};
344
+
345
+ if ( valueString ) {
346
+ for ( var key in valueString ) {
347
+ // do not process the query part of the string
348
+ if ( key !== 'q' ) {
349
+ valueObject = tvc_convertValueStringToValueObject( valueString[ key ] );
350
+ }
351
+ }
352
+ }
353
+
354
+ return valueObject;
355
+ }
356
+
357
+ function tvc_convertQueryStringToQueryObject( queryString ) {
358
+ var queryObject = {};
359
+
360
+ var stringSplit = queryString.split( '#' );
361
+
362
+ if ( stringSplit[ 0 ] === '1' || stringSplit[ 0 ] === '2' ) {
363
+ queryObject.preCondition = stringSplit[ 0 ];
364
+ } else {
365
+ queryObject.preCondition = '0';
366
+ }
367
+
368
+ queryObject.source = stringSplit[ 1 ];
369
+ queryObject.condition = stringSplit[ 2 ];
370
+ queryObject.value = stringSplit[ 3 ] ? stringSplit[ 3 ] : '';
371
+ queryObject.endValue = stringSplit[ 5 ] ? stringSplit[ 5 ] : '';
372
+
373
+ return queryObject;
374
+ }
375
+
376
+ function tvc_resortObject( object ) {
377
+ var result = [];
378
+ var i = 1;
379
+
380
+ // re-sort the conditions
381
+ for ( var element in object ) {
382
+ var o = {};
383
+ for ( var key in object[ element ] ) {
384
+ if ( key !== 'q' ) { // exclude q as key
385
+ o[ i ] = object[ element ][ key ];
386
+ result.push( o );
387
+ } else {
388
+ result[ i - 1 ].q = object[ element ][ key ];
389
+ }
390
+ }
391
+
392
+ i ++;
393
+ }
394
+
395
+ // don't return an empty {} string
396
+ return i > 1 ? result : '';
397
+ }
398
+
399
+ function tvc_convertValueStringToValueObject( valueString ) {
400
+ var valueObject = {};
401
+ var valueSplit = valueString.split( '#' );
402
+
403
+ valueObject.preCondition = valueSplit[ 0 ];
404
+ valueObject.condition = valueSplit[ 1 ];
405
+ valueObject.value = valueSplit[ 2 ];
406
+ valueObject.endValue = valueSplit[ 3 ] ? valueSplit[ 3 ] : '';
407
+
408
+ return valueObject;
409
+ }
410
+
411
+ function tvc_makeCleanQueryObject() {
412
+ var queryObject = {};
413
+
414
+ queryObject.preCondition = 'if';
415
+ queryObject.source = 'select';
416
+ queryObject.condition = '';
417
+ queryObject.value = '';
418
+ queryObject.endValue = '';
419
+
420
+ return queryObject;
421
+ }
422
+
423
+ function tvc_makeCleanValueObject() {
424
+ var valueObject = {};
425
+
426
+ valueObject.preCondition = 'change';
427
+ valueObject.condition = 'overwrite';
428
+ valueObject.value = '';
429
+ valueObject.endValue = '';
430
+
431
+ return valueObject;
432
+ }
433
+
434
+ function tvc_addNewItemToCategoryString(
435
+ level, oldString, newValue, separator ) {
436
+ var categoryLevel = oldString.split( separator ).length;
437
+
438
+ if ( oldString === tvc_feed_settings_form_vars.map_to_default_category || level === '0' ) {
439
+ return newValue;
440
+ } else {
441
+ if ( categoryLevel <= level ) {
442
+ return oldString + separator + newValue;
443
+ } else {
444
+ var pos = 0;
445
+
446
+ for ( var i = 0; i < level; i ++ ) {
447
+ pos = oldString.indexOf( separator, pos + 1 );
448
+ var oldPart = oldString.substring( 0, pos );
449
+ }
450
+
451
+ return oldPart + separator + newValue;
452
+ }
453
+ }
454
+ }
includes/application/js/tvc_logic.min.js ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var _feedHolder;
2
+
3
+ function tvc_editCategories() {
4
+ var d = jQuery("#category-selector-lvl");
5
+ if (!tvc_isCustomChannel(_feedHolder.channel)) {
6
+ var e = _feedHolder.mainCategory.split(" > ");
7
+ var c = e.length;
8
+ var a = jQuery("#lvl_" + (c)).html() !== "" ? c + 1 : c;
9
+ jQuery("#selected-categories").hide();
10
+ jQuery("#lvl_0").prop("disabled", false);
11
+ for (var b = 0; b < a; b++) {
12
+ var f = jQuery("#lvl_" + b);
13
+ if (!e[b]) {
14
+ f.val("0")
15
+ }
16
+ f.show()
17
+ }
18
+ } else {
19
+ d.html(tvc_freeCategoryInputCntrl("default", _feedHolder.feedId, _feedHolder.mainCategory));
20
+ d.prop("disabled", false)
21
+ }
22
+ }
23
+
24
+ function tvc_generateFeed() {
25
+ if (jQuery("#file-name").val() !== "") {
26
+ if (_feedHolder.categoryMapping && _feedHolder.categoryMapping.length > 0) {
27
+ disableFeedActionButtons();
28
+ tvc_generateAndSaveFeed();
29
+ } else {
30
+ var a = confirm(tvc_feed_settings_form_vars.no_category_selected);
31
+ if (a === true) {
32
+ disableFeedActionButtons();
33
+ tvc_generateAndSaveFeed();
34
+ }
35
+ }
36
+
37
+ } else {
38
+ jQuery("#alert-message").html("<p>" + tvc_feed_settings_form_vars.file_name_required + "</p>");
39
+ jQuery("#success-message").show()
40
+ }
41
+ }
42
+
43
+ function tvc_saveFeedData() {
44
+ if (jQuery("#file-name").val() !== "") {
45
+ tvc_saveFeed()
46
+ } else {
47
+ jQuery("#alert-message").html("<p>" + tvc_feed_settings_form_vars.file_name_required + "</p>");
48
+ jQuery("#success-message").show()
49
+ }
50
+ }
51
+
52
+ function getCombinedValue(g, f) {
53
+ var h = 1;
54
+ var b = "";
55
+ var d = _feedHolder.getCombinedOutputValue(g, f);
56
+ while (jQuery("#combined-input-field-cntrl-" + g + "-" + f + "-" + h).val()) {
57
+ var a = g + "-" + f + "-" + h;
58
+ var e = jQuery("#combined-input-field-cntrl-" + a).val();
59
+ b += h > 1 ? jQuery("#combined-separator-cntrl-" + a).val() + "#" : "";
60
+ if (e !== "static") {
61
+ b += e !== "select" ? e + "|" : ""
62
+ } else {
63
+ if (jQuery("#static-input-field-" + a).val()) {
64
+ b += e + "#" + jQuery("#static-input-field-" + a).val() + "|"
65
+ } else {
66
+ b = d + "|";
67
+ break
68
+ }
69
+ }
70
+ h++
71
+ }
72
+ b = b.substring(0, b.length - 1);
73
+ return h > 1 ? b : false
74
+ }
75
+
76
+ function tvc_staticValueChanged(c, b, a) {
77
+ if (a > 0) {
78
+ tvc_changedCombinedOutput(c, b, a)
79
+ } else {
80
+ tvc_setStaticValue(c, b, a);
81
+ if (c === 34) {
82
+ tvc_setIdentifierExistsDependancies()
83
+ }
84
+ }
85
+ }
86
+
87
+ function tvc_changedOutputSelection(b) {
88
+ var a = jQuery("#output-field-cntrl-" + b);
89
+ if (a.val() !== "no-value") {
90
+ tvc_activateOptionalFieldRow(b, a.val())
91
+ }
92
+ }
93
+
94
+ function tvc_hasExtraSourceRow(a, b) {
95
+ if (b.length > 0) {
96
+ return b[a - 1].hasOwnProperty("c")
97
+ } else {
98
+ return false
99
+ }
100
+ }
101
+
102
+ function tvc_changedCustomOutputTitle() {
103
+ var a = jQuery("#custom-output-title-input").val();
104
+ if (a) {
105
+ tvc_activateCustomFieldRow(a)
106
+ }
107
+ }
108
+
109
+ function tvc_deleteSpecificFeed(c, b) {
110
+ var a = confirm(tvc_feed_list_form_vars.confirm_delete_feed.replace("%feedname%", b));
111
+ if (a === true) {
112
+ tvc_deleteFeed(c, b);
113
+ console.log("File " + b + " removed from server.");
114
+ tvc_show_success_message(tvc_feed_list_form_vars.feed_removed.replace("%feedname%", b))
115
+ parent.location='admin.php?page=tvc-product-feed-manager&tab=feed-list';
116
+ }
117
+ }
118
+
119
+ function tvc_alertRemoveChannel() {
120
+ var a = confirm(tvc_manage_channels_vars.confirm_removing_channel);
121
+ if (true !== a) {
122
+ return false
123
+ }
124
+ }
125
+
126
+ function tvc_valueOptionChanged(d, c, e) {
127
+ var b = jQuery("#value-options-" + d + "-" + c + "-" + e).val();
128
+ var a = tvc_getCorrectValueSelector(d, c, 0, b, "", "");
129
+ jQuery("#value-editor-input-span-" + d + "-" + c + "-" + e).html(a)
130
+ }
131
+
132
+ function tvc_getCorrectValueSelector(f, e, g, c, d, a) {
133
+ var b = "";
134
+ switch (c) {
135
+ case"0":
136
+ case"change nothing":
137
+ tvc_valueInputOptionsChanged(f, e, g);
138
+ b = "";
139
+ break;
140
+ case"1":
141
+ case"overwrite":
142
+ b = tvc_valueOptionsSingleInput(f, e, g, d);
143
+ break;
144
+ case"2":
145
+ case"replace":
146
+ b = tvc_valueOptionsReplaceInput(f, e, g, d, a);
147
+ break;
148
+ case"3":
149
+ case"remove":
150
+ case"4":
151
+ case"add prefix":
152
+ case"5":
153
+ case"add suffix":
154
+ b = tvc_valueOptionsSingleInputValue(f, e, g, d);
155
+ break;
156
+ case"6":
157
+ case"recalculate":
158
+ b = tvc_valueOptionsRecalculate(f, e, g, d, a);
159
+ break;
160
+ case"7":
161
+ case"convert to child-element":
162
+ b = tvc_valueOptionsElementInput(f, e, g, d);
163
+ break;
164
+ default:
165
+ b = tvc_valueOptionsSingleInput(f, e, g, d);
166
+ break
167
+ }
168
+ return b
169
+ }
170
+
171
+ function tvc_deactivateFeed(a) {
172
+ tvc_switchFeedStatus(a, function (b) {
173
+ tvc_updateFeedRowStatus(a, parseInt(b))
174
+ })
175
+ }
176
+
177
+ function tvc_duplicateFeed(b, a) {
178
+ tvc_duplicateExistingFeed(b, function (c) {
179
+ if (c) {
180
+ tvc_show_success_message(tvc_feed_list_form_vars.added_feed_copy.replace("%feedname%", a))
181
+ }
182
+ })
183
+ }
184
+
185
+ function tvc_regenerateFeed(a) {
186
+ var b = tvcQueueStringIsEmpty() ? 3 : 4;
187
+ tvcAddToQueueString(a);
188
+ tvc_showFeedSpinner();
189
+ tvc_updateFeedRowStatus(a, b);
190
+ console.log("Started regenerating feed " + a);
191
+ tvc_updateFeedFile(a, function (d) {
192
+ tvc_hideFeedSpinner();
193
+ console.log(d);
194
+ var c = setInterval(function () {
195
+ tvc_getCurrentFeedStatus(a, function (f) {
196
+ var e = JSON.parse(f);
197
+ if ("3" !== e.status_id && "4" !== e.status_id) {
198
+ console.log(e);
199
+ tvc_resetFeedStatus(e);
200
+ tvc_resetFeedList();
201
+ clearInterval(c);
202
+ tvcRemoveFromQueueString(a)
203
+ }
204
+ })
205
+ }, 10000)
206
+ })
207
+ }
208
+
209
+ function tvc_viewFeed(a) {
210
+ if (-1 !== a.indexOf("http")) {
211
+ window.open(a)
212
+ } else {
213
+ alert(tvc_feed_list_form_vars.feed_not_generated)
214
+ }
215
+ }
216
+
217
+ function tvc_addRowValueEditor(c, b, d, a) {
218
+ jQuery("#end-row-id-" + c).remove();
219
+ jQuery("#row-" + c).append(tvc_valueEditor(c, b, d, a) + tvc_endrow(c));
220
+ jQuery("#value-editor-input-query-add-span-" + c + "-" + b + "-" + d).remove()
221
+ }
222
+
223
+ function tvc_convertToCamelCase(b) {
224
+ var a = b[0].toLowerCase();
225
+ for (var c = 1; c < b.length; c++) {
226
+ a += b[c].charAt(0).toUpperCase() + b[c].slice(1)
227
+ }
228
+ return a
229
+ }
230
+
231
+ function tvc_addValueEditorQuery(c, b, a) {
232
+ if (tvc_changeValueIsFilled(c, b, a)) {
233
+ if (tvc_queryIsFilled(c, (b - 1), 1)) {
234
+ tvc_showEditValueQuery(c, b, a, true)
235
+ } else {
236
+ alert(tvc_feed_settings_form_vars.query_requirements)
237
+ }
238
+ } else {
239
+ alert(tvc_feed_settings_form_vars.first_fill_in_change_value)
240
+ }
241
+ }
242
+
243
+ function tvc_queryStringToQueryObject(c) {
244
+ var b = {};
245
+ if (c) {
246
+ for (var a in c) {
247
+ b = tvc_convertQueryStringToQueryObject(c[a])
248
+ }
249
+ }
250
+ return b
251
+ }
252
+
253
+ function tvc_valueStringToValueObject(b) {
254
+ var a = {};
255
+ if (b) {
256
+ for (var c in b) {
257
+ if (c !== "q") {
258
+ a = tvc_convertValueStringToValueObject(b[c])
259
+ }
260
+ }
261
+ }
262
+ return a
263
+ }
264
+
265
+ function tvc_convertQueryStringToQueryObject(c) {
266
+ var b = {};
267
+ var a = c.split("#");
268
+ if (a[0] === "1" || a[0] === "2") {
269
+ b.preCondition = a[0]
270
+ } else {
271
+ b.preCondition = "0"
272
+ }
273
+ b.source = a[1];
274
+ b.condition = a[2];
275
+ b.value = a[3] ? a[3] : "";
276
+ b.endValue = a[5] ? a[5] : "";
277
+ return b
278
+ }
279
+
280
+ function tvc_resortObject(b) {
281
+ var a = [];
282
+ var e = 1;
283
+ for (var d in b) {
284
+ var f = {};
285
+ for (var c in b[d]) {
286
+ if (c !== "q") {
287
+ f[e] = b[d][c];
288
+ a.push(f)
289
+ } else {
290
+ a[e - 1].q = b[d][c]
291
+ }
292
+ }
293
+ e++
294
+ }
295
+ return e > 1 ? a : ""
296
+ }
297
+
298
+ function tvc_convertValueStringToValueObject(b) {
299
+ var a = {};
300
+ var c = b.split("#");
301
+ a.preCondition = c[0];
302
+ a.condition = c[1];
303
+ a.value = c[2];
304
+ a.endValue = c[3] ? c[3] : "";
305
+ return a
306
+ }
307
+
308
+ function tvc_makeCleanQueryObject() {
309
+ var a = {};
310
+ a.preCondition = "if";
311
+ a.source = "select";
312
+ a.condition = "";
313
+ a.value = "";
314
+ a.endValue = "";
315
+ return a
316
+ }
317
+
318
+ function tvc_makeCleanValueObject() {
319
+ var a = {};
320
+ a.preCondition = "change";
321
+ a.condition = "overwrite";
322
+ a.value = "";
323
+ a.endValue = "";
324
+ return a
325
+ }
326
+
327
+ function tvc_addNewItemToCategoryString(h, a, f, e) {
328
+ var b = a.split(e).length;
329
+ if (a === tvc_feed_settings_form_vars.map_to_default_category || h === "0") {
330
+ return f
331
+ } else {
332
+ if (b <= h) {
333
+ return a + e + f
334
+ } else {
335
+ var g = 0;
336
+ for (var c = 0; c < h; c++) {
337
+ g = a.indexOf(e, g + 1);
338
+ var d = a.substring(0, g)
339
+ }
340
+ return d + e + f
341
+ }
342
+ }
343
+ };
includes/application/js/tvc_object-attribute-meta.js ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+
3
+ function Tvc_AttributeMeta( key, value ) {
4
+
5
+ this.key = key;
6
+ this.value = value;
7
+ }
8
+
9
+ function countSources( mappingData ) {
10
+
11
+ return mappingData.length > 0 ? mappingData.length : 1;
12
+ }
13
+
14
+ function tvc_getMappingSourceValue( mapping, sourceCounter ) {
15
+
16
+ if ( mapping && mapping.length > 0 ) {
17
+
18
+ if ( mapping[ sourceCounter ] && 's' in mapping[ sourceCounter ] && 'source' in mapping[ sourceCounter ].s ) {
19
+
20
+ // do not return a combined value
21
+ return mapping[ sourceCounter ].s[ 'source' ] !== 'combined' ? mapping[ sourceCounter ].s[ 'source' ] : null;
22
+ } else {
23
+ return null;
24
+ }
25
+ } else {
26
+ return null; // mapping seems to be empty
27
+ }
28
+ }
29
+
30
+ function tvc_getMappingCombinedValue( mapping, sourceCounter ) {
31
+
32
+ if ( mapping && mapping.length > 0 ) {
33
+
34
+ if ( mapping[ sourceCounter ] && 's' in mapping[ sourceCounter ] && 'source' in mapping[ sourceCounter ].s && mapping[ sourceCounter ].s[ 'source' ] === 'combined' ) {
35
+ return mapping[ sourceCounter ].s[ 'f' ];
36
+ } else {
37
+ return null;
38
+ }
39
+ } else {
40
+ return null; // mapping seems to be empty
41
+ }
42
+ }
43
+
44
+ function tvc_getMappingStaticValue( mapping, sourceCounter ) {
45
+
46
+ if ( mapping && mapping.length > 0 ) {
47
+
48
+ if ( mapping[ sourceCounter ] && 's' in mapping[ sourceCounter ] && 'static' in mapping[ sourceCounter ].s ) {
49
+ return mapping[ sourceCounter ].s[ 'static' ];
50
+ } else {
51
+ return null;
52
+ }
53
+ } else {
54
+ return null; // mapping seems to be empty
55
+ }
56
+ }
57
+
58
+ function tvc_getMappingConditions( mapping, sourceCounter ) {
59
+ if ( mapping && mapping.length > 0 ) {
60
+ if ( mapping[ sourceCounter ] && 'c' in mapping[ sourceCounter ] ) {
61
+ return mapping[ sourceCounter ].c;
62
+ }
63
+ } else {
64
+ return null;
65
+ }
66
+ }
includes/application/js/tvc_object-attribute-meta.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function Tvc_AttributeMeta(a,b){this.key=a;this.value=b}function countSources(a){return a.length>0?a.length:1}function tvc_getMappingSourceValue(b,a){if(b&&b.length>0){if(b[a]&&"s" in b[a]&&"source" in b[a].s){return b[a].s.source!=="combined"?b[a].s.source:null}else{return null}}else{return null}}function tvc_getMappingCombinedValue(b,a){if(b&&b.length>0){if(b[a]&&"s" in b[a]&&"source" in b[a].s&&b[a].s.source==="combined"){return b[a].s.f}else{return null}}else{return null}}function tvc_getMappingStaticValue(b,a){if(b&&b.length>0){if(b[a]&&"s" in b[a]&&"static" in b[a].s){return b[a].s["static"]}else{return null}}else{return null}}function tvc_getMappingConditions(b,a){if(b&&b.length>0){if(b[a]&&"c" in b[a]){return b[a].c}}else{return null}};
includes/application/js/tvc_object-feed.js ADDED
@@ -0,0 +1,849 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+
3
+ /**
4
+ * Feed Object
5
+ *
6
+ * @param {int} feedId
7
+ * @param {string} title Title of the feed file
8
+ * @param {int} includeVariations Does this feed include variations
9
+ * @param {int} aggregator Is this an aggregator feed
10
+ * @param {int} channel Channel definition
11
+ * @param {string} mainCategory
12
+ * @param {array} categoryMapping
13
+ * @param {string} url
14
+ * @param {string} dataSource Source id (for now only WooCommerce is supported)
15
+ * @param {string} country Two letter country identifier
16
+ * @param {string} language
17
+ * @param {string} feedTitle Google's feed title text
18
+ * @param {string} feedDescription Google's feed description text
19
+ * @param {string} updateSchedule Updates schedule string
20
+ * @param {array} feedFilter Feed filters
21
+ * @param {int} status Status of the feed
22
+ * @param {string} feedType Type of feed (default Product Feed Type)
23
+ *
24
+ * @constructor
25
+ */
26
+ function Feed( feedId, title, includeVariations, aggregator, channel, mainCategory,
27
+ categoryMapping, url, dataSource, country, language, feedTitle,
28
+ feedDescription, updateSchedule, feedFilter, status, feedType ) {
29
+
30
+ this.feedId = feedId;
31
+ this.title = title;
32
+ this.mainCategory = mainCategory;
33
+ this.categoryMapping = categoryMapping;
34
+ this.includeVariations = includeVariations;
35
+ this.isAggregator = aggregator;
36
+ this.feedTitle = feedTitle;
37
+ this.feedDescription = feedDescription;
38
+ this.url = url;
39
+ this.dataSource = dataSource;
40
+ this.channel = channel;
41
+ this.country = channel !== '3' ? country : 'NL'; // for Beslist.nl only register the Netherlands
42
+ this.language = language;
43
+ this.status = status;
44
+ this.updateSchedule = updateSchedule;
45
+ this.feedFilter = feedFilter;
46
+ this.attributes = [];
47
+ this.feedType = feedType;
48
+
49
+ // objects functions
50
+ this.addAttribute = addAttributeToFeed;
51
+ this.getAttributeIdByName = getAttributeId;
52
+ this.activateAttribute = activateFeedsAttribute;
53
+ this.checkIfCustomNameExists = checkCustomName;
54
+ this.countCombinedFields = countAttributesCombinedFields;
55
+ this.deactivateAttribute = deactivateFeedsAttribute;
56
+ this.deactivateCategory = deactivateCategoryMap;
57
+ this.activateCategory = activateCategoryMap;
58
+ this.setStaticAttributeValue = setAttributesStaticValue;
59
+ this.setSourceValue = setAttributesSourceValue;
60
+ this.setAlternativeSourceValue = setAlternativeAttributesSourceValue;
61
+ this.setCombinedOutputValue = setAttributesCombinedOutputValue;
62
+ this.setCategoryValue = setAttributesCategoryValue;
63
+ this.setFeedFilter = setFeedFilterValue;
64
+ this.mapCategory = mapACategory;
65
+ this.changeCustomFeedCategoryMap = changeCustomCategoryMap;
66
+ this.changeIncludeVariations = changeIncludeVariationsValue;
67
+ this.changeAggregator = changeAggregatorValue;
68
+ this.resetNrQueries = rstNrQueries;
69
+ this.incrNrQueries = addNrQueries;
70
+ this.decrNrQueries = substrNrQueries;
71
+ this.addConditionValue = addAttributesCondition;
72
+ this.addValueQueryValue = addAttributesValueQuery;
73
+ this.removeAttribute = removeAttributeFromFeed;
74
+ this.removeValueConditionValue = removeAttributesCondition;
75
+ this.removeValueQueryValue = removeAttributesValueQuery;
76
+ this.removeAlternativeSourceValue = removeAlternativeSource;
77
+ this.removeCombinedOutputValue = removeAttributesCombinedOutputValue;
78
+ this.removeEditValueValue = removeAttributesEditValue;
79
+ this.removeFeedFilter = removeFeedFilterValue;
80
+ this.getAttributesQueriesObject = getAttributesQueries;
81
+ this.getCombinedOutputValue = getAttributesCombinedOutputValue;
82
+ this.getValueQueryValue = getAttributesValueQueries;
83
+ this.getAttributesSourceObject = getAttributesSources;
84
+ this.getSourceObject = getSourceData;
85
+ this.getAlternativeSourcesObject = getAlternativeSources;
86
+ this.getAttributesValueObject = getAttributesValues;
87
+ this.getFeedFilter = getFeedFilterValue;
88
+ this.getFeedType = getFeedType;
89
+ this.setMainCategory = setCategories;
90
+ this.setUpdateSchedule = setSchedule;
91
+ this.setCustomCategory = setFeedCustomCategory;
92
+ this.setCountry = changeCountry;
93
+ this.clearSourceValue = clearAttributesSourceValue;
94
+ this.cleanAttributes = cleanUnusedAttributes;
95
+ this.clearAllAttributes = clearAttributes;
96
+ this.addChangeValue = addAttributesChangeValue;
97
+ }
98
+
99
+ function FeedAttribute( attributeId, fieldName, advisedSource, value, fieldLevel, isActive,
100
+ nrQueries, nrValueEdits, nrValueConditions ) {
101
+
102
+ this.rowId = attributeId;
103
+ this.fieldName = fieldName;
104
+ this.advisedSource = advisedSource;
105
+ this.value = value;
106
+ this.fieldLevel = fieldLevel;
107
+ this.isActive = isActive;
108
+ this.nrQueries = nrQueries;
109
+ this.nrValueEdits = nrValueEdits;
110
+ this.nrValueConditions = nrValueConditions;
111
+ }
112
+
113
+ function CategoryMap( shopCategory, feedCategories ) {
114
+
115
+ this.shopCategoryId = shopCategory;
116
+ this.feedCategories = feedCategories;
117
+ }
118
+
119
+ function addAttributeToFeed( attributeId, fieldName, advisedSource, value, fieldLevel, isActive, queryLevel, valuesLevel, valueConditions ) {
120
+
121
+ var attribute = new FeedAttribute( attributeId, fieldName, advisedSource, value, fieldLevel, isActive, queryLevel, valuesLevel, valueConditions );
122
+
123
+ this.attributes.push( attribute );
124
+ }
125
+
126
+ function removeAttributeFromFeed( rowId ) {
127
+
128
+ for ( var i = 0; i < this.attributes.length; i ++ ) {
129
+
130
+ if ( this.attributes[ i ].rowId === rowId ) {
131
+
132
+ this.attributes.splice( i, 1 );
133
+ }
134
+ }
135
+ }
136
+
137
+ function mapACategory( categorySelectorId, category ) {
138
+
139
+ var selectedLevel = categorySelectorId.match( /(\d+)$/ )[ 0 ]; // next level
140
+ var sc = categorySelectorId.replace( '_' + selectedLevel, '' );
141
+ var shopCategoryId = sc.match( /(\d+)$/ )[ 0 ];
142
+ var mo = JSON.parse( this.categoryMapping );
143
+
144
+ // check if this.categoryMapping already has a mapped category with this id
145
+ var categoryMapForGivenId = jQuery.grep(
146
+ mo,
147
+ function( e ) {
148
+ return e.shopCategoryId === shopCategoryId;
149
+ }
150
+ );
151
+
152
+ if ( categoryMapForGivenId.length > 0 ) {
153
+
154
+ var oldString = categoryMapForGivenId[ 0 ].feedCategories;
155
+
156
+ categoryMapForGivenId[ 0 ].feedCategories = tvc_addNewItemToCategoryString(
157
+ selectedLevel,
158
+ oldString,
159
+ category,
160
+ ' > '
161
+ );
162
+ } else { // this category map does not exist so add a new one to the array
163
+
164
+ var catMap = new CategoryMap();
165
+
166
+ catMap.shopCategoryId = shopCategoryId;
167
+ catMap.feedCategories = category;
168
+
169
+ mo.push( catMap );
170
+ }
171
+
172
+ this.categoryMapping = JSON.stringify( mo );
173
+ }
174
+
175
+ function changeCustomCategoryMap( shopCategoryId, feedCategories ) {
176
+
177
+ var mo = JSON.parse( this.categoryMapping );
178
+
179
+ // check if this.categoryMapping already has a maped category with this id
180
+ var categoryMapForGivenId = jQuery.grep(
181
+ mo,
182
+ function( e ) {
183
+ return e.shopCategoryId === shopCategoryId;
184
+ }
185
+ );
186
+
187
+ if ( categoryMapForGivenId.length > 0 ) {
188
+
189
+ categoryMapForGivenId[ 0 ].feedCategories = feedCategories;
190
+ } else { // this category map does not exist so add a new one to the array
191
+
192
+ var catMap = new CategoryMap();
193
+
194
+ catMap.shopCategoryId = shopCategoryId;
195
+ catMap.feedCategories = feedCategories;
196
+
197
+ mo.push( catMap );
198
+ }
199
+
200
+ this.categoryMapping = JSON.stringify( mo );
201
+ }
202
+
203
+ function changeIncludeVariationsValue( selectedValue ) {
204
+
205
+ this.includeVariations = selectedValue ? '1' : '0';
206
+ }
207
+
208
+ function changeAggregatorValue( selectedValue ) {
209
+
210
+ this.isAggregator = selectedValue ? '1' : '0';
211
+ }
212
+
213
+ function activateCategoryMap( shopCategoryId, channelUsesOwnCategory ) {
214
+
215
+ // get the currently stored mapping
216
+ var mo = this.categoryMapping.length > 0 ? JSON.parse( this.categoryMapping ) : [];
217
+
218
+ // test if this.categoryMapping already has a mapped category with this id
219
+ var categoryMapForGivenId = jQuery.grep(
220
+ mo,
221
+ function( e ) {
222
+ return e.shopCategoryId === shopCategoryId.toString();
223
+ }
224
+ );
225
+
226
+ // only store this mapping if it has not been registered already to this id
227
+ if ( categoryMapForGivenId.length < 1 ) {
228
+
229
+ var catMap = new CategoryMap();
230
+
231
+ catMap.shopCategoryId = shopCategoryId.toString();
232
+ catMap.feedCategories = channelUsesOwnCategory ? 'wp_ownCategory' : 'wp_mainCategory';
233
+
234
+ mo.push( catMap );
235
+
236
+ this.categoryMapping = JSON.stringify( mo );
237
+ }
238
+ }
239
+
240
+ function deactivateCategoryMap( shopCategoryId ) {
241
+
242
+ var mo = this.categoryMapping.length > 0 ? JSON.parse( this.categoryMapping ) : [];
243
+
244
+ if ( mo.length > 1 ) {
245
+
246
+ var index = tvc_arrayObjectIndexOf(
247
+ mo,
248
+ shopCategoryId.toString(),
249
+ 'shopCategoryId'
250
+ );
251
+
252
+ mo.splice( index, 1 ); // remove the category object
253
+
254
+ this.categoryMapping = JSON.stringify( mo );
255
+ } else {
256
+
257
+ this.categoryMapping = [];
258
+ }
259
+ }
260
+
261
+ function getAttributeId( name ) {
262
+
263
+ var attributeId = false;
264
+
265
+ for ( var i = 0; i < this.attributes.length; i ++ ) {
266
+
267
+ if ( this.attributes[ i ][ 'fieldName' ] === name ) {
268
+
269
+ attributeId = this.attributes[ i ][ 'rowId' ];
270
+ break;
271
+ }
272
+ }
273
+
274
+ if ( attributeId === false ) { // seems like a custom field
275
+
276
+ attributeId = this.attributes.length;
277
+ }
278
+
279
+ return attributeId;
280
+ }
281
+
282
+ function setAttributesStaticValue(
283
+ attributeId, level, combinationLevel, newValue ) {
284
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
285
+
286
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeSourceValue( level, currentValue, 'static', newValue );
287
+
288
+ this.attributes[ attributeId ][ 'isActive' ] = ! ! this.attributes[ attributeId ][ 'value' ];
289
+ }
290
+
291
+ function setAttributesSourceValue( attributeId, sourceLevel, newSource ) {
292
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
293
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeSourceValue(
294
+ sourceLevel,
295
+ currentValue,
296
+ 'source',
297
+ newSource
298
+ );
299
+ }
300
+
301
+ function setAlternativeAttributesSourceValue( attributeId, level, value ) {
302
+
303
+ var attributeValueObject = {};
304
+ var attributeArray = [];
305
+
306
+ if ( this.attributes[ attributeId ][ 'value' ] ) {
307
+ attributeValueObject = JSON.parse(
308
+ this.attributes[ attributeId ][ 'value' ]
309
+ );
310
+
311
+ attributeValueObject.a = addOrRemoveValueInValueString(
312
+ attributeValueObject.a,
313
+ value,
314
+ level,
315
+ 'add'
316
+ );
317
+ } else {
318
+
319
+ var o = {};
320
+ o[ 1 ] = value;
321
+
322
+ attributeArray.push( o );
323
+ attributeValueObject.a = attributeArray;
324
+ }
325
+
326
+ this.attributes[ attributeId ][ 'value' ] = JSON.stringify( attributeValueObject );
327
+ }
328
+
329
+ function setAttributesCombinedOutputValue(
330
+ attributeId, sourceLevel, newCombinedValue ) {
331
+
332
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
333
+ console.log( currentValue );
334
+
335
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeCombinedValue(
336
+ sourceLevel,
337
+ currentValue,
338
+ newCombinedValue
339
+ );
340
+ }
341
+
342
+ function getAttributesCombinedOutputValue( attributeId, sourceLevel ) {
343
+
344
+ var attributeObject = this.attributes[ attributeId ][ 'value' ] ? JSON.parse( this.attributes[ attributeId ][ 'value' ] ) : {};
345
+
346
+ if ( attributeObject && attributeObject.m && attributeObject.m[ sourceLevel ] && attributeObject.m[ sourceLevel ].s && attributeObject.m[ sourceLevel ].s.f ) {
347
+
348
+ return attributeObject.m[ sourceLevel ].s.f;
349
+ } else {
350
+
351
+ return '';
352
+ }
353
+ }
354
+
355
+ function removeAttributesCombinedOutputValue(
356
+ attributeId, sourceLevel, combinedLevel ) {
357
+
358
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
359
+ this.attributes[ attributeId ][ 'value' ] = tvc_removeCombinedValue(
360
+ sourceLevel,
361
+ combinedLevel,
362
+ currentValue
363
+ );
364
+ }
365
+
366
+ function countAttributesCombinedFields( attributeId ) {
367
+
368
+ if ( this.attributes[ attributeId ][ 'value' ] ) {
369
+ var attributeValueObject = JSON.parse(
370
+ this.attributes[ attributeId ][ 'value' ]
371
+ );
372
+
373
+ if ( attributeValueObject.hasOwnProperty( 'f' ) ) {
374
+ return tvc_countObjectItems( attributeValueObject.f );
375
+ } else {
376
+ return 0;
377
+ }
378
+ } else {
379
+ return 0;
380
+ }
381
+ }
382
+
383
+ function setAttributesCategoryValue( attributeId, newCategory ) {
384
+
385
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
386
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeSourceValue(
387
+ 0,
388
+ currentValue,
389
+ '',
390
+ newCategory
391
+ );
392
+ }
393
+
394
+ function rstNrQueries( attributeId ) {
395
+ this.attributes[ attributeId ][ 'nrQueries' ] = 0;
396
+ }
397
+
398
+ function addNrQueries( attributeId ) {
399
+ var currentNr = this.attributes[ attributeId ][ 'nrQueries' ];
400
+ this.attributes[ attributeId ][ 'nrQueries' ] = currentNr + 1;
401
+ }
402
+
403
+ function substrNrQueries( attributeId ) {
404
+
405
+ var currentNr = this.attributes[ attributeId ][ 'nrQueries' ];
406
+ if ( currentNr > 0 ) {
407
+ this.attributes[ attributeId ][ 'nrQueries' ] = currentNr - 1;
408
+ }
409
+ }
410
+
411
+ function addAttributesChangeValue(
412
+ attributeId, sourceLevel, valueEditorLevel, value ) {
413
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
414
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeValueChange(
415
+ sourceLevel,
416
+ valueEditorLevel,
417
+ value,
418
+ 'add',
419
+ currentValue
420
+ );
421
+ }
422
+
423
+ function addAttributesCondition(
424
+ attributeId, newCondition, sourceLevel, conditionLevel ) {
425
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
426
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeConditionValue(
427
+ sourceLevel,
428
+ conditionLevel,
429
+ currentValue,
430
+ newCondition
431
+ );
432
+ }
433
+
434
+ function addAttributesValueQuery(
435
+ attributeId, sourceLevel, queryLevel, queryToAdd ) {
436
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
437
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeQueryValue(
438
+ sourceLevel,
439
+ queryLevel,
440
+ currentValue,
441
+ queryToAdd
442
+ );
443
+ }
444
+
445
+ function setFeedFilterValue( value ) {
446
+ this.feedFilter = value;
447
+ }
448
+
449
+ function removeFeedFilterValue( filterLevelToRemove ) {
450
+ this.feedFilter = removeFeedFilterLevel(
451
+ this.feedFilter,
452
+ filterLevelToRemove
453
+ );
454
+ }
455
+
456
+ function removeAttributesCondition( attributeId, sourceLevel, conditionLevel ) {
457
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
458
+ this.attributes[ attributeId ][ 'value' ] = tvc_removeConditionValue(
459
+ sourceLevel,
460
+ conditionLevel,
461
+ currentValue
462
+ );
463
+ }
464
+
465
+ function removeAttributesValueQuery( attributeId, sourceLevel, queryLevel ) {
466
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
467
+ this.attributes[ attributeId ][ 'value' ] = tvc_removeQueryValue(
468
+ sourceLevel,
469
+ queryLevel,
470
+ currentValue
471
+ );
472
+ }
473
+
474
+ function removeAttributesEditValue(
475
+ attributeId, sourceLevel, valueEditorLevel ) {
476
+ var currentValue = this.attributes[ attributeId ][ 'value' ];
477
+ this.attributes[ attributeId ][ 'value' ] = tvc_removeEditValuesValue(
478
+ sourceLevel,
479
+ valueEditorLevel,
480
+ currentValue
481
+ );
482
+ }
483
+
484
+ function removeAlternativeSource( attributeId, level ) {
485
+ var attributeValueObject = {};
486
+ if ( this.attributes[ attributeId ][ 'value' ] ) {
487
+ attributeValueObject = JSON.parse(
488
+ this.attributes[ attributeId ][ 'value' ]
489
+ );
490
+
491
+ attributeValueObject.a = addOrRemoveValueInValueString(
492
+ attributeValueObject.a,
493
+ '',
494
+ level,
495
+ 'remove'
496
+ );
497
+
498
+ if ( ! attributeValueObject.a ) {
499
+ delete attributeValueObject.a;
500
+ }
501
+
502
+ this.attributes[ attributeId ][ 'value' ] = JSON.stringify(
503
+ attributeValueObject
504
+ );
505
+ }
506
+ }
507
+
508
+ /**
509
+ * Gets the queries from a specific attribute
510
+ *
511
+ * @param {int} attributeId
512
+ * @param {int} sourceLevel
513
+ * @returns {array} containing the queries
514
+ */
515
+ function getAttributesQueries( attributeId, sourceLevel ) {
516
+
517
+ var attributeString = this.attributes[ attributeId ][ 'value' ];
518
+ var queries = {};
519
+ if ( attributeString ) {
520
+ var o = JSON.parse( attributeString );
521
+ if ( o && o.hasOwnProperty( 'm' ) && o.m[ sourceLevel ] && o.m[ sourceLevel ].hasOwnProperty( 'c' ) && o.m[ sourceLevel ].c.length > 0 ) {
522
+ queries = o.m[ sourceLevel ].c;
523
+ }
524
+ }
525
+
526
+ return queries;
527
+ }
528
+
529
+ function getAttributesValueQueries( attributeId, sourceLevel ) {
530
+
531
+ var attributeString = this.attributes[ attributeId ][ 'value' ];
532
+ var queries = {};
533
+
534
+ if ( attributeString ) {
535
+ var attributeObject = JSON.parse( attributeString );
536
+ if ( attributeObject && attributeObject.v && attributeObject.v[ sourceLevel ] && attributeObject.v[ sourceLevel ].hasOwnProperty( 'q' ) && attributeObject.v[ sourceLevel ].q.length > 0 ) {
537
+ queries = attributeObject.v[ sourceLevel ].q;
538
+ }
539
+ }
540
+ return queries;
541
+ }
542
+
543
+ function getAttributesValues( attributeId ) {
544
+
545
+ var attributeString = this.attributes[ attributeId ][ 'value' ];
546
+ var values = {};
547
+ if ( attributeString ) {
548
+ var attributeObject = JSON.parse( attributeString );
549
+ if ( attributeObject && 'v' in attributeObject && attributeObject.v.length > 0 ) {
550
+ values = attributeObject.v;
551
+ }
552
+ }
553
+ return values;
554
+ }
555
+
556
+ function getFeedFilterValue( feedId ) {
557
+
558
+ }
559
+
560
+ function getAlternativeSources( attributeId ) {
561
+
562
+ var attributeString = this.attributes[ attributeId ][ 'value' ];
563
+ var values = {};
564
+
565
+ if ( attributeString ) {
566
+
567
+ var attributeObject = JSON.parse( attributeString );
568
+
569
+ if ( attributeObject && 'a' in attributeObject && attributeObject.a.length > 0 ) {
570
+
571
+ values = attributeObject.a;
572
+ }
573
+ }
574
+
575
+ return values;
576
+ }
577
+
578
+ /**
579
+ * Returns an object filled with all the required data for a specific feed row
580
+ *
581
+ * @param {string} feedId
582
+ * @returns {object} containing the required data
583
+ */
584
+ function getSourceData( feedId ) {
585
+
586
+ var data = {};
587
+
588
+ // add the basic data to the object
589
+ data.rowId = feedId;
590
+ data.fieldName = this.attributes[ feedId ][ 'fieldName' ];
591
+ data.advisedSource = this.attributes[ feedId ][ 'advisedSource' ];
592
+
593
+ // get the attribute data
594
+ var attributeString = this.attributes[ feedId ][ 'value' ];
595
+
596
+ // and put the attribute data in the object
597
+ if ( attributeString ) {
598
+
599
+ var attributeDataObject = JSON.parse( attributeString );
600
+
601
+ data.mapping = attributeDataObject && 'm' in attributeDataObject ? attributeDataObject.m : [];
602
+ data.changeValues = attributeDataObject && 'v' in attributeDataObject ? attributeDataObject.v : [];
603
+ data.customCondition = ! ! (
604
+ attributeDataObject && 't' in attributeDataObject
605
+ );
606
+ } else {
607
+
608
+ data.mapping = [];
609
+ data.changeValues = [];
610
+ data.customCondition = false;
611
+ }
612
+
613
+ return data;
614
+ }
615
+
616
+ function getAttributesSources( attributeId ) {
617
+
618
+ var attributeString = this.attributes[ attributeId ][ 'value' ];
619
+ var source = {};
620
+
621
+ if ( attributeString ) {
622
+
623
+ var attributeObject = JSON.parse( attributeString );
624
+
625
+ if ( attributeObject && 's' in attributeObject ) {
626
+
627
+ source = attributeObject.s;
628
+ }
629
+ }
630
+
631
+ return source;
632
+ }
633
+
634
+ function addOrRemoveValueInValueString( values, value, level, add ) {
635
+
636
+ var valueArray = values ? values : [];
637
+
638
+ if ( add === 'add' ) {
639
+
640
+ var o = {};
641
+ var queriesMemory = '';
642
+ o[ level ] = value;
643
+
644
+ // if the value also has a query than store it first
645
+ if ( valueArray[ level - 1 ] && 'q' in valueArray[ level - 1 ] ) {
646
+
647
+ queriesMemory = valueArray[ level - 1 ][ 'q' ];
648
+ }
649
+
650
+ // remove values with the same key
651
+ if ( level in o ) {
652
+
653
+ valueArray.splice( level - 1, 1 );
654
+ }
655
+
656
+ // if there were queries stored, then put them back in to the new value
657
+ if ( queriesMemory ) {
658
+ o[ 'q' ] = queriesMemory;
659
+ }
660
+
661
+ valueArray.push( o );
662
+ } else { // remove
663
+
664
+ valueArray.splice( level - 1, 1 );
665
+
666
+ // re-sort the queries
667
+ valueArray = tvc_resortObject( valueArray );
668
+ }
669
+
670
+ if ( tvc_countObjectItems( valueArray ) > 0 ) {
671
+
672
+ return valueArray;
673
+ } else {
674
+
675
+ return '';
676
+ }
677
+ }
678
+
679
+ function clearAttributesSourceValue( attributeId, sourceLevel ) {
680
+
681
+ if ( this.attributes[ attributeId ][ 'value' ] ) {
682
+
683
+ this.attributes[ attributeId ][ 'value' ] = tvc_storeSourceValue(
684
+ sourceLevel,
685
+ this.attributes[ attributeId ][ 'value' ],
686
+ 'clear',
687
+ ''
688
+ );
689
+ } else {
690
+
691
+ this.attributes[ attributeId ][ 'value' ] = '';
692
+ }
693
+ }
694
+
695
+ function setFeedCustomCategory( rowId, category ) {
696
+
697
+ console.log( this.attributes );
698
+ console.log( category );
699
+
700
+ // set the main category
701
+ this.mainCategory = category;
702
+
703
+ var id = rowId ? rowId : getCustomCategoryAttributeId( this.attributes, category );
704
+
705
+ // when a output is initialised as category, then set the category in the correct row
706
+ if ( id ) {
707
+
708
+ console.log( id );
709
+
710
+ var o = this.attributes[ id ][ 'value' ] ? JSON.parse( this.attributes[ id ][ 'value' ] ) : {};
711
+
712
+ o.t = category;
713
+
714
+ this.attributes[ id ][ 'value' ] = JSON.stringify( o );
715
+ }
716
+ }
717
+
718
+ function changeCountry( selectedCountry ) {
719
+
720
+ this.country = selectedCountry;
721
+ }
722
+
723
+ function getCustomCategoryAttributeId( attr ) {
724
+
725
+ for ( var i = 0; i < attr.length; i ++ ) {
726
+
727
+ console.log( attr[ i ] );
728
+
729
+ var catObject = attr[ i ][ 'value' ] ? JSON.parse( attr[ i ][ 'value' ] ) : {};
730
+
731
+ console.log( catObject );
732
+
733
+ if ( catObject.hasOwnProperty( 't' ) ) {
734
+
735
+ return i;
736
+ }
737
+ }
738
+ }
739
+
740
+ function setCategories( level, category, channel ) {
741
+ if ( this.attributes[ 3 ] !== undefined ) {
742
+ var categoryAttributeObject = this.attributes[ 3 ][ 'value' ] ? JSON.parse( this.attributes[ 3 ][ 'value' ] ) : {};
743
+ var categoryDelimiter = tvc_category_separator( channel );
744
+
745
+ var categoryString = this.mainCategory;
746
+ var categoryLevel = this.attributes[ 3 ][ 'value' ] !== undefined ? categoryString.split( categoryDelimiter ).length : 0;
747
+
748
+ var selectedLevel = level.match( /(\d+)$/ )[ 0 ];
749
+
750
+ if ( selectedLevel === '0' ) {
751
+ this.mainCategory = category;
752
+ this.attributes[ 3 ][ 'value' ] = '{"t":"' + category + '"}';
753
+ } else {
754
+ if ( categoryLevel <= selectedLevel ) {
755
+ this.mainCategory += categoryDelimiter + category;
756
+ this.attributes[ 3 ][ 'value' ] = '{"t":"' + categoryAttributeObject.t + categoryDelimiter + category + '"}';
757
+ } else {
758
+ var pos = 0;
759
+
760
+ for ( var i = 0; i < selectedLevel; i ++ ) {
761
+ pos = categoryString.indexOf( categoryDelimiter, pos + 1 );
762
+ }
763
+
764
+ categoryString = categoryString.substring( 0, pos );
765
+
766
+ if ( category !== '0' ) {
767
+ this.mainCategory = categoryString + categoryDelimiter + category;
768
+ this.attributes[ 3 ][ 'value' ] = '{"t":"' + categoryString + categoryDelimiter + category + '"}';
769
+ } else {
770
+ this.mainCategory = categoryString;
771
+ this.attributes[ 3 ][ 'value' ] = '{"t":"' + categoryString + '"}';
772
+ }
773
+ }
774
+ }
775
+ }
776
+ }
777
+
778
+ function setSchedule( days, hours, minutes, frequency ) {
779
+
780
+ this.updateSchedule = days + ':' + hours + ':' + minutes + ':' + frequency;
781
+ }
782
+
783
+ function activateFeedsAttribute( attributeId ) {
784
+
785
+ this.attributes[ attributeId ][ 'isActive' ] = true;
786
+ }
787
+
788
+ function deactivateFeedsAttribute( attributeId ) {
789
+
790
+ if ( this.attributes[ attributeId ][ 'fieldLevel' ] !== '1' ) {
791
+
792
+ var attributeDataObject = this.attributes[ attributeId ][ 'value' ] ? JSON.parse( this.attributes[ attributeId ][ 'value' ] ) : {};
793
+ this.attributes[ attributeId ][ 'isActive' ] = false;
794
+
795
+ // clear the meta value but only if it not contains the category string
796
+ if ( attributeDataObject && ! 't' in attributeDataObject ) {
797
+ this.attributes[ attributeId ][ 'value' ] = '';
798
+ }
799
+ } else {
800
+
801
+ this.attributes[ attributeId ][ 'isActive' ] = true; // any required attribute should always stay active
802
+ }
803
+ }
804
+
805
+ function checkCustomName( name ) {
806
+
807
+ var result = false;
808
+
809
+ for ( var i = 0; i < this.attributes.length; i ++ ) {
810
+
811
+ if ( this.attributes[ i ][ 'fieldName' ] === name ) {
812
+ result = true;
813
+ }
814
+ }
815
+
816
+ return result;
817
+ }
818
+
819
+ function getFeedType() {
820
+ return this.feedType;
821
+ }
822
+
823
+ function removeAttribute( attributeId ) {
824
+
825
+ this.attributes.splice( attributeId, 1 );
826
+ }
827
+
828
+ function cleanUnusedAttributes() {
829
+
830
+ if ( this.attributes.length > 0 ) {
831
+
832
+ for ( var i = 0; i < this.attributes.length; i ++ ) {
833
+
834
+ if ( this.attributes[ i ][ 'isActive' ] !== true ) {
835
+
836
+ this.attributes.splice( i, 1 );
837
+ i --; // reset i for the removed attribute
838
+ } else if ( this.attributes[ i ][ 'advisedSource' ] === undefined && getSourceString( this.attributes[ i ][ 'value' ] ) === '' ) {
839
+
840
+ this.attributes.splice( i, 1 );
841
+ i --; // reset i for the removed attribute
842
+ }
843
+ }
844
+ }
845
+ }
846
+
847
+ function clearAttributes() {
848
+ this.attributes = [];
849
+ }
includes/application/js/tvc_object-feed.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function Feed(e,n,g,d,j,k,o,c,a,f,i,b,m,q,p,h,l){this.feedId=e;this.title=n;this.mainCategory=k;this.categoryMapping=o;this.includeVariations=g;this.isAggregator=d;this.feedTitle=b;this.feedDescription=m;this.url=c;this.dataSource=a;this.channel=j;this.country=j!=="3"?f:"NL";this.language=i;this.status=h;this.updateSchedule=q;this.feedFilter=p;this.attributes=[];this.feedType=l;this.addAttribute=addAttributeToFeed;this.getAttributeIdByName=getAttributeId;this.activateAttribute=activateFeedsAttribute;this.checkIfCustomNameExists=checkCustomName;this.countCombinedFields=countAttributesCombinedFields;this.deactivateAttribute=deactivateFeedsAttribute;this.deactivateCategory=deactivateCategoryMap;this.activateCategory=activateCategoryMap;this.setStaticAttributeValue=setAttributesStaticValue;this.setSourceValue=setAttributesSourceValue;this.setAlternativeSourceValue=setAlternativeAttributesSourceValue;this.setCombinedOutputValue=setAttributesCombinedOutputValue;this.setCategoryValue=setAttributesCategoryValue;this.setFeedFilter=setFeedFilterValue;this.mapCategory=mapACategory;this.changeCustomFeedCategoryMap=changeCustomCategoryMap;this.changeIncludeVariations=changeIncludeVariationsValue;this.changeAggregator=changeAggregatorValue;this.resetNrQueries=rstNrQueries;this.incrNrQueries=addNrQueries;this.decrNrQueries=substrNrQueries;this.addConditionValue=addAttributesCondition;this.addValueQueryValue=addAttributesValueQuery;this.removeAttribute=removeAttributeFromFeed;this.removeValueConditionValue=removeAttributesCondition;this.removeValueQueryValue=removeAttributesValueQuery;this.removeAlternativeSourceValue=removeAlternativeSource;this.removeCombinedOutputValue=removeAttributesCombinedOutputValue;this.removeEditValueValue=removeAttributesEditValue;this.removeFeedFilter=removeFeedFilterValue;this.getAttributesQueriesObject=getAttributesQueries;this.getCombinedOutputValue=getAttributesCombinedOutputValue;this.getValueQueryValue=getAttributesValueQueries;this.getAttributesSourceObject=getAttributesSources;this.getSourceObject=getSourceData;this.getAlternativeSourcesObject=getAlternativeSources;this.getAttributesValueObject=getAttributesValues;this.getFeedFilter=getFeedFilterValue;this.getFeedType=getFeedType;this.setMainCategory=setCategories;this.setUpdateSchedule=setSchedule;this.setCustomCategory=setFeedCustomCategory;this.setCountry=changeCountry;this.clearSourceValue=clearAttributesSourceValue;this.cleanAttributes=cleanUnusedAttributes;this.clearAllAttributes=clearAttributes;this.addChangeValue=addAttributesChangeValue}function FeedAttribute(e,g,h,f,b,i,a,c,d){this.rowId=e;this.fieldName=g;this.advisedSource=h;this.value=f;this.fieldLevel=b;this.isActive=i;this.nrQueries=a;this.nrValueEdits=c;this.nrValueConditions=d}function CategoryMap(b,a){this.shopCategoryId=b;this.feedCategories=a}function addAttributeToFeed(e,h,i,g,b,j,d,c,f){var a=new FeedAttribute(e,h,i,g,b,j,d,c,f);this.attributes.push(a)}function removeAttributeFromFeed(b){for(var a=0;a<this.attributes.length;a++){if(this.attributes[a].rowId===b){this.attributes.splice(a,1)}}}function mapACategory(i,a){var h=i.match(/(\d+)$/)[0];var f=i.replace("_"+h,"");var b=f.match(/(\d+)$/)[0];var c=JSON.parse(this.categoryMapping);var d=jQuery.grep(c,function(j){return j.shopCategoryId===b});if(d.length>0){var e=d[0].feedCategories;d[0].feedCategories=tvc_addNewItemToCategoryString(h,e,a," > ")}else{var g=new CategoryMap();g.shopCategoryId=b;g.feedCategories=a;c.push(g)}this.categoryMapping=JSON.stringify(c)}function changeCustomCategoryMap(c,b){var d=JSON.parse(this.categoryMapping);var a=jQuery.grep(d,function(f){return f.shopCategoryId===c});if(a.length>0){a[0].feedCategories=b}else{var e=new CategoryMap();e.shopCategoryId=c;e.feedCategories=b;d.push(e)}this.categoryMapping=JSON.stringify(d)}function changeIncludeVariationsValue(a){this.includeVariations=a?"1":"0"}function changeAggregatorValue(a){this.isAggregator=a?"1":"0"}function activateCategoryMap(c,b){var d=this.categoryMapping.length>0?JSON.parse(this.categoryMapping):[];var a=jQuery.grep(d,function(f){return f.shopCategoryId===c.toString()});if(a.length<1){var e=new CategoryMap();e.shopCategoryId=c.toString();e.feedCategories=b?"wp_ownCategory":"wp_mainCategory";d.push(e);this.categoryMapping=JSON.stringify(d)}}function deactivateCategoryMap(b){var c=this.categoryMapping.length>0?JSON.parse(this.categoryMapping):[];if(c.length>1){var a=tvc_arrayObjectIndexOf(c,b.toString(),"shopCategoryId");c.splice(a,1);this.categoryMapping=JSON.stringify(c)}else{this.categoryMapping=[]}}function getAttributeId(a){var c=false;for(var b=0;b<this.attributes.length;b++){if(this.attributes[b]["fieldName"]===a){c=this.attributes[b]["rowId"];break}}if(c===false){c=this.attributes.length}return c}function setAttributesStaticValue(b,e,d,c){var a=this.attributes[b]["value"];this.attributes[b]["value"]=tvc_storeSourceValue(e,a,"static",c);this.attributes[b]["isActive"]=!!this.attributes[b]["value"]}function setAttributesSourceValue(b,c,d){var a=this.attributes[b]["value"];this.attributes[b]["value"]=tvc_storeSourceValue(c,a,"source",d)}function setAlternativeAttributesSourceValue(b,f,c){var a={};var d=[];if(this.attributes[b]["value"]){a=JSON.parse(this.attributes[b]["value"]);a.a=addOrRemoveValueInValueString(a.a,c,f,"add")}else{var e={};e[1]=c;d.push(e);a.a=d}this.attributes[b]["value"]=JSON.stringify(a)}function setAttributesCombinedOutputValue(b,c,d){var a=this.attributes[b]["value"];console.log(a);this.attributes[b]["value"]=tvc_storeCombinedValue(c,a,d)}function getAttributesCombinedOutputValue(a,b){var c=this.attributes[a]["value"]?JSON.parse(this.attributes[a]["value"]):{};if(c&&c.m&&c.m[b]&&c.m[b].s&&c.m[b].s.f){return c.m[b].s.f}else{return""}}function removeAttributesCombinedOutputValue(c,d,b){var a=this.attributes[c]["value"];this.attributes[c]["value"]=tvc_removeCombinedValue(d,b,a)}function countAttributesCombinedFields(b){if(this.attributes[b]["value"]){var a=JSON.parse(this.attributes[b]["value"]);if(a.hasOwnProperty("f")){return tvc_countObjectItems(a.f)}else{return 0}}else{return 0}}function setAttributesCategoryValue(b,c){var a=this.attributes[b]["value"];this.attributes[b]["value"]=tvc_storeSourceValue(0,a,"",c)}function rstNrQueries(a){this.attributes[a]["nrQueries"]=0}function addNrQueries(a){var b=this.attributes[a]["nrQueries"];this.attributes[a]["nrQueries"]=b+1}function substrNrQueries(a){var b=this.attributes[a]["nrQueries"];if(b>0){this.attributes[a]["nrQueries"]=b-1}}function addAttributesChangeValue(b,d,e,c){var a=this.attributes[b]["value"];this.attributes[b]["value"]=tvc_storeValueChange(d,e,c,"add",a)}function addAttributesCondition(d,c,e,a){var b=this.attributes[d]["value"];this.attributes[d]["value"]=tvc_storeConditionValue(e,a,b,c)}function addAttributesValueQuery(d,e,c,a){var b=this.attributes[d]["value"];this.attributes[d]["value"]=tvc_storeQueryValue(e,c,b,a)}function setFeedFilterValue(a){this.feedFilter=a}function removeFeedFilterValue(a){this.feedFilter=removeFeedFilterLevel(this.feedFilter,a)}function removeAttributesCondition(c,d,a){var b=this.attributes[c]["value"];this.attributes[c]["value"]=tvc_removeConditionValue(d,a,b)}function removeAttributesValueQuery(c,d,b){var a=this.attributes[c]["value"];this.attributes[c]["value"]=tvc_removeQueryValue(d,b,a)}function removeAttributesEditValue(b,c,d){var a=this.attributes[b]["value"];this.attributes[b]["value"]=tvc_removeEditValuesValue(c,d,a)}function removeAlternativeSource(b,c){var a={};if(this.attributes[b]["value"]){a=JSON.parse(this.attributes[b]["value"]);a.a=addOrRemoveValueInValueString(a.a,"",c,"remove");if(!a.a){delete a.a}this.attributes[b]["value"]=JSON.stringify(a)}}function getAttributesQueries(b,c){var e=this.attributes[b]["value"];var a={};if(e){var d=JSON.parse(e);if(d&&d.hasOwnProperty("m")&&d.m[c]&&d.m[c].hasOwnProperty("c")&&d.m[c].c.length>0){a=d.m[c].c}}return a}function getAttributesValueQueries(b,c){var e=this.attributes[b]["value"];var a={};if(e){var d=JSON.parse(e);if(d&&d.v&&d.v[c]&&d.v[c].hasOwnProperty("q")&&d.v[c].q.length>0){a=d.v[c].q}}return a}function getAttributesValues(b){var d=this.attributes[b]["value"];var a={};if(d){var c=JSON.parse(d);if(c&&"v" in c&&c.v.length>0){a=c.v}}return a}function getFeedFilterValue(a){}function getAlternativeSources(b){var d=this.attributes[b]["value"];var a={};if(d){var c=JSON.parse(d);if(c&&"a" in c&&c.a.length>0){a=c.a}}return a}function getSourceData(a){var c={};c.rowId=a;c.fieldName=this.attributes[a]["fieldName"];c.advisedSource=this.attributes[a]["advisedSource"];var d=this.attributes[a]["value"];if(d){var b=JSON.parse(d);c.mapping=b&&"m" in b?b.m:[];c.changeValues=b&&"v" in b?b.v:[];c.customCondition=!!(b&&"t" in b)}else{c.mapping=[];c.changeValues=[];c.customCondition=false}return c}function getAttributesSources(a){var d=this.attributes[a]["value"];var b={};if(d){var c=JSON.parse(d);if(c&&"s" in c){b=c.s}}return b}function addOrRemoveValueInValueString(b,d,g,e){var c=b?b:[];if(e==="add"){var f={};var a="";f[g]=d;if(c[g-1]&&"q" in c[g-1]){a=c[g-1]["q"]}if(g in f){c.splice(g-1,1)}if(a){f.q=a}c.push(f)}else{c.splice(g-1,1);c=tvc_resortObject(c)}if(tvc_countObjectItems(c)>0){return c}else{return""}}function clearAttributesSourceValue(a,b){if(this.attributes[a]["value"]){this.attributes[a]["value"]=tvc_storeSourceValue(b,this.attributes[a]["value"],"clear","")}else{this.attributes[a]["value"]=""}}function setFeedCustomCategory(b,a){console.log(this.attributes);console.log(a);this.mainCategory=a;var d=b?b:getCustomCategoryAttributeId(this.attributes,a);if(d){console.log(d);var c=this.attributes[d]["value"]?JSON.parse(this.attributes[d]["value"]):{};c.t=a;this.attributes[d]["value"]=JSON.stringify(c)}}function changeCountry(a){this.country=a}function getCustomCategoryAttributeId(a){for(var b=0;b<a.length;b++){console.log(a[b]);var c=a[b]["value"]?JSON.parse(a[b]["value"]):{};console.log(c);if(c.hasOwnProperty("t")){return b}}}function setCategories(a,b,e){if(this.attributes[3]!==undefined){var f=this.attributes[3]["value"]?JSON.parse(this.attributes[3]["value"]):{};var k=tvc_category_separator(e);var h=this.mainCategory;var c=this.attributes[3]["value"]!==undefined?h.split(k).length:0;var j=a.match(/(\d+)$/)[0];if(j==="0"){this.mainCategory=b;this.attributes[3]["value"]='{"t":"'+b+'"}'}else{if(c<=j){this.mainCategory+=k+b;this.attributes[3]["value"]='{"t":"'+f.t+k+b+'"}'}else{var g=0;for(var d=0;d<j;d++){g=h.indexOf(k,g+1)}h=h.substring(0,g);if(b!=="0"){this.mainCategory=h+k+b;this.attributes[3]["value"]='{"t":"'+h+k+b+'"}'}else{this.mainCategory=h;this.attributes[3]["value"]='{"t":"'+h+'"}'}}}}}function setSchedule(d,a,b,c){this.updateSchedule=d+":"+a+":"+b+":"+c}function activateFeedsAttribute(a){this.attributes[a]["isActive"]=true}function deactivateFeedsAttribute(a){if(this.attributes[a]["fieldLevel"]!=="1"){var b=this.attributes[a]["value"]?JSON.parse(this.attributes[a]["value"]):{};this.attributes[a]["isActive"]=false;if(b&&!"t" in b){this.attributes[a]["value"]=""}}else{this.attributes[a]["isActive"]=true}}function checkCustomName(b){var a=false;for(var c=0;c<this.attributes.length;c++){if(this.attributes[c]["fieldName"]===b){a=true}}return a}function getFeedType(){return this.feedType}function removeAttribute(a){this.attributes.splice(a,1)}function cleanUnusedAttributes(){if(this.attributes.length>0){for(var a=0;a<this.attributes.length;a++){if(this.attributes[a]["isActive"]!==true){this.attributes.splice(a,1);a--}else{if(this.attributes[a]["advisedSource"]===undefined&&getSourceString(this.attributes[a]["value"])===""){this.attributes.splice(a,1);a--}}}}}function clearAttributes(){this.attributes=[]};
includes/application/tvc-cron-functions.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package TVC Product Feed Manager/Application/Functions
4
+ * @version 1.3.0
5
+ */
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+ /**
11
+ * Activates the feed update schedules using Cron Jobs
12
+ */
13
+ function tvc_update_feeds() {
14
+ // include the required WordPress files
15
+ require_once( ABSPATH . 'wp-load.php' );
16
+ require_once( ABSPATH . 'wp-admin/includes/admin.php' );
17
+ require_once( ABSPATH . 'wp-admin/includes/file.php' ); // required for using the file system
18
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); // required to prevent a fatal error about not finding the is_plugin_active function
19
+ // include all product feed manager files
20
+ require_once( ENHANCAD_PLUGIN_DIR . 'includes/user-interface/tvc-messaging-functions.php' );
21
+ //require_once( ENHANCAD_PLUGIN_DIR . 'includes/tvc-wpincludes.php' );
22
+ //require_once( ENHANCAD_PLUGIN_DIR . 'includes/data/tvc-admin-functions.php' );
23
+ //require_once( ENHANCAD_PLUGIN_DIR . 'includes/user-interface/tvc-url-functions.php' );
24
+ //require_once( ENHANCAD_PLUGIN_DIR . 'includes/application/tvc-feed-processing-support.php' );
25
+ //require_once( ENHANCAD_PLUGIN_DIR . 'includes/application/tvc-feed-processor-functions.php' );
26
+
27
+ // WooCommerce needs to be installed and active
28
+ if ( ! tvc_wc_installed_and_active() ) {
29
+ tvc_write_log_file( 'Tried to start the auto update process but failed because WooCommerce is not installed.' );
30
+ exit;
31
+ }
32
+
33
+ // Feed Manager requires at least WooCommerce version 3.0.0
34
+ if ( ! tvc_wc_min_version_required() ) {
35
+ tvc_write_log_file( sprintf( 'Tried to start the auto update process but failed because WooCommerce is older than version %s', TVC_MIN_REQUIRED_WC_VERSION ) );
36
+ exit;
37
+ }
38
+
39
+ WC_Post_types::register_taxonomies(); // make sure the woocommerce taxonomies are loaded
40
+ WC_Post_types::register_post_types(); // make sure the woocommerce post types are loaded
41
+
42
+ // include all required classes
43
+ //include_classes();
44
+ //include_channels();
45
+
46
+ do_action( 'tvc_automatic_feed_processing_triggered' );
47
+
48
+ // update the database if required
49
+ tvc_check_db_version();
50
+
51
+ // start updating the active feeds
52
+ $tvc_schedules = new TVC_Schedules();
53
+ $tvc_schedules->update_active_feeds();
54
+ }
includes/application/tvc-feed-processing-support.php ADDED
@@ -0,0 +1,1583 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package TVC Product Feed Manager/Application/Functions
5
+ * @version 1.4.0
6
+ */
7
+
8
+ trait TVC_Processing_Support {
9
+
10
+ protected $_selected_number;
11
+
12
+ /**
13
+ * Returns the correct category for this specific product
14
+ *
15
+ * @param string $id
16
+ * @param string $main_category
17
+ * @param string $category_mapping
18
+ *
19
+ * @return string
20
+ */
21
+ protected function get_mapped_category( $id, $main_category, $category_mapping ) {
22
+ $result = false;
23
+ $support_class = new TVC_Feed_Support();
24
+ $yoast_primary_category = TVC_Taxonomies::get_yoast_primary_cat( $id );
25
+ $yoast_cat_is_selected = $yoast_primary_category ? $support_class->category_is_selected( $yoast_primary_category[0]->term_id, $category_mapping ) : false;
26
+
27
+ $product_categories = $yoast_primary_category && false !== $yoast_cat_is_selected ? $yoast_primary_category :
28
+ wp_get_post_terms( $id, 'product_cat', array( 'taxonomy' => 'product_cat' ) ); // get the categories from a specific product in the shop
29
+
30
+ if ( $product_categories && ! is_wp_error( $product_categories ) ) {
31
+ // loop through each category
32
+ foreach ( $product_categories as $category ) {
33
+ // check if this category is selected in the category mapping
34
+ $shop_category_id = $support_class->category_is_selected( $category->term_id, $category_mapping );
35
+
36
+ // only add this product when at least one of the categories is selected in the category mapping
37
+ if ( false !== $shop_category_id ) {
38
+ switch ( $category_mapping[ $shop_category_id ]->feedCategories ) {
39
+ case 'wp_mainCategory':
40
+ $result = $main_category;
41
+ break;
42
+
43
+ case 'wp_ownCategory':
44
+ $result = TVC_Taxonomies::get_shop_categories( $id, ' > ' );
45
+ break;
46
+
47
+ default:
48
+ $result = $category_mapping[ $shop_category_id ]->feedCategories;
49
+ }
50
+
51
+ // found a selected category so now return the result
52
+ return $result; // fixed ticket #1117
53
+
54
+ } else { // if this product was not selected in the category mapping, it is possible it has been filtered in so map to the default category
55
+ $result = $main_category;
56
+ }
57
+ }
58
+ } else {
59
+ if ( is_wp_error( $product_categories ) ) {
60
+ echo tvc_handle_wp_errors_response(
61
+ $product_categories,
62
+ sprintf(
63
+ /* translators: %s: link to the support page */
64
+ esc_html__( '2131 - Please try to refresh the page and open a support ticket at %s if the issue persists.', 'tvc-product-feed-manager'),
65
+ TVC_SUPPORT_PAGE_URL
66
+ )
67
+ );
68
+ }
69
+
70
+ return false;
71
+ }
72
+
73
+ return $result;
74
+ }
75
+
76
+ /**
77
+ * Checks if this product has been filtered out of the feed
78
+ *
79
+ * @param string $feed_filter_strings
80
+ * @param array $product_data
81
+ *
82
+ * @return boolean
83
+ */
84
+ protected function is_product_filtered( $feed_filter_strings, $product_data ) {
85
+ if ( $feed_filter_strings ) {
86
+ return $this->filter_result( json_decode( $feed_filter_strings[0]['meta_value'] ), $product_data ) ? true : false;
87
+ } else {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * @param $feed_id
94
+ * @return array
95
+ */
96
+ protected function get_meta_parent_ids( $feed_id ) {
97
+ $queries_class = new TVC_Queries();
98
+
99
+ $query_result = $queries_class->get_meta_parents( $feed_id );
100
+ $ids = array();
101
+
102
+ foreach ( $query_result as $result ) {
103
+ array_push( $ids, $result['ID'] );
104
+ }
105
+
106
+ return $ids;
107
+ }
108
+
109
+ /**
110
+ * return an array with source column names from an attribute string
111
+ *
112
+ * @param string $value_string
113
+ *
114
+ * @return array
115
+ */
116
+ protected function get_source_columns_from_attribute_value( $value_string ) {
117
+ $source_columns = array();
118
+
119
+ $value_object = json_decode( $value_string );
120
+
121
+ if ( property_exists( $value_object, 'm' ) ) {
122
+ foreach ( $value_object->m as $source ) {
123
+ // TODO: I guess I should further reduce the "if" loops by combining them more then now
124
+ if ( is_object( $source ) && property_exists( $source, 's' ) ) {
125
+ if ( property_exists( $source->s, 'source' ) ) {
126
+ if ( 'combined' !== $source->s->source ) {
127
+ array_push( $source_columns, $source->s->source );
128
+ } else {
129
+ if ( property_exists( $source->s, 'f' ) ) {
130
+ $source_columns = array_merge( $source_columns, $this->get_combined_sources_from_combined_string( $source->s->f ) );
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ return $source_columns;
138
+ }
139
+
140
+ /**
141
+ * return an array with condition column names from an attribute string
142
+ *
143
+ * @param string $value_string
144
+ *
145
+ * @return array
146
+ */
147
+ protected function get_condition_columns_from_attribute_value( $value_string ) {
148
+ $condition_columns = array();
149
+
150
+ $value_object = json_decode( $value_string );
151
+
152
+ if ( property_exists( $value_object, 'm' ) ) {
153
+ foreach ( $value_object->m as $source ) {
154
+ if ( is_object( $source ) && property_exists( $source, 'c' ) ) {
155
+ for ( $i = 0; $i < count( $source->c ); $i ++ ) {
156
+ array_push( $condition_columns, $this->get_names_from_string( $source->c[ $i ]->{$i + 1} ) );
157
+ }
158
+ }
159
+ }
160
+ }
161
+ return $condition_columns;
162
+ }
163
+
164
+ /**
165
+ * return an array with query column names from an attribute string
166
+ *
167
+ * @param string $value_string
168
+ *
169
+ * @return array
170
+ */
171
+ protected function get_queries_columns_from_attribute_value( $value_string ) {
172
+ $query_columns = array();
173
+
174
+ $value_object = json_decode( $value_string );
175
+
176
+ if ( property_exists( $value_object, 'v' ) ) {
177
+ foreach ( $value_object->v as $changed_value ) {
178
+ if ( property_exists( $changed_value, 'q' ) ) {
179
+ for ( $i = 0; $i < count( $changed_value->q ); $i ++ ) {
180
+ array_push( $query_columns, $this->get_names_from_string( $changed_value->q[ $i ]->{$i + 1} ) );
181
+ }
182
+ }
183
+ }
184
+ }
185
+ return $query_columns;
186
+ }
187
+
188
+ /**
189
+ * extract a column name from a string
190
+ *
191
+ * @param string $string
192
+ *
193
+ * @return array
194
+ */
195
+ protected function get_names_from_string( $string ) {
196
+ $condition_string_array = explode( '#', $string );
197
+
198
+ return $condition_string_array[1];
199
+ }
200
+
201
+ /**
202
+ * split the combined string into single combination items
203
+ *
204
+ * @param string $combined_string
205
+ *
206
+ * @return array
207
+ */
208
+ public function get_combined_sources_from_combined_string( $combined_string ) {
209
+ $result = array();
210
+ $combined_string_array = explode( '|', $combined_string );
211
+
212
+ array_push( $result, $combined_string_array[0] );
213
+
214
+ for ( $i = 1; $i < count( $combined_string_array ); $i ++ ) {
215
+ $a = explode( '#', $combined_string_array[ $i ] );
216
+ if ( array_key_exists( 1, $a ) ) {
217
+ array_push( $result, $a[1] );
218
+ }
219
+ }
220
+
221
+ return $result;
222
+ }
223
+
224
+ /**
225
+ * Gets the meta data from a specific field
226
+ *
227
+ * @param string $field
228
+ * @param stdClass $attributes
229
+ *
230
+ * @return stdClass attribute
231
+ */
232
+ protected function get_meta_data_from_specific_field( $field, $attributes ) {
233
+ $i = 0;
234
+
235
+ while ( true ) {
236
+ if ( $attributes[ $i ]->fieldName !== $field ) {
237
+ $i ++;
238
+ if ( $i > 1000 ) {
239
+ break;
240
+ }
241
+ } else {
242
+ return $attributes[ $i ];
243
+ }
244
+ }
245
+
246
+ return new stdClass();
247
+ }
248
+
249
+ /**
250
+ * Generate the value of a field based on what the user has selected in filters, combined data, static data eg.
251
+ *
252
+ * @param array $product_data
253
+ * @param stdClass $field_meta_data
254
+ * @param string $main_category_feed_title
255
+ * @param string $row_category
256
+ * @param string $feed_language
257
+ * @param array $relation_table
258
+ *
259
+ * @return array Returns an key=>value array of a specific product field where the key contains the field name and the value the field value
260
+ */
261
+ protected function process_product_field( $product_data, $field_meta_data, $main_category_feed_title, $row_category, $feed_language, $relation_table ) {
262
+
263
+ $product_object[ $field_meta_data->fieldName ] = $this->get_correct_field_value(
264
+ $field_meta_data,
265
+ $product_data,
266
+ $main_category_feed_title,
267
+ $row_category,
268
+ $feed_language,
269
+ $relation_table
270
+ );
271
+
272
+ return $product_object;
273
+ }
274
+
275
+ /**
276
+ * Processes a single field of a single product in the feed
277
+ *
278
+ * @param stdClass $field_meta_data containing the meta data of the field
279
+ * @param array $product_data containing the product data of the field
280
+ * @param string $main_category_feed_title main category title
281
+ * @param string $row_category complete category string
282
+ * @param string $feed_language language of the feed
283
+ * @param array $relation_table table with the shop and merchant category relations
284
+ *
285
+ * @return string
286
+ */
287
+ protected function get_correct_field_value( $field_meta_data, $product_data, $main_category_feed_title, $row_category, $feed_language, $relation_table ) {
288
+ $this->_selected_number = 0;
289
+
290
+ // do not process category strings, but only fields that are requested
291
+ if ( property_exists( $field_meta_data, 'fieldName' ) && $field_meta_data->fieldName !== $main_category_feed_title
292
+ && $this->meta_data_contains_category_data( $field_meta_data ) === false ) {
293
+
294
+ $value_object = property_exists( $field_meta_data, 'value' ) && '' !== $field_meta_data->value ? json_decode( $field_meta_data->value ) : new stdClass();
295
+
296
+ if ( property_exists( $field_meta_data, 'value' ) && '' !== $field_meta_data->value && property_exists( $value_object, 'm' ) ) { // seems to be something we need to work on
297
+ $advised_source = property_exists( $field_meta_data, 'advisedSource' ) ? $field_meta_data->advisedSource : '';
298
+
299
+ // get the end value depending on the filter settings
300
+ $end_row_value = $this->get_correct_end_row_value( $value_object->m, $product_data, $advised_source );
301
+
302
+ } else { // no queries, edit values or alternative sources for this field
303
+
304
+ if ( property_exists( $field_meta_data, 'advisedSource' ) && '' !== $field_meta_data->advisedSource ) {
305
+ $db_title = $field_meta_data->advisedSource;
306
+ } else {
307
+ $support_class = new TVC_Feed_Support();
308
+ $source_title = property_exists( $field_meta_data, 'fieldName' ) ? $field_meta_data->fieldName : '';
309
+ $db_title = $support_class->find_relation( $source_title, $relation_table );
310
+ }
311
+
312
+ $end_row_value = array_key_exists( $db_title, $product_data ) ? $product_data[ $db_title ] : '';
313
+ }
314
+
315
+ // change value if requested
316
+ if ( property_exists( $field_meta_data, 'value' ) && '' !== $field_meta_data->value && property_exists( $value_object, 'v' ) ) {
317
+ $pos = $this->_selected_number;
318
+
319
+ if ( property_exists( $value_object, 'm' ) && property_exists( $value_object->m[ $pos ], 's' ) ) {
320
+ $combination_string = property_exists( $value_object->m[ $pos ]->s, 'f' ) ? $value_object->m[ $pos ]->s->f : false;
321
+ $is_money = property_exists( $value_object->m[ $pos ]->s, 'source' ) ? tvc_meta_key_is_money( $value_object->m[ $pos ]->s->source ) : false;
322
+ } else {
323
+ $combination_string = false;
324
+ $is_money = false;
325
+ }
326
+
327
+ $row_value = ! $is_money ? $end_row_value : tvc_prep_money_values( $end_row_value . $feed_language );
328
+ $end_row_value = $this->get_edited_end_row_value( $value_object->v, $row_value, $product_data, $combination_string, $feed_language );
329
+ }
330
+ } else {
331
+ $end_row_value = $row_category;
332
+ }
333
+
334
+ return $end_row_value;
335
+ }
336
+
337
+ /**
338
+ * @param $value
339
+ * @param $product_data
340
+ * @param $advised_source
341
+ * @return array|mixed|string
342
+ */
343
+ protected function get_correct_end_row_value( $value, $product_data, $advised_source ) {
344
+ $end_row_value = '';
345
+ $nr_values = count( $value ); // added @since 1.9.4
346
+ $value_counter = 1; // added @since 1.9.4
347
+
348
+ foreach ( $value as $filter ) {
349
+ if ( true === $this->get_filter_status( $filter, $product_data ) && '' === $end_row_value ) {
350
+
351
+ $end_row_value = $this->get_row_source_data( $filter, $product_data, $advised_source );
352
+ break;
353
+ } else {
354
+ // no "or else" value seems to be selected
355
+ if ( $value_counter >= $nr_values ) {
356
+ return $end_row_value;
357
+ } // added @since 1.9.4
358
+
359
+ $this->_selected_number ++;
360
+ }
361
+
362
+ $value_counter ++; // added @since 1.9.4
363
+ }
364
+
365
+ // not found a condition that was correct so lets take the "for all other products" data to fetch the correct row_value
366
+ if ( '' === $end_row_value ) {
367
+ $end_row_value = $this->get_row_source_data( end( $value ), $product_data, $advised_source );
368
+ }
369
+
370
+ return $end_row_value;
371
+ }
372
+
373
+ /**
374
+ * Removes links from a the post content and post excerpts in a product data array.
375
+ *
376
+ * @since 2.6.0
377
+ *
378
+ * @param $product_data array
379
+ */
380
+ protected function remove_links_from_product_data_description( &$product_data ) {
381
+ $pattern = '#<a.*?>(.*?)</a>#i'; // link pattern
382
+ $replacement = '\1';
383
+
384
+ if ( array_key_exists( 'post_content', $product_data ) ) {
385
+ $product_data['post_content'] = preg_replace( $pattern, $replacement, $product_data['post_content'] );
386
+ }
387
+
388
+ if ( array_key_exists( 'post_excerpt', $product_data ) ) {
389
+ $product_data['post_excerpt'] = preg_replace( $pattern, $replacement, $product_data['post_excerpt'] );
390
+ }
391
+ }
392
+
393
+ /**
394
+ * @param $filter
395
+ * @param $product_data
396
+ * @return bool
397
+ */
398
+ protected function get_filter_status( $filter, $product_data ) {
399
+ if ( property_exists( $filter, 'c' ) ) {
400
+ // check if the query is true for this field
401
+ return $this->filter_result( $filter->c, $product_data );
402
+ } else {
403
+ // apparently there is no condition so the result is always true
404
+ return true;
405
+ }
406
+ }
407
+
408
+ /**
409
+ * @param $conditions
410
+ * @param $product_data
411
+ * @return bool
412
+ */
413
+ protected function filter_result( $conditions, $product_data ) {
414
+ $query_results = array();
415
+ $support_class = new TVC_Feed_Support();
416
+
417
+ // run each query on the data
418
+ foreach ( $conditions as $condition ) {
419
+ $condition_string = $support_class->get_query_string_from_query_object( $condition );
420
+
421
+ $query_split = explode( '#', $condition_string );
422
+
423
+ $row_result = $support_class->check_query_result_on_specific_row( $query_split, $product_data ) === true ? 'false' : 'true';
424
+
425
+ array_push( $query_results, $query_split[0] . '#' . $row_result );
426
+ }
427
+
428
+ // return the final filter result, based on the specific results
429
+ return $this->connect_query_results( $query_results );
430
+ }
431
+
432
+ /**
433
+ * Recieves an array with condition results and generates a single end result based on the "and" or "or"
434
+ * connection between the conditions
435
+ *
436
+ * @param array with $results
437
+ *
438
+ * @return boolean
439
+ */
440
+ protected function connect_query_results( $results ) {
441
+ $and_results = array();
442
+ $end_result = true;
443
+ $or_results = array();
444
+
445
+ if ( count( $results ) > 0 ) {
446
+ foreach ( $results as $query_result ) {
447
+ $result_split = explode( '#', $query_result );
448
+
449
+ if ( '2' === $result_split[0] ) {
450
+ array_push( $or_results, $and_results ); // store the current "and" result for processing as "or" result
451
+
452
+ $and_results = array(); // clear the "and" array
453
+ }
454
+
455
+ $and_result = $result_split[1]; // === 'false' ? 'false' : 'true';
456
+
457
+ array_push( $and_results, $and_result );
458
+ }
459
+
460
+ if ( count( $and_results ) > 0 ) {
461
+ array_push( $or_results, $and_results );
462
+ }
463
+
464
+ if ( count( $or_results ) > 0 ) {
465
+ $end_result = false;
466
+
467
+ foreach ( $or_results as $or_result ) {
468
+ $a = true;
469
+
470
+ foreach ( $or_result as $and_array ) {
471
+ if ( 'false' === $and_array ) {
472
+ $a = false;
473
+ }
474
+ }
475
+
476
+ if ( $a ) {
477
+ $end_result = true;
478
+ }
479
+ }
480
+ } else { // no "or" results found
481
+ $end_result = false;
482
+ }
483
+ } else {
484
+ $end_result = false;
485
+ }
486
+
487
+ return $end_result;
488
+ }
489
+
490
+ /**
491
+ * @param $filter
492
+ * @param $product_data
493
+ * @param $advised_source
494
+ * @return array|mixed|string
495
+ */
496
+ protected function get_row_source_data( $filter, $product_data, $advised_source ) {
497
+ $row_source_data = '';
498
+
499
+ if ( property_exists( $filter, 's' ) ) {
500
+ if ( property_exists( $filter->s, 'static' ) ) {
501
+ $row_source_data = $filter->s->static;
502
+ } elseif ( property_exists( $filter->s, 'source' ) ) {
503
+ if ( 'combined' !== $filter->s->source ) {
504
+ $row_source_data = array_key_exists( $filter->s->source, $product_data ) ? $product_data[ $filter->s->source ] : '';
505
+ } else {
506
+ $row_source_data = $this->generate_combined_string( $filter->s->f, $product_data );
507
+ }
508
+ }
509
+ } else {
510
+ // return the advised source data
511
+ if ( '' !== $advised_source ) {
512
+ $row_source_data = array_key_exists( $advised_source, $product_data ) ? $product_data[ $advised_source ] : '';
513
+ }
514
+ }
515
+
516
+ return $row_source_data;
517
+ }
518
+
519
+ /**
520
+ * @param $combined_sources
521
+ * @param $row
522
+ * @return array|string
523
+ */
524
+ protected function generate_combined_string( $combined_sources, $row ) {
525
+ $source_selectors_array = explode( '|', $combined_sources ); //split the combined source string in an array containing every single source
526
+ $values_class = new TVC_Feed_Value_Editors();
527
+ $separators = $values_class->combination_separators(); // array with all possible separators
528
+
529
+ // if one of the row results is an array, the final output needs to be an array
530
+ $result_is_array = $this->check_if_any_source_has_array_data( $source_selectors_array, $row );
531
+ $result = $result_is_array ? array() : '';
532
+
533
+ if ( ! $result_is_array ) {
534
+ $result = $this->make_combined_string( $source_selectors_array, $separators, $row, false );
535
+ } else {
536
+ for ( $i = 0; $i < count( $result_is_array ); $i ++ ) {
537
+ $combined_string = $this->make_combined_string( $source_selectors_array, $separators, $row, $i );
538
+ array_push( $result, $combined_string );
539
+ }
540
+ }
541
+
542
+ return $result;
543
+ }
544
+
545
+ /**
546
+ * Distracts the keys from the $sources string (separated by a #) and looks if any of these keys
547
+ * are linked to an array in the $data_row
548
+ *
549
+ * @param array $sources
550
+ * @param array $data_row
551
+ *
552
+ * @return array|bool from the data_row or false
553
+ */
554
+ protected function check_if_any_source_has_array_data( $sources, $data_row ) {
555
+ foreach ( $sources as $source ) {
556
+ $split_source = explode( '#', $source );
557
+
558
+ if ( count( $split_source ) > 1 && 'static' === $split_source[1] ) {
559
+ $last_key = 'static';
560
+ } elseif ( 'static' === $split_source[0] ) {
561
+ $last_key = 'static';
562
+ } else {
563
+ $last_key = array_pop( $split_source );
564
+ }
565
+
566
+ if ( array_key_exists( $last_key, $data_row ) && is_array( $data_row[ $last_key ] ) ) {
567
+ return $data_row[ $last_key ];
568
+ }
569
+ }
570
+
571
+ return false;
572
+ }
573
+
574
+ /**
575
+ * @param $meta_data
576
+ * @return bool
577
+ */
578
+ protected function meta_data_contains_category_data( $meta_data ) {
579
+ if ( ! property_exists( $meta_data, 'value' ) || empty( $meta_data->value ) ) {
580
+ return false;
581
+ }
582
+
583
+ $meta_obj = json_decode( $meta_data->value );
584
+
585
+ return property_exists( $meta_obj, 't' ) ? true : false;
586
+ }
587
+
588
+ /**
589
+ * @param $change_parameters
590
+ * @param $original_output
591
+ * @param $product_data
592
+ * @param $combination_string
593
+ * @param $feed_language
594
+ * @return float|int|mixed|string
595
+ */
596
+ protected function get_edited_end_row_value( $change_parameters, $original_output, $product_data, $combination_string, $feed_language ) {
597
+ $result_is_filtered = false;
598
+ $support_class = new TVC_Feed_Support();
599
+ $y = 0;
600
+ $final_output = '';
601
+
602
+ for ( $i = 0; $i < ( count( $change_parameters ) - 1 ); $i ++ ) {
603
+ if ( property_exists( $change_parameters[ $i ], 'q' ) ) {
604
+ $filter_result = $this->filter_result( $change_parameters[ $i ]->q, $product_data );
605
+
606
+ if ( true === $filter_result ) {
607
+ $combined_data_elements = $combination_string ? $this->get_combined_elements( $product_data, $combination_string ) : '';
608
+ $final_output = $support_class->edit_value(
609
+ $original_output,
610
+ $change_parameters[ $i ]->{$i + 1},
611
+ $combination_string,
612
+ $combined_data_elements,
613
+ $feed_language
614
+ );
615
+
616
+ $result_is_filtered = true;
617
+ }
618
+ }
619
+
620
+ $y ++;
621
+ }
622
+
623
+ if ( false === $result_is_filtered ) {
624
+ $combined_data_elements = $combination_string ? $this->get_combined_elements( $product_data, $combination_string ) : '';
625
+ $final_output = $support_class->edit_value(
626
+ $original_output,
627
+ $change_parameters[ $y ]->{$y + 1},
628
+ $combination_string,
629
+ $combined_data_elements,
630
+ $feed_language
631
+ );
632
+ }
633
+
634
+ return $final_output;
635
+ }
636
+
637
+ /**
638
+ * @param $product_data
639
+ * @param $combination_string
640
+ * @return array
641
+ */
642
+ protected function get_combined_elements( $product_data, $combination_string ) {
643
+ $result = array();
644
+ $found_all_data = true;
645
+
646
+ $combination_elements = explode( '|', $combination_string );
647
+
648
+ if ( false === strpos( $combination_elements[0], 'static#' ) ) {
649
+ if ( array_key_exists( $combination_elements[0], $product_data ) ) {
650
+ array_push( $result, $product_data[ $combination_elements[0] ] );
651
+ } else {
652
+ $found_all_data = false;
653
+ }
654
+ } else {
655
+ $element = explode( '#', $combination_elements[0] );
656
+ array_push( $result, $element[1] );
657
+ }
658
+
659
+ for ( $i = 1; $i <= count( $combination_elements ) - 1; $i ++ ) {
660
+ $pos = strpos( $combination_elements[ $i ], '#' );
661
+ $selector = substr( $combination_elements[ $i ], ( false !== $pos ? $pos + 1 : 0 ) );
662
+
663
+ if ( substr( $selector, 0, 7 ) === 'static#' ) {
664
+ $selector = explode( '#', $selector );
665
+ array_push( $result, $selector[1] );
666
+ } elseif ( array_key_exists( $selector, $product_data ) ) {
667
+ array_push( $result, $product_data[ $selector ] );
668
+ } else {
669
+ //array_push( $result, $selector );
670
+ $found_all_data = false;
671
+ }
672
+ }
673
+
674
+ if ( $found_all_data ) {
675
+ return $result;
676
+ } else {
677
+ $message = sprintf( 'Missing the data for one or both combined elements of the combination %s in the product with id %s.', $combination_string, $product_data['ID'] );
678
+ do_action( 'tvc_feed_generation_message', $this->_feed_data->feedId, $message );
679
+ return array();
680
+ }
681
+ }
682
+
683
+ /**
684
+ * @param $source_selectors_array
685
+ * @param $separators
686
+ * @param $row
687
+ * @param $array_pos
688
+ * @return string
689
+ */
690
+ protected function make_combined_string( $source_selectors_array, $separators, $row, $array_pos ) {
691
+ $combined_string = '';
692
+
693
+ foreach ( $source_selectors_array as $source ) {
694
+ $split_source = explode( '#', $source );
695
+
696
+ // get the separator
697
+ $separators_id = count( $split_source ) > 1 && 'static' !== $split_source[0] ? $split_source[0] : 0;
698
+ $sep = $separators[ $separators_id ];
699
+
700
+ $data_key = count( $split_source ) > 1 && 'static' !== $split_source[0] ? $split_source[1] : $split_source[0];
701
+
702
+ if ( ( array_key_exists( $data_key, $row ) && $row[ $data_key ] ) || 'static' === $data_key ) {
703
+ if ( 'static' !== $data_key && ! is_array( $row[ $data_key ] ) ) { // not static and no array
704
+ $combined_string .= $sep;
705
+ $combined_string .= 'static' !== $data_key ? $row[ $data_key ] : $split_source[2];
706
+ } elseif ( 'static' === $data_key ) { // static inputs
707
+ $static_string = count( $split_source ) > 2 ? $split_source[2] : $split_source[1];
708
+ $combined_string .= $sep . $static_string;
709
+ } else { // array inputs
710
+ $input_array = $row[ $data_key ][ $array_pos ];
711
+ $combined_string .= $sep . $input_array;
712
+ }
713
+ }
714
+ }
715
+
716
+ return $combined_string;
717
+ }
718
+
719
+ /**
720
+ * get an array with the relations between the WooCommerce fields and the channel fields
721
+ *
722
+ * @return array
723
+ */
724
+ public function get_channel_to_woocommerce_field_relations() {
725
+ $relations = array();
726
+
727
+ foreach ( $this->_feed->attributes as $attribute ) {
728
+
729
+ // get the source name except for the category_mapping field
730
+ if ( 'category_mapping' !== $attribute->fieldName ) {
731
+ $source = $this->get_source_from_attribute( $attribute );
732
+ }
733
+
734
+ if ( ! empty( $source ) ) {
735
+ // correct Google product category source
736
+ if ( 'google_product_category' === $attribute->fieldName ) {
737
+ $source = 'google_product_category';
738
+ }
739
+
740
+ // correct Google identifier exists source
741
+ if ( 'identifier_exists' === $attribute->fieldName ) {
742
+ $source = 'identifier_exists';
743
+ }
744
+
745
+ // fill the relations array
746
+ $a = array(
747
+ 'field' => $attribute->fieldName,
748
+ 'db' => $source,
749
+ );
750
+ array_push( $relations, $a );
751
+ }
752
+ }
753
+
754
+ if ( empty( $relations ) ) {
755
+ tvc_write_log_file( 'Function get_channel_to_woocommerce_field_relations returned zero relations.' );
756
+ }
757
+
758
+ return $relations;
759
+ }
760
+
761
+ /**
762
+ * extract the source name from the attribute string
763
+ *
764
+ * @param array $attribute
765
+ *
766
+ * @return string
767
+ */
768
+ protected function get_source_from_attribute( $attribute ) {
769
+
770
+ $value_source = property_exists( $attribute, 'value' ) ? $this->get_source_from_attribute_value( $attribute->value ) : '';
771
+
772
+ if ( ! empty( $value_source ) ) {
773
+ $source = $value_source;
774
+ } elseif ( property_exists( $attribute, 'advisedSource' ) && '' !== $attribute->advisedSource ) {
775
+ $source = $attribute->advisedSource;
776
+ } else {
777
+ $source = $attribute->fieldName;
778
+ }
779
+
780
+ return $source;
781
+ }
782
+
783
+ /**
784
+ * extract the source value from the attribute string
785
+ *
786
+ * @param string $value
787
+ *
788
+ * @return string
789
+ */
790
+ protected function get_source_from_attribute_value( $value ) {
791
+ $source = '';
792
+
793
+ if ( $value ) {
794
+ $value_string = $this->get_source_string( $value );
795
+
796
+ $value_object = json_decode( $value_string );
797
+
798
+ if ( is_object( $value_object ) && property_exists( $value_object, 'source' ) ) {
799
+ $source = $value_object->source;
800
+ }
801
+ }
802
+
803
+ return $source;
804
+ }
805
+
806
+ /**
807
+ * get the value
808
+ *
809
+ * @param string $value_string
810
+ *
811
+ * @return string
812
+ */
813
+ protected function get_source_string( $value_string ) {
814
+ $source_string = '';
815
+
816
+ if ( ! empty( $value_string ) ) {
817
+ $value_object = json_decode( $value_string );
818
+
819
+ if ( property_exists( $value_object, 'm' ) && property_exists( $value_object->m[0], 's' ) ) {
820
+ $source_string = json_encode( $value_object->m[0]->s );
821
+ }
822
+ }
823
+
824
+ return $source_string;
825
+ }
826
+
827
+ /**
828
+ * makes an xml string of one product including its variations
829
+ *
830
+ * @param array $data
831
+ * @param string $category_name
832
+ * @param string $description_name
833
+ *
834
+ * @return string
835
+ */
836
+ protected function convert_data_to_xml( $data, $category_name, $description_name, $channel ) {
837
+ return $data ? $this->make_xml_string_row( $data, $category_name, $description_name, $channel ) : '';
838
+ }
839
+
840
+ /**
841
+ * makes an xml string for one product
842
+ *
843
+ * @param array $product Contains all the data from the product.
844
+ * @param string $category_name Selected category name.
845
+ * @param string $description_name The name of the description.
846
+ * @param string $channel Contains the channel id.
847
+ *
848
+ * @return string
849
+ */
850
+ protected function make_xml_string_row( $product, $category_name, $description_name, $channel ) {
851
+ $product_node_name = function_exists( 'product_node_name' ) ? product_node_name( $channel ) : 'item';
852
+ $node_pre_tag_name = function_exists( 'get_node_pretag' ) ? get_node_pretag( $channel ) : 'g:';
853
+ $product_node = apply_filters( 'tvc_xml_product_node_name', $product_node_name, $channel );
854
+ $node_pre_tag = apply_filters( 'tvc_xml_product_pre_tag_name', $node_pre_tag_name, $channel );
855
+ $tags_with_sub_tags = $this->_channel_class->keys_that_have_sub_tags();
856
+ $tags_repeated_fields = $this->_channel_class->keys_that_can_be_used_more_than_once();
857
+ $sub_keys_for_subs = $this->_channel_class->sub_keys_for_sub_tags();
858
+
859
+ $this->_channel_class->add_xml_sub_tags( $product, $sub_keys_for_subs, $tags_with_sub_tags, $node_pre_tag );
860
+ $xml_string = "<$product_node>";
861
+
862
+ // for each product value item
863
+ foreach ( $product as $key => $value ) {
864
+ if ( ! is_array( $value ) ) {
865
+ $xml_string .= $this->make_xml_string( $key, $value, $category_name, $description_name, $node_pre_tag, $tags_with_sub_tags, $tags_repeated_fields, $channel );
866
+ } else {
867
+ $xml_string .= $this->make_array_string( $key, $value, $node_pre_tag, $channel );
868
+ }
869
+ }
870
+
871
+ $xml_string .= "</$product_node>";
872
+
873
+ return $xml_string;
874
+ }
875
+
876
+ /**
877
+ * makes an csv string of one product including its variations
878
+ *
879
+ * @param array $data
880
+ * @param array $active_fields
881
+ * @param string $csv_separator
882
+ *
883
+ * @return string
884
+ */
885
+ protected function convert_data_to_csv( $data, $active_fields, $csv_separator ) {
886
+ if ( $data ) {
887
+ if ( count( $data ) > count( $active_fields ) ) {
888
+ $support_class = new TVC_Feed_Support();
889
+ $support_class->correct_active_fields_list( $active_fields );
890
+ }
891
+
892
+ // the first row in a csv file should contain the index, the following rows the data
893
+ return $this->make_comma_separated_string_from_data_array( $data, $active_fields, $this->_feed_data->channel, $csv_separator );
894
+ } else {
895
+ return '';
896
+ }
897
+ }
898
+
899
+ /**
900
+ * makes a tab separated string for a tsv file
901
+ *
902
+ * @param array $data
903
+ *
904
+ * @return string
905
+ */
906
+ protected function convert_data_to_tsv( $data ) {
907
+ if ( $data ) {
908
+ return $this->make_tab_delimited_string_from_data_array( $data );
909
+ } else {
910
+ return '';
911
+ }
912
+ }
913
+
914
+ /**
915
+ * @param $data
916
+ * @return string
917
+ */
918
+ protected function convert_data_to_txt( $data ) {
919
+ if ( $data ) {
920
+ return $this->make_tab_delimited_string_from_data_array( $data );
921
+ } else {
922
+ return '';
923
+ }
924
+ }
925
+
926
+ /**
927
+ * takes one row data and converts it to a tab delimited string
928
+ *
929
+ * @param array $row_data
930
+ *
931
+ * @return string
932
+ */
933
+ protected function make_tab_delimited_string_from_data_array( $row_data ) {
934
+ $row_string = '';
935
+
936
+ foreach ( $row_data as $row_item ) {
937
+ $a_row_item = ! is_array( $row_item ) ? preg_replace( "/\r|\n/", "", $row_item ) : implode( ', ', $row_item );
938
+ $clean_row_item = strip_tags( $a_row_item );
939
+ $row_string .= $clean_row_item . "\t";
940
+ }
941
+
942
+ $row = trim( $row_string ); // removes the tab at the end of the line
943
+
944
+ return $row . "\r\n";
945
+ }
946
+
947
+ /**
948
+ * Takes the data for one row and converts it to a comma separated string that fits into the feed.
949
+ *
950
+ * @param array $row_data Array with the attribute name => attribute data.
951
+ * @param array $active_fields Array containing the attributes that are active and need to go into the feed.
952
+ * @param string $channel Channel id.
953
+ * @param string $separator Requested data separator (default ,).
954
+ *
955
+ * @return string
956
+ */
957
+ public function make_comma_separated_string_from_data_array( $row_data, $active_fields, $channel, $separator = ',' ) {
958
+ $row_string = '';
959
+
960
+ $quotes_not_allowed = channel_requires_no_quotes_on_empty_attributes( $channel );
961
+
962
+ // @since 2.11.0 allows choosing another separator for array data.
963
+ $separator_for_arrays = apply_filters( 'tvc_separator_for_arrays_in_csv_feed', '|' );
964
+
965
+ // Loop through the active attributes.
966
+ foreach ( $active_fields as $row_item ) {
967
+ if ( array_key_exists( $row_item, $row_data ) ) {
968
+ $clean_row_item = ! is_array( $row_data[ $row_item ] ) ? preg_replace( "/\r|\n/", '', $row_data[ $row_item ] ) : implode( $separator_for_arrays, $row_data[ $row_item ] );
969
+ } else {
970
+ $clean_row_item = '';
971
+ }
972
+
973
+ $quotes = $quotes_not_allowed && '' === $clean_row_item ? '' : '"';
974
+
975
+ $remove_double_quotes_from_string = str_replace( '"', "'", $clean_row_item );
976
+ $row_string .= $quotes . $remove_double_quotes_from_string . $quotes . $separator;
977
+ }
978
+
979
+ $row = rtrim( $row_string, $separator ); // Removes the comma at the end of the line.
980
+
981
+ return $row . "\r\n";
982
+ }
983
+
984
+ /**
985
+ * makes the header string for a csv file
986
+ *
987
+ * @param array $active_fields
988
+ * @param string $separator
989
+ *
990
+ * @return string
991
+ */
992
+ protected function make_csv_header_string( $active_fields, $separator ) {
993
+ $header = implode( $separator, $active_fields );
994
+
995
+ return $header . "\r\n";
996
+ }
997
+
998
+ /**
999
+ * make an array of product element strings
1000
+ *
1001
+ * @param string $key
1002
+ * @param array $value
1003
+ * @param string $google_node_pre_tag
1004
+ * @param string $channel
1005
+ *
1006
+ * @return string
1007
+ */
1008
+ protected function make_array_string( $key, $value, $google_node_pre_tag, $channel ) {
1009
+ $xml_strings = '';
1010
+ $tags_with_sub_tags = $this->_channel_class->keys_that_have_sub_tags();
1011
+ $tags_repeated_fields = $this->_channel_class->keys_that_can_be_used_more_than_once();
1012
+
1013
+ for ( $i = 0; $i < count( $value ); $i ++ ) {
1014
+ $xml_key = 'Extra_Afbeeldingen' === $key ? 'Extra_Image_' . ( $i + 1 ) : $key; // required for Beslist.nl
1015
+ $xml_strings .= $this->make_xml_string( $xml_key, $value[ $i ], '', '', $google_node_pre_tag, $tags_with_sub_tags, $tags_repeated_fields, $channel );
1016
+ }
1017
+
1018
+ return $xml_strings;
1019
+ }
1020
+
1021
+ /**
1022
+ * Generates an xml node.
1023
+ *
1024
+ * Returns an xml node for a product tag and uses the product data to make the node.
1025
+ *
1026
+ * @since 1.1.0
1027
+ * @access public
1028
+ *
1029
+ * @param string $key Note id.
1030
+ * @param string $xml_value Note value.
1031
+ * @param string $category_name Category name.
1032
+ * @param string $description_name Description name.
1033
+ * @param string $google_node_pre_tag Pre node tag.
1034
+ * @param array $tags_with_sub_tags Array with tags that have a sub tag construction.
1035
+ * @param array $tags_repeated_fields Array with tags that are allowed to be placed in the feed more than once
1036
+ * @param string $channel Selected channel id.
1037
+ *
1038
+ * @return string Node string in xml format eg. <id>43</id>.
1039
+ */
1040
+ protected function make_xml_string( $key, $xml_value, $category_name, $description_name, $google_node_pre_tag, $tags_with_sub_tags, $tags_repeated_fields, $channel ) {
1041
+ $xml_string = '';
1042
+ $repeated_field = ! in_array( $key, $tags_repeated_fields ) ? false : true;
1043
+ $subtag_sep = apply_filters( 'tvc_sub_tag_separator', '||' );
1044
+
1045
+ if ( substr( $xml_value, 0, 5 ) === '!sub:' ) {
1046
+ $sub_array = explode( "|", $xml_value );
1047
+ $sa = $sub_array[0];
1048
+ $st = explode( ":", $sa );
1049
+ $sub_tag = $st[1];
1050
+ $xml_value = "<$google_node_pre_tag$sub_tag>$sub_array[1]</$google_node_pre_tag$sub_tag>";
1051
+ }
1052
+
1053
+ if ( $repeated_field && ! is_array( $xml_value ) ) {
1054
+ $xml_value = explode( $subtag_sep, $xml_value );
1055
+ }
1056
+
1057
+ // keys to be added in a CDATA bracket to the xml feed
1058
+ $cdata_keys = apply_filters( 'tvc_cdata_keys', array(
1059
+ $category_name,
1060
+ $description_name,
1061
+ 'title'
1062
+ ) );
1063
+
1064
+ if ( ! is_array( $xml_value ) && ! in_array( $key, $tags_with_sub_tags ) ) {
1065
+ if ( in_array( $key, $cdata_keys ) ) {
1066
+ $xml_value = $this->convert_to_character_data_string( $xml_value ); // put in a ![CDATA[...]] bracket
1067
+ } else {
1068
+ $xml_value = $this->convert_to_xml_value( $xml_value );
1069
+ }
1070
+ }
1071
+
1072
+ $google_suffix_exceptions = apply_filters( 'tvc_google_suffux_exceptions', array(
1073
+ 'title',
1074
+ 'link'
1075
+ ) );
1076
+
1077
+ // as of October 2016 google removed the need for a g: suffix only for title and link. Facebook still requires it
1078
+ if ( in_array( $key, $google_suffix_exceptions ) ) {
1079
+ $google_node_pre_tag = $channel === '1' ? '' : $google_node_pre_tag;
1080
+ }
1081
+
1082
+ if ( $key !== '' ) {
1083
+ if ( is_array( $xml_value ) && $repeated_field ) {
1084
+ foreach ( $xml_value as $value_item ) {
1085
+ $xml_string .= $this->add_xml_string( $key, $value_item, $google_node_pre_tag );
1086
+ }
1087
+ } else {
1088
+ $xml_string = $this->add_xml_string( $key, $xml_value, $google_node_pre_tag );
1089
+ }
1090
+ }
1091
+
1092
+ return $xml_string;
1093
+ }
1094
+
1095
+ /**
1096
+ * Generates a single xml line string
1097
+ *
1098
+ * @since 1.9.0
1099
+ *
1100
+ * @param string $key
1101
+ * @param string $xml_value
1102
+ * @param string $google_node_pre_tag
1103
+ *
1104
+ * @return string
1105
+ */
1106
+ protected function add_xml_string( $key, $xml_value, $google_node_pre_tag ) {
1107
+ $not_allowed_characters = array( ' ', '-' );
1108
+ $clean_key = str_replace( $not_allowed_characters, '_', $key );
1109
+
1110
+ return "<$google_node_pre_tag$clean_key>$xml_value</$google_node_pre_tag$clean_key>";
1111
+ }
1112
+
1113
+ /**
1114
+ * converts an ordinary xml string into a CDATA string
1115
+ *
1116
+ * @param string $string
1117
+ *
1118
+ * @return string
1119
+ */
1120
+ protected function convert_to_character_data_string( $string ) {
1121
+ return "<![CDATA[ $string ]]>";
1122
+ }
1123
+
1124
+ /**
1125
+ * can be overridden by a channel specific function in its class-feed.php
1126
+ *
1127
+ * @since 1.9.0
1128
+ *
1129
+ * @param $product array Pointer to the product data.
1130
+ * @param $sub_keys_for_subs array Array with the tags that can be placed in the feed as a sub tag (eg. <loyalty_points><ratio>).
1131
+ * @param $tags_repeated_fields array Array with tags of fields that can have more than one instance in the feed.
1132
+ * @param $node_pre_tag string The channel dependant pre tag (eg. g: for Google Feeds).
1133
+ *
1134
+ * @return array The product with the correct xml tags.
1135
+ */
1136
+ public function add_xml_sub_tags( &$product, $sub_keys_for_subs, $tags_repeated_fields, $node_pre_tag ) {
1137
+ $sub_tags = array_intersect_key( $product, array_flip( $sub_keys_for_subs ) );
1138
+
1139
+ if ( count( $sub_tags ) < 1 ) {
1140
+ return $product;
1141
+ }
1142
+
1143
+ $subtag_sep = apply_filters( 'tvc_sub_tag_separator', '||' );
1144
+ $tags_value = array();
1145
+
1146
+ foreach ( $sub_tags as $key => $value ) {
1147
+ $split = explode( '-', $key );
1148
+
1149
+ if ( in_array( $split[0], $tags_repeated_fields ) ) {
1150
+ $tags_counter = 0;
1151
+ $value_array = is_array( $value ) ? $value : explode( $subtag_sep, $value );
1152
+
1153
+ foreach ( $value_array as $sub_value ) {
1154
+ $prev_string = array_key_exists( $tags_counter, $tags_value ) ? $tags_value[ $tags_counter ] : '';
1155
+ $tags_value[ $tags_counter ] = $prev_string . '<' . $node_pre_tag . $split[1] . '>' . $sub_value . '</' . $node_pre_tag . $split[1] . '>';
1156
+ $tags_counter ++;
1157
+ }
1158
+ } else {
1159
+ $tags_value = array_key_exists( $split[0], $product ) ? $product[ $split[0] ] : '';
1160
+ $tags_value .= '<' . $node_pre_tag . $split[1] . '>' . $value . '</' . $node_pre_tag . $split[1] . '>';
1161
+ }
1162
+
1163
+ unset( $product[ $key ] );
1164
+ $product[ $split[0] ] = $tags_value;
1165
+ }
1166
+
1167
+ return $product;
1168
+ }
1169
+
1170
+ /**
1171
+ * can be overridden by a channel specific function in its class-feed.php
1172
+ *
1173
+ * @since 1.9.0
1174
+ *
1175
+ * @return array
1176
+ */
1177
+ public function keys_that_have_sub_tags() {
1178
+ return array();
1179
+ }
1180
+
1181
+ /**
1182
+ * can be overridden by a channel specific function in its class-feed.php
1183
+ *
1184
+ * @since 2.1.0
1185
+ *
1186
+ * @return array
1187
+ */
1188
+ public function sub_keys_for_sub_tags() {
1189
+ return array();
1190
+ }
1191
+
1192
+ /**
1193
+ * can be overridden by a channel specific function in its class-feed.php
1194
+ *
1195
+ * @since 1.9.0
1196
+ *
1197
+ * @return array
1198
+ */
1199
+ public function keys_that_can_be_used_more_than_once() {
1200
+ return array();
1201
+ }
1202
+
1203
+ /**
1204
+ * replaces certain characters to get a valid xml value
1205
+ *
1206
+ * @param string $value_string
1207
+ *
1208
+ * @return string
1209
+ */
1210
+ public function convert_to_xml_value( $value_string ) {
1211
+ $string_without_tags = strip_tags( $value_string );
1212
+ $prep_string = str_replace(
1213
+ array(
1214
+ '&amp;',
1215
+ '&lt;',
1216
+ '&gt;',
1217
+ '&apos;',
1218
+ '&quot;',
1219
+ '&nbsp;',
1220
+ ),
1221
+ array(
1222
+ '&',
1223
+ '<',
1224
+ '>',
1225
+ '\'',
1226
+ '"',
1227
+ 'nbsp;',
1228
+ ),
1229
+ $string_without_tags
1230
+ );
1231
+
1232
+ $clean_xml_string = str_replace(
1233
+ array(
1234
+ '&',
1235
+ '<',
1236
+ '>',
1237
+ '\'',
1238
+ '"',
1239
+ 'nbsp;',
1240
+ '`',
1241
+ ),
1242
+ array(
1243
+ '&amp;',
1244
+ '&lt;',
1245
+ '&gt;',
1246
+ '&apos;',
1247
+ '&quot;',
1248
+ ' ',
1249
+ '',
1250
+ ),
1251
+ $prep_string
1252
+ );
1253
+
1254
+ return $clean_xml_string;
1255
+ }
1256
+
1257
+ /**
1258
+ * get formal woocommerce custom fields data
1259
+ *
1260
+ * @param string $id
1261
+ * @param string $parent_product_id @since 2.0.9
1262
+ * @param string $field
1263
+ *
1264
+ * @return string
1265
+ */
1266
+ protected function get_custom_field_data( $id, $parent_product_id, $field ) {
1267
+ $custom_string = '';
1268
+ $taxonomy = 'pa_' . $field;
1269
+ $custom_values = get_the_terms( $id, $taxonomy );
1270
+
1271
+ if ( ! $custom_values && 0 !== $parent_product_id ) {
1272
+ $custom_values = get_the_terms( $parent_product_id, $taxonomy );
1273
+ }
1274
+
1275
+ if ( $custom_values ) {
1276
+ foreach ( $custom_values as $custom_value ) {
1277
+ $custom_string .= $custom_value->name . ', ';
1278
+ }
1279
+ }
1280
+
1281
+ return $custom_string ? substr( $custom_string, 0, - 2 ) : '';
1282
+ }
1283
+
1284
+ /**
1285
+ * get third party custom field data
1286
+ *
1287
+ * @since 1.6.0
1288
+ *
1289
+ * @param string $feed_id
1290
+ * @param string $parent_product_id @since 2.0.9
1291
+ * @param string $field
1292
+ *
1293
+ * @return string
1294
+ */
1295
+ protected function get_third_party_custom_field_data( $feed_id, $parent_product_id, $field ) {
1296
+ $result = '';
1297
+ $product_brand = '';
1298
+
1299
+ // YITH Brands plugin
1300
+ if ( get_option( 'yith_wcbr_brands_label' ) === $field ) { // YITH Brands plugin active
1301
+ if ( has_term( '', 'yith_product_brand', $feed_id ) ) {
1302
+ $product_brand = get_the_terms( $feed_id, 'yith_product_brand' );
1303
+ }
1304
+
1305
+ if ( ! $product_brand && 0 !== $parent_product_id && has_term( '', 'yith_product_brand', $parent_product_id ) ) {
1306
+ $product_brand = get_the_terms( $parent_product_id, 'yith_product_brand' );
1307
+ }
1308
+
1309
+ if ( $product_brand && ! is_wp_error( $product_brand ) ) {
1310
+ foreach ( $product_brand as $brand ) {
1311
+ $result .= $brand->name . ', ';
1312
+ }
1313
+ }
1314
+ }
1315
+
1316
+ // WooCommerce Brands plugin
1317
+ if (
1318
+ in_array(
1319
+ 'woocommerce-brands/woocommerce-brands.php',
1320
+ apply_filters(
1321
+ 'active_plugins',
1322
+ get_option( 'active_plugins' )
1323
+ )
1324
+ )
1325
+ ) {
1326
+
1327
+ if ( has_term( '', 'product_brand', $feed_id ) ) {
1328
+ $product_brand = get_the_terms( $feed_id, 'product_brand' );
1329
+ }
1330
+
1331
+ if ( ! $product_brand && 0 !== $parent_product_id && has_term( '', 'product_brand', $parent_product_id ) ) {
1332
+ $product_brand = get_the_terms( $parent_product_id, 'product_brand' );
1333
+ }
1334
+
1335
+ if ( $product_brand && ! is_wp_error( $product_brand ) ) {
1336
+ foreach ( $product_brand as $brand ) {
1337
+ $result .= $brand->name . ', ';
1338
+ }
1339
+ } elseif ( is_wp_error( $product_brand ) ) {
1340
+ do_action( 'tvc_feed_generation_warning', $feed_id, $product_brand ); // @since 2.3.0
1341
+ }
1342
+ }
1343
+
1344
+ return $result ? substr( $result, 0, - 2 ) : '';
1345
+ }
1346
+
1347
+ /**
1348
+ * adds data to the product that require a procedure to get
1349
+ *
1350
+ * @param object $product
1351
+ * @param array $active_field_names
1352
+ * @param string $selected_language
1353
+ * @param string $feed_id
1354
+ *
1355
+ * @return bool
1356
+ */
1357
+ protected function add_procedural_data( &$product, $active_field_names, $selected_language, $feed_id ) {
1358
+ $woocommerce_product = wc_get_product( $product->ID );
1359
+
1360
+ if ( false === $woocommerce_product ) {
1361
+ $msg = sprintf( 'Failed to get the WooCommerce products procedural data from product %s.', $product->ID );
1362
+ do_action( 'tvc_feed_generation_warning', $feed_id, $msg ); // @since 2.3.0
1363
+
1364
+ return false;
1365
+ }
1366
+
1367
+ $woocommerce_parent_id = $woocommerce_product->get_parent_id();
1368
+ $woocommerce_product_parent = $woocommerce_product && ( $woocommerce_product->is_type( 'variable' ) ||
1369
+ $woocommerce_product->is_type( 'variation' ) ) ? wc_get_product( $woocommerce_parent_id ) : null;
1370
+
1371
+ if ( false === $woocommerce_product_parent || null === $woocommerce_product_parent ) {
1372
+ // this product has no parent id so it is possible this is the main of a variable product
1373
+ // So to make sure the general variation data like min_variation_price are available, copy the product
1374
+ // in the parent product
1375
+ $woocommerce_product_parent = $woocommerce_product;
1376
+ }
1377
+
1378
+ if ( in_array( 'shipping_class', $active_field_names ) ) {
1379
+ if ( $woocommerce_product_parent ) {
1380
+ $product->shipping_class = $woocommerce_product_parent->get_shipping_class();
1381
+ } elseif ( $woocommerce_product ) {
1382
+ $product->shipping_class = $woocommerce_product->get_shipping_class();
1383
+ }
1384
+ }
1385
+
1386
+ if ( in_array( 'permalink', $active_field_names ) ) {
1387
+ $permalink = get_permalink( $product->ID );
1388
+ if ( false === $permalink && 0 !== $woocommerce_parent_id ) {
1389
+ $permalink = get_permalink( $woocommerce_parent_id );
1390
+ }
1391
+
1392
+ // WPML support
1393
+ $product->permalink = has_filter( 'tvc_get_wpml_permalink' )
1394
+ ? apply_filters( 'tvc_get_wpml_permalink', $permalink, $selected_language ) : $permalink;
1395
+ }
1396
+
1397
+ if ( in_array( 'attachment_url', $active_field_names ) ) {
1398
+ // WPML support -> Returns an elements ID in the selected language.
1399
+ $object_id = has_filter( 'wpml_object_id' ) ? apply_filters( 'wpml_object_id', $product->ID, 'attachment', true ) : $product->ID;
1400
+ $attachment_url = wp_get_attachment_url( get_post_thumbnail_id( $object_id ) );
1401
+
1402
+ // If the attachment url is empty and the product has a parent try getting the attachment url of the parent.
1403
+ if ( false === $attachment_url && 0 !== $woocommerce_parent_id ) {
1404
+ // WPML support -> Returns an elements ID in the selected language.
1405
+ $parent_object_id = has_filter( 'wpml_object_id' ) ? apply_filters( 'wpml_object_id', $woocommerce_parent_id, 'attachment', true ) : $woocommerce_parent_id;
1406
+ $attachment_url = wp_get_attachment_url( get_post_thumbnail_id( $parent_object_id ) );
1407
+ }
1408
+
1409
+ // WPML support -> Filter the permalink and convert it to a language-specific permalink.
1410
+ $product->attachment_url = has_filter( 'tvc_get_wpml_permalink' )
1411
+ ? apply_filters( 'tvc_get_wpml_permalink', $attachment_url, $selected_language ) : $attachment_url;
1412
+ }
1413
+
1414
+ if ( in_array( 'product_cat', $active_field_names ) ) {
1415
+ $product->product_cat = TVC_Taxonomies::get_shop_categories( $product->ID );
1416
+ if ( '' === $product->product_cat && 0 !== $woocommerce_parent_id ) {
1417
+ $product->product_cat = TVC_Taxonomies::get_shop_categories( $woocommerce_parent_id );
1418
+ }
1419
+ }
1420
+
1421
+ if ( in_array( 'product_cat_string', $active_field_names ) ) {
1422
+ $product->product_cat_string = TVC_Taxonomies::make_shop_taxonomies_string( $product->ID );
1423
+ if ( '' === $product->product_cat_string && 0 !== $woocommerce_parent_id ) {
1424
+ $product->product_cat_string = TVC_Taxonomies::make_shop_taxonomies_string( $woocommerce_parent_id );
1425
+ }
1426
+ }
1427
+
1428
+ if ( in_array( 'last_update', $active_field_names ) ) {
1429
+ $product->last_update = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
1430
+ }
1431
+
1432
+ if ( in_array( '_wp_attachement_metadata', $active_field_names ) ) {
1433
+ $attachment_id = 0 === $woocommerce_parent_id ? $product->ID : $woocommerce_parent_id;
1434
+ $product->_wp_attachement_metadata = $this->get_product_image_gallery( $attachment_id, $selected_language );
1435
+ }
1436
+
1437
+ if ( in_array( 'product_tags', $active_field_names ) ) {
1438
+ $product->product_tags = $this->get_product_tags( $product->ID );
1439
+ }
1440
+
1441
+ if ( in_array( 'wc_currency', $active_field_names ) ) {
1442
+ // WPML support
1443
+ $product->wc_currency = has_filter( 'tvc_get_wpml_currency' )
1444
+ ? apply_filters( 'tvc_get_wpml_currency', get_woocommerce_currency(), $selected_language ) : get_woocommerce_currency();
1445
+ }
1446
+
1447
+ if ( $woocommerce_product_parent && ( $woocommerce_product_parent->is_type( 'variable' ) || $woocommerce_product_parent->is_type( 'variation' ) ) ) {
1448
+ if ( in_array( '_min_variation_price', $active_field_names ) ) {
1449
+ $product->_min_variation_price = $woocommerce_product_parent ? tvc_prep_money_values( $woocommerce_product_parent->get_variation_price(), $selected_language ) : '';
1450
+ }
1451
+
1452
+ if ( in_array( '_max_variation_price', $active_field_names ) ) {
1453
+ $product->_max_variation_price = $woocommerce_product_parent ? tvc_prep_money_values( $woocommerce_product_parent->get_variation_price( 'max' ), $selected_language ) : '';
1454
+ }
1455
+
1456
+ if ( in_array( '_min_variation_regular_price', $active_field_names ) ) {
1457
+ $product->_min_variation_regular_price = $woocommerce_product_parent ? tvc_prep_money_values( $woocommerce_product_parent->get_variation_regular_price(), $selected_language ) : '';
1458
+ }
1459
+
1460
+ if ( in_array( '_max_variation_regular_price', $active_field_names ) ) {
1461
+ $product->_max_variation_regular_price = $woocommerce_product_parent ? tvc_prep_money_values( $woocommerce_product_parent->get_variation_regular_price( 'max' ), $selected_language ) : '';
1462
+ }
1463
+
1464
+ if ( in_array( '_min_variation_sale_price', $active_field_names ) ) {
1465
+ $product->_min_variation_sale_price = $woocommerce_product_parent ? tvc_prep_money_values( $woocommerce_product_parent->get_variation_sale_price(), $selected_language ) : '';
1466
+ }
1467
+
1468
+ if ( in_array( '_max_variation_sale_price', $active_field_names ) ) {
1469
+ $product->_max_variation_sale_price = $woocommerce_product_parent ? tvc_prep_money_values( $woocommerce_product_parent->get_variation_sale_price( 'max' ), $selected_language ) : '';
1470
+ }
1471
+
1472
+ if ( in_array( 'item_group_id', $active_field_names ) ) {
1473
+ $parent_sku = $woocommerce_product_parent ? $woocommerce_product_parent->get_sku() : '';
1474
+
1475
+ if ( $parent_sku ) {
1476
+ $product->item_group_id = $parent_sku; // best practise
1477
+ } elseif ( $woocommerce_product_parent && $woocommerce_parent_id ) {
1478
+ $product->item_group_id = 'GID' . $woocommerce_parent_id;
1479
+ } else {
1480
+ $product->item_group_id = '';
1481
+ }
1482
+ }
1483
+ } else {
1484
+ if ( ! $woocommerce_product_parent->is_type( 'simple' ) && ! $woocommerce_product_parent->is_type( 'grouped' )
1485
+ && ! $woocommerce_product_parent->is_type( 'virtual' ) && ! $woocommerce_product_parent->is_type( 'downloadable' )
1486
+ && ! $woocommerce_product_parent->is_type( 'external' ) ) {
1487
+ $msg = sprintf(
1488
+ 'Product type of product %s could not be identified. The products shows as type %s',
1489
+ $product->ID,
1490
+ function_exists( 'get_product_type' ) ? get_product_type( $product->ID ) : 'unknown'
1491
+ );
1492
+ do_action( 'tvc_feed_generation_warning', $feed_id, $msg ); // @since 2.3.0
1493
+ }
1494
+ }
1495
+
1496
+ // @since 2.1.4
1497
+ if ( in_array( 'empty', $active_field_names ) ) {
1498
+ $product->empty = '';
1499
+ }
1500
+
1501
+ // @since 2.2.0
1502
+ if ( in_array( 'product_type', $active_field_names ) ) {
1503
+ $product->type = $woocommerce_product ? $woocommerce_product->get_type() : 'unknown';
1504
+ }
1505
+
1506
+ // @since 2.2.0
1507
+ if ( in_array( 'product_variation_title_without_attributes', $active_field_names ) ) {
1508
+ $product_title = get_post_field( 'post_title', $product->ID );
1509
+
1510
+ if ( false !== strpos( $product_title, ' - ' ) ) { // assuming that the woocommerce_product_variation_title_attributes_separator is ' - '
1511
+ $title_parts = explode( ' - ', $product_title );
1512
+ $product_title = $title_parts[0];
1513
+ }
1514
+
1515
+ $product->product_variation_title_without_attributes = $product_title;
1516
+ }
1517
+
1518
+ $woocommerce_product = null;
1519
+
1520
+ return true;
1521
+ }
1522
+
1523
+ /**
1524
+ * get additional images
1525
+ *
1526
+ * @param string $post_id
1527
+ * @param string $selected_language
1528
+ *
1529
+ * @return array|string
1530
+ */
1531
+ protected function get_product_image_gallery( $post_id, $selected_language ) {
1532
+ $image_urls = array();
1533
+ $images = 1;
1534
+ $max_nr_images = 10;
1535
+
1536
+ $prdct = wc_get_product( $post_id );
1537
+ $attachment_ids = $prdct->get_gallery_image_ids();
1538
+
1539
+ foreach ( $attachment_ids as $attachment_id ) {
1540
+ $link = wp_get_attachment_url( $attachment_id );
1541
+
1542
+ // WPML support
1543
+ $image_link = has_filter( 'tvc_get_wpml_permalink' )
1544
+ ? apply_filters( 'tvc_get_wpml_permalink', $link, $selected_language ) : $link;
1545
+
1546
+ // correct baseurl for https if required
1547
+ if ( is_ssl() ) {
1548
+ $url = str_replace( 'http://', 'https://', $image_link );
1549
+ } else {
1550
+ $url = $image_link;
1551
+ }
1552
+
1553
+ array_push( $image_urls, $url );
1554
+ $images ++;
1555
+
1556
+ if ( $images > $max_nr_images ) {
1557
+ break;
1558
+ }
1559
+ }
1560
+
1561
+ return ! empty( $image_urls ) ? $image_urls : '';
1562
+ }
1563
+
1564
+ protected function get_product_tags( $id ) {
1565
+ $product_tags_string = '';
1566
+ $product_tag_values = get_the_terms( $id, 'product_tag' );
1567
+ $post_tag_values = get_the_tags( $id );
1568
+
1569
+ if ( $product_tag_values ) {
1570
+ foreach ( $product_tag_values as $product_tag ) {
1571
+ $product_tags_string .= $product_tag->name . ', ';
1572
+ }
1573
+ }
1574
+
1575
+ if ( $post_tag_values ) {
1576
+ foreach ( $post_tag_values as $post_tag ) {
1577
+ $product_tags_string .= $post_tag->name . ', ';
1578
+ }
1579
+ }
1580
+
1581
+ return $product_tags_string ? substr( $product_tags_string, 0, - 2 ) : '';
1582
+ }
1583
+ }
includes/application/tvc-feed-processor-functions.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package TVC Product Review Feed Manager/Functions
5
+ * @version 1.0.0
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ trait TVC_Feed_Processor_Functions {
13
+
14
+ /**
15
+ * Adds a string to the feed
16
+ *
17
+ * @param array $line_data
18
+ *
19
+ * @return boolean
20
+ */
21
+ private function add_file_format_line_to_feed( $line_data ) {
22
+ return false !== file_put_contents( $this->_feed_file_path, $line_data['file_format_line'], FILE_APPEND ) ? true : false;
23
+ }
24
+
25
+ /**
26
+ * Adds an error message to the feed
27
+ *
28
+ * @param array $error_message_data
29
+ *
30
+ * @return boolean
31
+ */
32
+ private function add_error_message_to_feed( $error_message_data ) {
33
+ return false !== file_put_contents( $this->_feed_file_path, $error_message_data['feed_line_message'], FILE_APPEND ) ? true : false;
34
+ }
35
+
36
+ /**
37
+ * register the update in the database
38
+ *
39
+ * @param string $feed_id
40
+ * @param string $feed_name
41
+ * @param string $nr_products
42
+ * @param string $status
43
+ */
44
+ private function register_feed_update( $feed_id, $feed_name, $nr_products, $status = null ) {
45
+ $data_class = new TVC_Data();
46
+
47
+ // register the update and update the feed Last Change time
48
+ $data_class->update_feed_data( $feed_id, tvc_get_file_url( $feed_name ), $nr_products );
49
+
50
+ $actual_status = $status ? $status : $data_class->get_feed_status( $feed_id );
51
+
52
+ if ( '4' !== $actual_status && '5' !== $actual_status && '6' !== $actual_status ) { // no errors
53
+ $data_class->update_feed_status( $feed_id, intval( $status ) ); // put feed on status hold if no errors are reported
54
+ }
55
+ }
56
+
57
+ /**
58
+ * @param $product_id
59
+ * @param $parent_product_id
60
+ * @param $post_columns_query_string
61
+ * @return array|mixed|object|void|null
62
+ */
63
+ private function get_products_main_data( $product_id, $parent_product_id, $post_columns_query_string ) {
64
+ $queries_class = new TVC_Queries();
65
+ $prep_meta_class = new TVC_Feed_Value_Editors();
66
+
67
+ $product_data = $queries_class->read_post_data( $product_id, $post_columns_query_string );
68
+
69
+ // WPML support
70
+ if ( has_filter( 'wpml_translation' ) ) {
71
+ $product_data = apply_filters( 'wpml_translation', $product_data, $this->_feed_data->language );
72
+ }
73
+
74
+ // parent ids are required to get the main data from product variations
75
+ $meta_parent_ids = 0 !== $parent_product_id ? array( $parent_product_id ) : $this->get_meta_parent_ids( $product_id );
76
+
77
+ array_unshift( $meta_parent_ids, $product_id ); // add the product id to the parent ids
78
+
79
+ $meta_data = $queries_class->read_meta_data( $product_id, $parent_product_id, $meta_parent_ids, $this->_pre_data['database_fields']['meta_fields'] );
80
+
81
+ foreach ( $meta_data as $meta ) {
82
+ $meta_value = $prep_meta_class->prep_meta_values( $meta, $this->_feed_data->language );
83
+
84
+ if ( property_exists( $product_data, $meta->meta_key ) ) {
85
+ $meta_key = $meta->meta_key;
86
+
87
+ if ( '' === $product_data->$meta_key ) {
88
+ $product_data = (object) array_merge( (array) $product_data, array( $meta->meta_key => $meta_value ) );
89
+ }
90
+ } else {
91
+ $product_data = (object) array_merge( (array) $product_data, array( $meta->meta_key => $meta_value ) );
92
+ }
93
+ }
94
+
95
+ foreach ( $this->_pre_data['database_fields']['active_custom_fields'] as $field ) {
96
+ $product_data->{$field} = $this->get_custom_field_data( $product_data->ID, $parent_product_id, $field );
97
+ }
98
+
99
+ foreach ( $this->_pre_data['database_fields']['third_party_custom_fields'] as $third_party_field ) {
100
+ $product_data->{$third_party_field} = $this->get_third_party_custom_field_data( $product_data->ID, $parent_product_id, $third_party_field );
101
+ }
102
+
103
+ $this->add_procedural_data( $product_data, $this->_pre_data['column_names'], $this->_feed_data->language, $this->_feed_data->feedId );
104
+
105
+ return $product_data;
106
+ }
107
+ }
includes/application/tvc-support-fields.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package TVC Product Review Feed Manager/Functions
5
+ * @version 1.0.0
6
+ * @since 2.10.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Adds custom fields to the products inventory card that can be used in the feeds.
15
+ */
16
+ function tvc_create_gtin_wc_support_field() {
17
+
18
+ // Add the Brand field.
19
+ woocommerce_wp_text_input(
20
+ array(
21
+ 'id' => 'tvc_product_brand',
22
+ 'label' => 'Product brand',
23
+ 'class' => 'tvc_product_brand',
24
+ 'desc_tip' => true,
25
+ 'description' => esc_html__('Brand name of the product. If the product has no brand name you can use the manufacturer or supplier name.', 'tvc-product-feed-manager' ),
26
+ )
27
+ );
28
+
29
+ // Add the GTIN field.
30
+ woocommerce_wp_text_input(
31
+ array(
32
+ 'id' => 'tvc_product_gtin',
33
+ 'label' => 'Product GTIN',
34
+ 'class' => 'tvc_product_gtin',
35
+ 'desc_tip' => true,
36
+ 'description' => esc_html__('GTIN refers to a products Global Trade Item Number. You can also use a UPC, EAN, JAN, ISBN or ITF-14 number here.', 'tvc-product-feed-manager' ),
37
+ )
38
+ );
39
+
40
+ // Add the MPN field.
41
+ woocommerce_wp_text_input(
42
+ array(
43
+ 'id' => 'tvc_product_mpn',
44
+ 'label' => 'Product MPN',
45
+ 'class' => 'tvc_product_mpn',
46
+ 'desc_tip' => true,
47
+ 'description' => esc_html__('Add your products Manufacturer Part Number (MPN).', 'tvc-product-feed-manager' ),
48
+ )
49
+ );
50
+ }
51
+
52
+ add_action( 'woocommerce_product_options_inventory_product_data', 'tvc_create_gtin_wc_support_field' );
53
+
54
+ /**
55
+ * Saves the custom fields data.
56
+ *
57
+ * @param mixed $post_id Post ID of the product.
58
+ */
59
+ function tvc_save_custom_fields( $post_id ) {
60
+ $product = wc_get_product( $post_id );
61
+
62
+ // Get the custom fields data.
63
+ $brand = isset( $_POST['tvc_product_brand'] ) ? $_POST['tvc_product_brand'] : '';
64
+ $gtin = isset( $_POST['tvc_product_gtin'] ) ? $_POST['tvc_product_gtin'] : '';
65
+ $mpn = isset( $_POST['tvc_product_mpn'] ) ? $_POST['tvc_product_mpn'] : '';
66
+
67
+ // Save the custom fields data.
68
+ $product->update_meta_data( 'tvc_product_brand', sanitize_text_field( $brand ) );
69
+ $product->update_meta_data( 'tvc_product_gtin', sanitize_text_field( $gtin ) );
70
+ $product->update_meta_data( 'tvc_product_mpn', sanitize_text_field( $mpn ) );
71
+
72
+ $product->save();
73
+ }
74
+
75
+ add_action( 'woocommerce_process_product_meta', 'tvc_save_custom_fields' );
76
+
77
+ /**
78
+ * Adds custom fields to the products inventory card of the product variations.
79
+ *
80
+ * @param array $loop
81
+ * @param object $variation_data
82
+ * @param object $variation
83
+ */
84
+ function tvc_create_mpn_wc_variation_support_field( $loop, $variation_data, $variation ) {
85
+
86
+ echo '<div class="options_group form-row form-row-full">';
87
+
88
+ // Add the MPN text field to the variation cards.
89
+ woocommerce_wp_text_input(
90
+ array(
91
+ 'id' => 'tvc_product_mpn[' . $variation->ID . ']',
92
+ 'label' => esc_html__('Product MPN', 'tvc-product-feed-manager'),
93
+ 'desc_tip' => true,
94
+ 'description' => esc_html__('Add your products Manufacturer Part Number (MPN).', 'tvc-product-feed-manager'),
95
+ 'value' => get_post_meta( $variation->ID, 'tvc_product_mpn', true ),
96
+ )
97
+ );
98
+
99
+ echo '</div>';
100
+ }
101
+
102
+ add_action( 'woocommerce_variation_options', 'tvc_create_mpn_wc_variation_support_field', 10, 3 );
103
+
104
+ /**
105
+ * Saves the custom fields data of the product variations.
106
+ *
107
+ * @param int $post_id
108
+ */
109
+ function tvc_save_variation_custom_fields( $post_id ) {
110
+
111
+ // Get the variations mpn.
112
+ $woocommerce_text_field = $_POST['tvc_product_mpn'][ $post_id ];
113
+
114
+ // Update.
115
+ update_post_meta( $post_id, 'tvc_product_mpn', sanitize_text_field( $woocommerce_text_field ) );
116
+ }
117
+
118
+ add_action( 'woocommerce_save_product_variation', 'tvc_save_variation_custom_fields', 10, 2 );
includes/class-enhanced-ecommerce-google-analytics.php CHANGED
File without changes
includes/class-tvc-register-scripts.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * TVC Register Scripts Class.
4
+ *
5
+ * @package TVC Product Feed Manager/Classes
6
+ */
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+ if ( ! class_exists( 'TVC_Register_Scripts' ) ) :
11
+ /**
12
+ * Register Scripts Class
13
+ */
14
+ class TVC_Register_Scripts {
15
+ // @private storage of scripts version
16
+ private $_version_stamp;
17
+ // @private register minified scripts
18
+ private $_js_min;
19
+ public function __construct() {
20
+ $premium_version_nr = TVC_EDD_SL_ITEM_NAME === 'Google Product Feed Manager' ? 'fr-' : 'pr-'; // prefix for version stamp depending on premium or free version
21
+ $action_level = 2; // for future use
22
+ $this->_version_stamp = defined( 'WP_DEBUG' ) && WP_DEBUG ? time() : $premium_version_nr . '1.0';
23
+ $this->_js_min = defined( 'WP_DEBUG' ) && WP_DEBUG ? '' : '.min';
24
+ // add hooks
25
+ add_action( 'admin_enqueue_scripts', array( $this, 'tvc_register_required_scripts' ) );
26
+ add_action( 'admin_enqueue_scripts', array( $this, 'tvc_register_required_nonce' ) );
27
+ // only load the next hooks when on the Settings page
28
+ if ( tvc_on_plugins_settings_page() ) {
29
+ add_action( 'admin_enqueue_scripts', array( $this, 'tvc_register_required_options_page_scripts' ) );
30
+ add_action( 'admin_enqueue_scripts', array( $this, 'tvc_register_required_options_page_nonce' ) );
31
+ }
32
+ if ( 1 === $action_level ) {
33
+ add_action( 'admin_enqueue_scripts', array( $this, 'tvc_register_level_one_scripts' ) );
34
+ } elseif ( 2 === $action_level ) {
35
+ add_action( 'admin_enqueue_scripts', array( $this, 'tvc_register_level_two_scripts' ) );
36
+ }
37
+ }
38
+ /**
39
+ * Registers all required java scripts for the feed manager pages.
40
+ */
41
+ public function tvc_register_required_scripts() {
42
+ $screen = get_current_screen();
43
+
44
+ if($screen->id == 'toplevel_page_aga-envato-api' || $screen->id == 'aga-google-shopping_page_tvc-product-feed-manager' || $screen->id == 'aga-google-shopping_page_tvc-configuration-page'){
45
+ wp_register_style("tvc_gmc_style-1", ENHANCAD_PLUGIN_URL . '/admin/css/style.css');
46
+ wp_enqueue_style( "tvc_gmc_style-1");
47
+ wp_register_style("tvc_gmc_style-2", ENHANCAD_PLUGIN_URL . '/css/style.css');
48
+ wp_enqueue_style( "tvc_gmc_style-2");
49
+ wp_register_style("tvc-product-feed-manager-1", ENHANCAD_PLUGIN_URL . '/css/actionable-google-analytics-admin.css');
50
+ wp_enqueue_style( "tvc-product-feed-manager-1");
51
+ wp_register_script( 'tvc_gmc_bootstrap-script-1', ENHANCAD_PLUGIN_URL . '/includes/setup/js/bootstrap' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
52
+ wp_enqueue_script( 'tvc_gmc_bootstrap-script-1');
53
+ wp_register_script( 'tvc_gmc_bootstrap-script-1', ENHANCAD_PLUGIN_URL . '/includes/setup/js/jquery-3.5.1.slim' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
54
+ wp_enqueue_script( 'tvc_gmc_bootstrap-script-1');
55
+ wp_register_script( 'tvc_gmc_bootstrap-script-1', ENHANCAD_PLUGIN_URL . '/includes/setup/js/popper' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
56
+ wp_enqueue_script( 'tvc_gmc_bootstrap-script-1');
57
+ wp_register_script( 'tvc_gmc-api-script', ENHANCAD_PLUGIN_URL . '/includes/setup/js/merchant-center.js', array( 'jquery' ), $this->_version_stamp, true );
58
+ wp_enqueue_script( 'tvc_gmc-api-script');
59
+ //wp_enqueue_script( 'tvc-product-feed-manager', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/sweetalert' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
60
+ wp_register_script( 'tvc-product-feed-manager-fa', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/fontawesome.js', array( 'jquery' ), $this->_version_stamp, false );
61
+ wp_enqueue_script( 'tvc-product-feed-manager-fa');
62
+ wp_register_style('aga_bootstrap', '//maxcdn.bootstrapcdn.com/bootstrap/4.5.1/css/bootstrap.min.css');
63
+ wp_enqueue_style('aga_bootstrap');
64
+ }
65
+ // enqueue notice handling script
66
+ wp_enqueue_script( 'tvc_message-handling-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_msg_events' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
67
+ // do not load the other scripts unless a tvc page is on
68
+
69
+ wp_register_style( 'tvc-product-feed-manager', ENHANCAD_PLUGIN_URL . '/css/tvc_admin-page' . $this->_js_min . '.css', '', $this->_version_stamp, 'screen' );
70
+ wp_enqueue_style( 'tvc-product-feed-manager' );
71
+ // embed the javascript file that makes the Ajax requests
72
+ wp_register_script( 'tvc_feed-settings-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_feed-form' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp,'screen' );
73
+ wp_enqueue_script( 'tvc_feed-settings-script');
74
+ wp_enqueue_script( 'tvc_business-logic-script', ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_logic.js', array( 'jquery' ), $this->_version_stamp, false );
75
+ wp_enqueue_script( 'tvc_data-script', ENHANCAD_PLUGIN_URL . '/includes/data/js/tvc_data' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
76
+ wp_enqueue_script( 'tvc_event-listener-script1', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_feed-form-events'. $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
77
+ wp_enqueue_script( 'wp_head', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/fontawesome.js', array( 'jquery' ), $this->_version_stamp, false );
78
+ wp_enqueue_script( 'tvc_form-support-script1', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_support' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
79
+ wp_enqueue_script( 'tvc_verify-inputs-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_verify-inputs' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
80
+ wp_enqueue_script( 'tvc_feed-handling-script', ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_feedhandling' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
81
+ wp_enqueue_script( 'tvc_feed-html', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_feed-html' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
82
+ wp_register_script( 'tvc_feed-list-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_feed-list.js', array( 'jquery' ), $this->_version_stamp,'screen' );
83
+ wp_enqueue_script( 'tvc_feed-list-script');
84
+ wp_enqueue_script( 'tvc_feed-meta-script', ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_object-attribute-meta' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
85
+ wp_enqueue_script( 'tvc_feed-objects-script', ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_object-feed' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
86
+ wp_enqueue_script( 'tvc_general-functions-script', ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_general-functions' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
87
+ wp_enqueue_script( 'tvc_object-handling-script', ENHANCAD_PLUGIN_URL . '/includes/data/js/tvc_metadatahandling' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false );
88
+ wp_enqueue_script( 'tvc_script_ajax', ENHANCAD_PLUGIN_URL . '/includes/data/js/tvc_ajaxdatahandling' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, false);
89
+ wp_enqueue_script( 'tvc_feed-queue-string-script', ENHANCAD_PLUGIN_URL . '/includes/data/js/tvc_feed-queue-string.js', array( 'jquery' ), $this->_version_stamp, false );
90
+ }
91
+ /**
92
+ * Generate the required nonce's.
93
+ */
94
+ public function tvc_register_required_nonce() {
95
+ // make a unique nonce for all Ajax requests
96
+ wp_localize_script(
97
+ 'tvc_script_ajax',
98
+ 'myAjaxNonces',
99
+ array(
100
+ // URL to wp-admin/admin-ajax.php to process the request
101
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
102
+ // generate the nonce's
103
+ 'campaignCategoryListsNonce' => wp_create_nonce( 'tvcajax-campaign-category-lists-nonce' ),
104
+ 'campaignStatusNonce' => wp_create_nonce( 'tvcajax-update-campaign-status-nonce' ),
105
+ 'campaignDeleteNonce' => wp_create_nonce( 'tvcajax-delete-campaign-nonce' ),
106
+ 'categoryListsNonce' => wp_create_nonce( 'tvcajax-category-lists-nonce' ),
107
+ 'deleteFeedNonce' => wp_create_nonce( 'tvcajax-delete-feed-nonce' ),
108
+ 'feedDataNonce' => wp_create_nonce( 'tvcajax-feed-data-nonce' ),
109
+ 'feedStatusNonce' => wp_create_nonce( 'tvcajax-feed-status-nonce' ),
110
+ 'inputFieldsNonce' => wp_create_nonce( 'tvcajax-input-fields-nonce' ),
111
+ 'inputFeedFiltersNonce' => wp_create_nonce( 'tvcajax-feed-filters-nonce' ),
112
+ 'logMessageNonce' => wp_create_nonce( 'tvcajax-log-message-nonce' ),
113
+ 'nextCategoryNonce' => wp_create_nonce( 'tvcajax-next-category-nonce' ),
114
+ 'outputFieldsNonce' => wp_create_nonce( 'tvcajax-output-fields-nonce' ),
115
+ 'postFeedsListNonce' => wp_create_nonce( 'tvcajax-post-feeds-list-nonce' ),
116
+ 'switchFeedStatusNonce' => wp_create_nonce( 'tvcajax-switch-feed-status-nonce' ),
117
+ 'duplicateFeedNonce' => wp_create_nonce( 'tvcajax-duplicate-existing-feed-nonce' ),
118
+ 'updateFeedDataNonce' => wp_create_nonce( 'tvcajax-update-feed-data-nonce' ),
119
+ 'updateAutoFeedFixNonce' => wp_create_nonce( 'tvcajax-set-auto-feed-fix-nonce' ),
120
+ 'updateFeedFileNonce' => wp_create_nonce( 'tvcajax-update-feed-file-nonce' ),
121
+ 'nextFeedInQueueNonce' => wp_create_nonce( 'tvcajax-next-feed-in-queue-nonce' ),
122
+ 'noticeDismissionNonce' => wp_create_nonce( 'tvcajax-duplicate-backup-nonce' ),
123
+ )
124
+ );
125
+ }
126
+ /**
127
+ * Registers all required java scripts for the feed manager Settings page.
128
+ */
129
+ public function tvc_register_required_options_page_scripts() {
130
+ // enqueue notice handling script
131
+ wp_enqueue_style( 'tvc-product-feed-manager-setting', ENHANCAD_PLUGIN_URL . '/css/tvc_setting-page' . $this->_js_min . '.css', '', $this->_version_stamp, 'screen' );
132
+ wp_enqueue_script( 'tvc_message-handling-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_msg_events' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, true );
133
+ wp_enqueue_style('font_awesome','//use.fontawesome.com/releases/v5.0.13/css/all.css');
134
+ //==wp_enqueue_script( 'tvc_backup-list-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_backup-list'. $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp,'screen' );
135
+ wp_enqueue_script( 'tvc_data-handling-script', ENHANCAD_PLUGIN_URL . '/includes/data/js/tvc_ajaxdatahandling' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, true );
136
+ wp_enqueue_script( 'tvc_setting-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_setting-form' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, true );
137
+ wp_enqueue_script( 'tvc_event-listener-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_feed-form-events' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, true );
138
+ wp_enqueue_script( 'tvc_form-support-script', ENHANCAD_PLUGIN_URL . '/includes/user-interface/js/tvc_support' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, true );
139
+ }
140
+ /**
141
+ * Generate the nonce's for the Settings page.
142
+ */
143
+ public function tvc_register_required_options_page_nonce() {
144
+ // make a unique nonce for all Ajax requests
145
+ wp_localize_script(
146
+ 'tvc_data-handling-script',
147
+ 'myAjaxNonces',
148
+ array(
149
+ // URL to wp-admin/admin-ajax.php to process the request
150
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
151
+ // generate the required nonce's
152
+ 'setAutoFeedFixNonce' => wp_create_nonce( 'tvcajax-auto-feed-fix-nonce' ),
153
+ 'setBackgroundModeNonce' => wp_create_nonce( 'tvcajax-background-mode-nonce' ),
154
+ 'setFeedLoggerStatusNonce' => wp_create_nonce( 'tvcajax-logger-status-nonce' ),
155
+ 'setShowPINonce' => wp_create_nonce( 'tvcajax-show-pi-nonce' ),
156
+ 'setThirdPartyKeywordsNonce' => wp_create_nonce( 'tvcajax-set-third-party-keywords-nonce' ),
157
+ 'setNoticeMailaddressNonce' => wp_create_nonce( 'tvcajax-set-notice-mailaddress-nonce' ),
158
+ 'setBatchProcessingLimitNonce' => wp_create_nonce( 'tvcajax-set-batch-processing-limit-nonce' ),
159
+ 'backupNonce' => wp_create_nonce( 'tvcajax-backup-nonce' ),
160
+ 'deleteBackupNonce' => wp_create_nonce( 'tvcajax-delete-backup-nonce' ),
161
+ 'restoreBackupNonce' => wp_create_nonce( 'tvcajax-restore-backup-nonce' ),
162
+ 'duplicateBackupNonce' => wp_create_nonce( 'tvcajax-duplicate-backup-nonce' ),
163
+ 'postBackupListNonce' => wp_create_nonce( 'tvcajax-backups-list-nonce' ),
164
+ 'postSetupOptionsNonce' => wp_create_nonce( 'tvcajax-setting-options-nonce' ),
165
+ 'setClearFeedProcessNonce' => wp_create_nonce( 'tvcajax-clear-feed-nonce' ),
166
+ 'setReInitiateNonce' => wp_create_nonce( 'tvcajax-reinitiate-nonce' ),
167
+ )
168
+ );
169
+ }
170
+ public function tvc_register_level_one_scripts() {
171
+ if ( ! tvc_on_own_main_plugin_page() ) {
172
+ return;
173
+ }
174
+ $data = new TVC_Data;
175
+ $installed_channels = $data->get_channels();
176
+ wp_enqueue_script( 'tvc_channel-functions-script', ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_channel-functions' . $this->_js_min . '.js', array( 'jquery' ), $this->_version_stamp, true );
177
+ foreach ( $installed_channels as $channel ) {
178
+ wp_enqueue_script( 'tvc_' . $channel['short'] . '-source-script', TVC_UPLOADS_URL . '/tvc-channels/' . $channel['short'] . '/tvc_' . $channel['short'] . '-source.js', array( 'jquery' ), $this->_version_stamp, true );
179
+ }
180
+ }
181
+ public function tvc_register_level_two_scripts() {
182
+ wp_enqueue_script(
183
+ 'tvc_channel-functions-script',
184
+ ENHANCAD_PLUGIN_URL . '/includes/application/js/tvc_channel-functions.js',
185
+ array( 'jquery' ),
186
+ $this->_version_stamp,
187
+ false
188
+ );
189
+ wp_enqueue_script(
190
+ 'tvc_google-source-script',
191
+ ENHANCAD_PLUGIN_URL . '/includes/application/google/tvc_google-source.js',
192
+ array( 'jquery' ),
193
+ $this->_version_stamp,
194
+ false
195
+ );
196
+ }
197
+ }
198
+ // End of TVC_Register_Scripts class
199
+ endif;
200
+ $my_ajax_registration_class = new TVC_Register_Scripts();
includes/data/class-tvc-ajax-calls.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Ajax Calls Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.0.1
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Ajax_Calls' ) ) :
15
+
16
+ /**
17
+ * Feed Controller Class
18
+ */
19
+ class TVC_Ajax_Calls {
20
+
21
+ public $_queries;
22
+ public $_files;
23
+
24
+ public function __construct() { }
25
+
26
+ protected function safe_ajax_call( $nonce, $registered_nonce_name ) {
27
+ // check the nonce
28
+ /*if ( ! wp_verify_nonce( $nonce, $registered_nonce_name ) ) {
29
+ die( 'You are not allowed to do this!' );
30
+ }*/
31
+
32
+ // only return results when the user is an admin with manage options
33
+ if ( is_admin() ) {
34
+ return true;
35
+ } else {
36
+ return false;
37
+ }
38
+ }
39
+ }
40
+ // end of TVC_Ajax_Calls class
41
+ endif;
includes/data/class-tvc-ajax-data.php ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Ajax Data Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.10.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Ajax_Data' ) ) :
15
+
16
+ /**
17
+ * Ajax Data Class
18
+ */
19
+ class TVC_Ajax_Data extends TVC_Ajax_Calls {
20
+
21
+ public function __construct() {
22
+ parent::__construct();
23
+
24
+ $this->_queries = new TVC_Queries();
25
+ $this->_files = new TVC_File();
26
+
27
+ // hooks
28
+ add_action( 'wp_ajax_tvcajax-get-list-of-feeds', array( $this, 'tvcajax_get_list_of_feeds' ) );
29
+ add_action( 'wp_ajax_tvcajax-get-list-of-backups', array( $this, 'tvcajax_get_list_of_backups' ) );
30
+ add_action( 'wp_ajax_tvcajax-get-settings-options', array( $this, 'tvcajax_get_settings_options' ) );
31
+ add_action( 'wp_ajax_tvcajax-get-output-fields', array( $this, 'tvcajax_get_output_fields' ) );
32
+ add_action( 'wp_ajax_tvcajax-get-input-fields', array( $this, 'tvcajax_get_input_fields' ) );
33
+ add_action( 'wp_ajax_tvcajax-get-feed-data', array( $this, 'tvcajax_get_feed_data' ) );
34
+ add_action( 'wp_ajax_tvcajax-get-feed-status', array( $this, 'tvcajax_get_feed_status' ) );
35
+ add_action( 'wp_ajax_tvcajax-get-main-feed-filters', array( $this, 'tvcajax_get_feed_filters' ) );
36
+ add_action( 'wp_ajax_tvcajax-switch-feed-status', array( $this, 'tvcajax_switch_feed_status_between_hold_and_ok' ) );
37
+ add_action( 'wp_ajax_tvcajax-duplicate-existing-feed', array( $this, 'tvcajax_duplicate_feed_data' ) );
38
+ add_action( 'wp_ajax_tvcajax-update-feed-data', array( $this, 'tvcajax_update_feed_data' ) );
39
+ add_action( 'wp_ajax_tvcajax-delete-feed', array( $this, 'tvcajax_delete_feed' ) );
40
+ add_action( 'wp_ajax_tvcajax-backup-current-data', array( $this, 'tvcajax_backup_current_data' ) );
41
+ add_action( 'wp_ajax_tvcajax-delete-backup-file', array( $this, 'tvcajax_delete_backup_file' ) );
42
+ add_action( 'wp_ajax_tvcajax-restore-backup-file', array( $this, 'tvcajax_restore_backup_file' ) );
43
+ add_action( 'wp_ajax_tvcajax-duplicate-backup-file', array( $this, 'tvcajax_duplicate_backup_file' ) );
44
+ add_action( 'wp_ajax_tvcajax-get-next-feed-in-queue', array( $this, 'tvcajax_get_next_feed_in_queue' ) );
45
+ add_action( 'wp_ajax_tvcajax-register-notice-dismission', array( $this, 'tvcajax_register_notice_dismission' ) );
46
+ }
47
+
48
+ /**
49
+ * Returns a list of all active feeds to an ajax caller
50
+ */
51
+ public function tvcajax_get_list_of_feeds() {
52
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'postFeedsListNonce' ), 'tvcajax-post-feeds-list-nonce' ) ) {
53
+ $list = $this->_queries->get_feeds_list();
54
+
55
+ // the status string entries from the database to identification strings (i.e. OK to ok and On hold in on_hold)
56
+ if ( $list && ! ctype_lower( $list[0]->status ) ) {
57
+ tvc_correct_old_feeds_list_status( $list );
58
+ }
59
+
60
+ $this->convert_type_numbers_to_text( $list );
61
+
62
+ // add information about the tvc_special_feeds_add_on_active filter to the feed list
63
+ $result = array(
64
+ 'list' => $list,
65
+ 'special_feed_add_ons_active' => apply_filters( 'tvc_special_feeds_add_on_active', false ),
66
+ );
67
+
68
+ echo json_encode( $result );
69
+ }
70
+
71
+ // IMPORTANT: don't forget to exit
72
+ exit;
73
+ }
74
+
75
+ /**
76
+ * Returns a list of backups the user has made
77
+ */
78
+ public function tvcajax_get_list_of_backups() {
79
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'postBackupListNonce' ), 'tvcajax-backups-list-nonce' ) ) {
80
+ echo json_encode( $this->_files->make_list_of_active_backups() );
81
+ }
82
+
83
+ // IMPORTANT: don't forget to exit
84
+ exit;
85
+ }
86
+
87
+ public function tvcajax_get_settings_options() {
88
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'postSetupOptionsNonce' ), 'tvcajax-setting-options-nonce' ) ) {
89
+ $options = [
90
+ get_option( 'tvc_auto_feed_fix' ),
91
+ get_option( 'tvc_third_party_attribute_keywords' ),
92
+ get_option( 'tvc_notice_mailaddress' ),
93
+ get_option( 'tvc_disabled_background_mode' ),
94
+ ];
95
+ echo json_encode( $options );
96
+ }
97
+
98
+ // IMPORTANT: don't forget to exit
99
+ exit;
100
+ }
101
+
102
+ /**
103
+ * Retrieves the output fields that are specific for a given merchant and
104
+ * also adds stored meta data to the output fields
105
+ *
106
+ * @access public (ajax triggered)
107
+ */
108
+ public function tvcajax_get_output_fields() {
109
+
110
+ // check: if the call is safe
111
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'outputFieldsNonce' ), 'tvcajax-output-fields-nonce' ) ) {
112
+ $data_class = new TVC_Data();
113
+
114
+ // get the posted inputs
115
+ $channel_id = filter_input( INPUT_POST, 'channelId' );
116
+ $feed_id = filter_input( INPUT_POST, 'feedId' );
117
+ $channel = trim( $this->_queries->get_channel_short_name_from_db( $channel_id ) );
118
+ $is_custom = function_exists( 'tvc_channel_is_custom_channel' ) ? tvc_channel_is_custom_channel( $channel_id ) : false;
119
+
120
+ if ( ! $is_custom ) {
121
+ // read the output fields
122
+ $outputs = $this->_files->get_output_fields_for_specific_channel( $channel );
123
+
124
+ // if the feed is a stored feed, look for meta data to add (a feed an id of -1 is a new feed that not yet has been saved)
125
+ if ( $feed_id >= 0 ) {
126
+ // add meta data to the feeds output fields
127
+ $outputs = $data_class->fill_output_fields_with_metadata( $feed_id, $outputs );
128
+ }
129
+ } else {
130
+ $data_class = new TVC_Data();
131
+ $outputs = $data_class->get_custom_fields_with_metadata( $feed_id );
132
+ }
133
+
134
+ echo json_encode( $outputs );
135
+ }
136
+
137
+ // IMPORTANT: don't forget to exit
138
+ exit;
139
+ }
140
+
141
+ /**
142
+ * Gets all the different source fields from the custom products and third party sources and combines them into one list
143
+ *
144
+ * @access public (ajax triggered)
145
+ */
146
+ public function tvcajax_get_input_fields() {
147
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'inputFieldsNonce' ), 'tvcajax-input-fields-nonce' ) ) {
148
+ $source_id = filter_input( INPUT_POST, 'sourceId' );
149
+
150
+ switch ( $source_id ) {
151
+ case '1':
152
+ $data_class = new TVC_Data();
153
+
154
+ $custom_product_attributes = $this->_queries->get_custom_product_attributes();
155
+ $custom_product_fields = $this->_queries->get_custom_product_fields();
156
+ $product_attributes = $this->_queries->get_all_product_attributes();
157
+ $product_taxonomies = get_taxonomies();
158
+ $third_party_custom_fields = $data_class->get_third_party_custom_fields();
159
+
160
+ $all_source_fields = $this->combine_custom_attributes_and_feeds(
161
+ $custom_product_attributes,
162
+ $custom_product_fields,
163
+ $product_attributes,
164
+ $product_taxonomies,
165
+ $third_party_custom_fields
166
+ );
167
+
168
+ echo json_encode( apply_filters( 'tvc_all_source_fields', $all_source_fields ) );
169
+ break;
170
+
171
+ default:
172
+ if ( 'valid' === get_option( 'tvc_lic_status' ) ) { // error message for paid versions
173
+ echo '<div id="error">' . esc_html__(
174
+ 'Could not add custom fields because I could not identify the channel.
175
+ If not already done add the correct channel in the Manage Channels page.
176
+ Also try to deactivate and then activate the plugin.',
177
+ 'tvc-product-feed-manager'
178
+ ) . '</div>';
179
+
180
+ tvc_write_log_file( sprintf( 'Could not define the channel in a valid Premium plugin version. Feed id = %s', $source_id ) );
181
+ } else { // error message for free version
182
+ echo '<div id="error">' . esc_html__(
183
+ 'Could not identify the channel.
184
+ Try to deactivate and then activate the plugin.
185
+ If that does not work remove the plugin through the WordPress Plugins page and than reinstall and activate it again.',
186
+ 'tvc-product-feed-manager'
187
+ ) . '</div>';
188
+
189
+ tvc_write_log_file( sprintf( 'Could not define the channel in a free plugin version. Feed id = %s', $source_id ) );
190
+ }
191
+
192
+ break;
193
+ }
194
+ }
195
+
196
+ // IMPORTANT: don't forget to exit
197
+ exit;
198
+ }
199
+
200
+ public function tvcajax_get_feed_filters() {
201
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'inputFeedFiltersNonce' ), 'tvcajax-feed-filters-nonce' ) ) {
202
+ $feed_id = filter_input( INPUT_POST, 'feedId' );
203
+
204
+ $data_class = new TVC_Data();
205
+ $filters = $data_class->get_filter_query( $feed_id );
206
+
207
+ echo $filters ? json_encode( $filters ) : '0';
208
+ }
209
+
210
+ // IMPORTANT: don't forget to exit
211
+ exit;
212
+ }
213
+
214
+ public function tvcajax_get_feed_data() {
215
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'feedDataNonce' ), 'tvcajax-feed-data-nonce' ) ) {
216
+ $feed_id = filter_input( INPUT_POST, 'sourceId' );
217
+ $feed_data = $this->_queries->read_feed( $feed_id );
218
+
219
+ echo json_encode( $feed_data );
220
+ }
221
+
222
+ // IMPORTANT: don't forget to exit
223
+ exit;
224
+ }
225
+
226
+ public function tvcajax_get_feed_status() {
227
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'feedStatusNonce' ), 'tvcajax-feed-status-nonce' ) ) {
228
+ $feed_id = filter_input( INPUT_POST, 'sourceId' );
229
+
230
+ $feed_master = new TVC_Feed_Master_Class( $feed_id );
231
+ $feed_data = $feed_master->feed_status_check( $feed_id );
232
+
233
+ echo json_encode( $feed_data );
234
+ }
235
+
236
+ // IMPORTANT: don't forget to exit
237
+ exit;
238
+ }
239
+
240
+ public function tvcajax_update_feed_data() {
241
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'updateFeedDataNonce' ), 'tvcajax-update-feed-data-nonce' ) ) {
242
+ // get the posted feed data
243
+ $ajax_feed_data = json_decode( filter_input( INPUT_POST, 'feed' ) );
244
+ $feed_filter = filter_input( INPUT_POST, 'feedFilter' );
245
+ $m_data = filter_input( INPUT_POST, 'metaData' );
246
+
247
+ echo TVC_Feed_CRUD_Handler::create_or_update_feed_data( $ajax_feed_data, $m_data, $feed_filter );
248
+ }
249
+
250
+ exit;
251
+ }
252
+
253
+ public function tvcajax_switch_feed_status_between_hold_and_ok() {
254
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'switchFeedStatusNonce' ), 'tvcajax-switch-feed-status-nonce' ) ) {
255
+ $feed_id = filter_input( INPUT_POST, 'feedId' );
256
+
257
+ $feed_status = $this->_queries->get_current_feed_status( $feed_id );
258
+ $current_status = $feed_status[0]->status_id;
259
+
260
+ $new_status = '1' === $current_status ? '2' : '1'; // only allow status 1 or 2
261
+
262
+ $result = $this->_queries->switch_feed_status( $feed_id, $new_status );
263
+
264
+ echo ( false === $result ) ? $current_status : $new_status;
265
+ }
266
+
267
+ // IMPORTANT: don't forget to exit
268
+ exit;
269
+ }
270
+
271
+ public function tvcajax_duplicate_feed_data() {
272
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'duplicateFeedNonce' ), 'tvcajax-duplicate-existing-feed-nonce' ) ) {
273
+ $feed_id = filter_input( INPUT_POST, 'feedId' );
274
+
275
+ echo TVC_Db_Management::duplicate_feed( $feed_id );
276
+ }
277
+
278
+ // IMPORTANT: don't forget to exit
279
+ exit;
280
+ }
281
+
282
+ public function tvcajax_delete_feed() {
283
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'deleteFeedNonce' ), 'tvcajax-delete-feed-nonce' ) ) {
284
+ $feed_id = filter_input( INPUT_POST, 'feedId' );
285
+
286
+ // only return results when the user is an admin with manage options
287
+ if ( is_admin() ) {
288
+ TVC_Feed_Controller::remove_id_from_feed_queue( $feed_id );
289
+ $this->_queries->delete_meta( $feed_id );
290
+ echo $this->_queries->delete_feed( $feed_id );
291
+ }
292
+ }
293
+
294
+ // IMPORTANT: don't forget to exit
295
+ exit;
296
+ }
297
+
298
+ public function tvcajax_backup_current_data() {
299
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'backupNonce' ), 'tvcajax-backup-nonce' ) ) {
300
+ // only take action when the user is an admin with manage options
301
+ if ( is_admin() ) {
302
+ $backup_file_name = filter_input( INPUT_POST, 'fileName' );
303
+ echo TVC_Db_Management::backup_database_tables( $backup_file_name );
304
+ }
305
+ }
306
+
307
+ // IMPORTANT: don't forget to exit
308
+ exit;
309
+ }
310
+
311
+ public function tvcajax_delete_backup_file() {
312
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'deleteBackupNonce' ), 'tvcajax-delete-backup-nonce' ) ) {
313
+ // only take action when the user is an admin with manage options
314
+ if ( is_admin() ) {
315
+ $backup_file_name = filter_input( INPUT_POST, 'fileName' );
316
+ TVC_Db_Management::delete_backup_file( $backup_file_name );
317
+ }
318
+ }
319
+
320
+ // IMPORTANT: don't forget to exit
321
+ exit;
322
+ }
323
+
324
+ public function tvcajax_restore_backup_file() {
325
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'restoreBackupNonce' ), 'tvcajax-restore-backup-nonce' ) ) {
326
+ // only take action when the user is an admin with manage options
327
+ if ( is_admin() ) {
328
+ $backup_file_name = filter_input( INPUT_POST, 'fileName' );
329
+ echo TVC_Db_Management::restore_backup( $backup_file_name );
330
+ }
331
+ }
332
+
333
+ // IMPORTANT: don't forget to exit
334
+ exit;
335
+ }
336
+
337
+ public function tvcajax_duplicate_backup_file() {
338
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'duplicateBackupNonce' ), 'tvcajax-duplicate-backup-nonce' ) ) {
339
+ // only take action when the user is an admin with manage options
340
+ if ( is_admin() ) {
341
+ $backup_file_name = filter_input( INPUT_POST, 'fileName' );
342
+ TVC_Db_Management::duplicate_backup_file( $backup_file_name );
343
+ }
344
+ }
345
+
346
+ // IMPORTANT: don't forget to exit
347
+ exit;
348
+ }
349
+
350
+ public function tvcajax_get_next_feed_in_queue() {
351
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'nextFeedInQueueNonce' ), 'tvcajax-next-feed-in-queue-nonce' ) ) {
352
+ $next_feed_id = TVC_Feed_Controller::get_next_id_from_feed_queue();
353
+ echo false !== $next_feed_id ? $next_feed_id : 'false';
354
+ }
355
+
356
+ // IMPORTANT: don't forget to exit
357
+ exit;
358
+ }
359
+
360
+ public function tvcajax_register_notice_dismission() {
361
+ if ( $this->safe_ajax_call( filter_input( INPUT_POST, 'noticeDismissionNonce' ), 'tvcajax-duplicate-backup-nonce' ) ) {
362
+
363
+ // only take action when the user is an admin with manage options
364
+ if ( is_admin() ) {
365
+ update_option( 'tvc_license_notice_suppressed', true );
366
+ echo 'true';
367
+ } else {
368
+ echo 'false';
369
+ }
370
+ }
371
+
372
+ // IMPORTANT: don't forget to exit
373
+ exit;
374
+ }
375
+
376
+ private function combine_custom_attributes_and_feeds( $attributes, $feeds, $product_attributes, $product_taxonomies, $third_party_fields ) {
377
+ $prev_dup_array = array(); // used to prevent doubles
378
+
379
+ foreach ( $feeds as $feed ) {
380
+ $obj = new stdClass();
381
+
382
+ $obj->attribute_name = $feed;
383
+ $obj->attribute_label = $feed;
384
+
385
+ array_push( $attributes, $obj );
386
+ array_push( $prev_dup_array, $obj->attribute_label );
387
+ }
388
+
389
+ foreach ( $product_taxonomies as $taxonomy ) {
390
+ if ( ! in_array( $taxonomy, $prev_dup_array ) ) {
391
+ $obj = new stdClass();
392
+ $obj->attribute_name = $taxonomy;
393
+ $obj->attribute_label = $taxonomy;
394
+
395
+ array_push( $attributes, $obj );
396
+ array_push( $prev_dup_array, $taxonomy );
397
+ }
398
+ }
399
+
400
+ foreach ( $product_attributes as $attribute_string ) {
401
+ $attribute_object = maybe_unserialize( $attribute_string->meta_value );
402
+
403
+ if ( $attribute_object && ( is_object( $attribute_object ) || is_array( $attribute_object ) ) ) {
404
+ foreach ( $attribute_object as $attribute ) {
405
+ if ( ! in_array( $attribute['name'], $prev_dup_array ) ) {
406
+ $obj = new stdClass();
407
+ $obj->attribute_name = $attribute['name'];
408
+ $obj->attribute_label = $attribute['name'];
409
+
410
+ array_push( $attributes, $obj );
411
+ array_push( $prev_dup_array, $attribute['name'] );
412
+ }
413
+ }
414
+ } else {
415
+ if ( $attribute_object ) {
416
+ tvc_write_log_file( $attribute_object, 'debug' );
417
+ }
418
+ }
419
+ }
420
+
421
+ foreach ( $third_party_fields as $field_label ) {
422
+ if ( ! in_array( $field_label, $prev_dup_array ) ) {
423
+ $obj = new stdClass();
424
+ $obj->attribute_name = $field_label;
425
+ $obj->attribute_label = $field_label;
426
+
427
+ array_push( $attributes, $obj );
428
+ array_push( $prev_dup_array, $field_label );
429
+ }
430
+ }
431
+
432
+ return $attributes;
433
+ }
434
+
435
+ private function convert_type_numbers_to_text( &$list ) {
436
+ $feed_types = tvc_list_feed_type_text();
437
+
438
+ foreach ( $list as $feed ) {
439
+ $feed->feed_type_name = $feed_types[ $feed->feed_type_id ];
440
+ }
441
+ }
442
+ }
443
+
444
+ // end of TVC_Ajax_Data_Class
445
+
446
+ endif;
447
+
448
+ $my_ajax_data_class = new TVC_Ajax_Data();
includes/data/class-tvc-ajax-file.php ADDED
@@ -0,0 +1,1081 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Ajax File Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ */
8
+ if(!defined('ABSPATH')){
9
+ exit;
10
+ }
11
+
12
+ if(!class_exists('TVC_Ajax_File')) :
13
+
14
+ /**
15
+ * Ajax File Class
16
+ */
17
+ class TVC_Ajax_File extends TVC_Ajax_Calls {
18
+
19
+ public function __construct(){
20
+ parent::__construct();
21
+
22
+ // hooks
23
+ add_action('wp_ajax_tvcajax-get-campaign-categories', array($this, 'tvcajax_get_campaign_categories'));
24
+ add_action('wp_ajax_tvcajax-update-campaign-status', array($this, 'tvcajax_update_campaign_status'));
25
+ add_action('wp_ajax_tvcajax-delete-campaign', array($this, 'tvcajax_delete_campaign'));
26
+ add_action('wp_ajax_tvcajax-get-next-categories', array($this, 'tvcajax_read_next_categories'));
27
+ add_action('wp_ajax_tvcajax-get-category-lists', array($this, 'tvcajax_read_category_lists'));
28
+ add_action('wp_ajax_tvcajax-delete-feed-file', array($this, 'tvcajax_delete_feed_file'));
29
+ add_action('wp_ajax_tvcajax-update-feed-file', array($this, 'tvcajax_update_feed_file'));
30
+ add_action('wp_ajax_tvcajax-log-message', array($this, 'tvcajax_log_message'));
31
+ add_action('wp_ajax_tvcajax-auto-feed-fix-mode-selection', array($this, 'tvcajax_auto_feed_fix_mode_selection'));
32
+ add_action('wp_ajax_tvcajax-background-processing-mode-selection', array($this, 'tvcajax_background_processing_mode_selection'));
33
+ add_action('wp_ajax_tvcajax-feed-logger-status-selection', array($this, 'tvcajax_feed_logger_status_selection'));
34
+ add_action('wp_ajax_tvcajax-show-product-identifiers-selection', array($this, 'tvcajax_show_product_identifiers_selection'));
35
+ add_action('wp_ajax_tvcajax-debug-mode-selection', array($this, 'tvcajax_debut_mode_selection'));
36
+ add_action('wp_ajax_tvcajax-third-party-attribute-keywords', array($this, 'tvcajax_set_third_party_attribute_keywords'));
37
+ add_action('wp_ajax_tvcajax-set-notice-mailaddress', array($this, 'tvcajax_set_notice_mailaddress'));
38
+ add_action('wp_ajax_tvcajax-clear-feed-process-data', array($this, 'tvcajax_clear_feed_process_data'));
39
+ add_action('wp_ajax_tvcajax-reinitiate-plugin', array($this, 'tvcajax_reinitiate_plugin'));
40
+ add_action('wp_ajax_tvcajax-product-syncup', array($this, 'tvcajax_product_syncup'));
41
+ add_action('wp_ajax_tvcajax-gmc-category-lists', array($this, 'tvcajax_get_gmc_categories'));
42
+ add_action('wp_ajax_tvcajax-custom-metrics-dimension', array($this, 'tvcajax_custom_metrics_dimension'));
43
+ add_action('wp_ajax_tvcajax-store-time-taken', array($this, 'tvcajax_store_time_taken'));
44
+ }
45
+
46
+ /**
47
+ * Delete the campaign
48
+ */
49
+ public function tvcajax_delete_campaign(){
50
+ // make sure this call is legal
51
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'campaignDeleteNonce'), 'tvcajax-delete-campaign-nonce')){
52
+
53
+ $merchantId = filter_input(INPUT_POST, 'merchantId');
54
+ $customerId = filter_input(INPUT_POST, 'customerId');
55
+ $campaignId = filter_input(INPUT_POST, 'campaignId');
56
+
57
+ $url = 'https://connect.tatvic.com/laravelapi/public/api/campaigns/delete';
58
+
59
+ $data = [
60
+ 'merchant_id' => $merchantId,
61
+ 'customer_id' => $customerId,
62
+ 'campaign_id' => $campaignId
63
+ ];
64
+
65
+ $args = array(
66
+ 'headers' => array(
67
+ 'Authorization' => "Bearer MTIzNA==",
68
+ 'Content-Type' => 'application/json'
69
+ ),
70
+ 'method' => 'DELETE',
71
+ 'body' => wp_json_encode($data)
72
+ );
73
+
74
+ // Send remote request
75
+ $request = wp_remote_request($url, $args);
76
+
77
+ // Retrieve information
78
+ $response_code = wp_remote_retrieve_response_code($request);
79
+ $response_message = wp_remote_retrieve_response_message($request);
80
+ $response_body = json_decode(wp_remote_retrieve_body($request));
81
+
82
+ if((isset($response_body->error) && $response_body->error == '')){
83
+ $message = $response_body->message;
84
+ echo json_encode(['status' => 'success', 'message' => $message]);
85
+ // return new WP_REST_Response(
86
+ // array(
87
+ // 'status' => $response_code,
88
+ // 'message' => $response_message,
89
+ // 'data' => $response_body->data
90
+ // )
91
+ // );
92
+ }else{
93
+ $message = is_array($response_body->errors) ? $response_body->errors[0] : "Face some unprocessable entity";
94
+ echo json_encode(['status' => 'error', 'message' => $message]);
95
+ // return new WP_Error($response_code, $response_message, $response_body);
96
+ }
97
+
98
+ // echo json_encode( $categories );
99
+ }
100
+
101
+ // IMPORTANT: don't forget to exit
102
+ exit;
103
+ }
104
+
105
+ /**
106
+ * Update the campaign status pause/active
107
+ */
108
+ public function tvcajax_update_campaign_status(){
109
+ // make sure this call is legal
110
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'campaignStatusNonce'), 'tvcajax-update-campaign-status-nonce')){
111
+
112
+ if(!class_exists('ShoppingApi')){
113
+ //require_once(__DIR__ . '/ShoppingApi.php');
114
+ include(ENHANCAD_PLUGIN_DIR . 'includes/setup/ShoppingApi.php');
115
+ }
116
+
117
+ $merchantId = filter_input(INPUT_POST, 'merchantId');
118
+ $customerId = filter_input(INPUT_POST, 'customerId');
119
+ $campaignId = filter_input(INPUT_POST, 'campaignId');
120
+ $budgetId = filter_input(INPUT_POST, 'budgetId');
121
+ $campaignName = filter_input(INPUT_POST, 'campaignName');
122
+ $budget = filter_input(INPUT_POST, 'budget');
123
+ $status = filter_input(INPUT_POST, 'status');
124
+ $url = 'https://connect.tatvic.com/laravelapi/public/api/campaigns/update';
125
+ $shoppingObj = new ShoppingApi();
126
+ $campaignData = $shoppingObj->getCampaignDetails($campaignId);
127
+
128
+ $data = [
129
+ 'merchant_id' => $merchantId,
130
+ 'customer_id' => $customerId,
131
+ 'campaign_id' => $campaignId,
132
+ 'account_budget_id' => $budgetId,
133
+ 'campaign_name' => $campaignName,
134
+ 'budget' => $budget,
135
+ 'status' => $status,
136
+ 'target_country' => $campaignData->data['data']->targetCountry,
137
+ 'ad_group_id' => $campaignData->data['data']->adGroupId,
138
+ 'ad_group_resource_name' => $campaignData->data['data']->adGroupResourceName
139
+ ];
140
+
141
+ $args = array(
142
+ 'headers' => array(
143
+ 'Authorization' => "Bearer MTIzNA==",
144
+ 'Content-Type' => 'application/json'
145
+ ),
146
+ 'method' => 'PATCH',
147
+ 'body' => wp_json_encode($data)
148
+ );
149
+
150
+ // Send remote request
151
+ $request = wp_remote_request($url, $args);
152
+
153
+ // Retrieve information
154
+ $response_code = wp_remote_retrieve_response_code($request);
155
+ $response_message = wp_remote_retrieve_response_message($request);
156
+ $response_body = json_decode(wp_remote_retrieve_body($request));
157
+ if((isset($response_body->error) && $response_body->error == '')){
158
+ $message = $response_body->message;
159
+ echo json_encode(['status' => 'success', 'message' => $message]);
160
+ // return new WP_REST_Response(
161
+ // array(
162
+ // 'status' => $response_code,
163
+ // 'message' => $response_message,
164
+ // 'data' => $response_body->data
165
+ // )
166
+ // );
167
+ }else{
168
+ $message = is_array($response_body->errors) ? $response_body->errors[0] : "Face some unprocessable entity";
169
+ echo json_encode(['status' => 'error', 'message' => $message]);
170
+ // return new WP_Error($response_code, $response_message, $response_body);
171
+ }
172
+
173
+ // echo json_encode( $categories );
174
+ }
175
+
176
+ // IMPORTANT: don't forget to exit
177
+ exit;
178
+ }
179
+
180
+ /**
181
+ * Returns the campaign categories from a selected country
182
+ */
183
+ public function tvcajax_get_campaign_categories(){
184
+ // make sure this call is legal
185
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'campaignCategoryListsNonce'), 'tvcajax-campaign-category-lists-nonce')){
186
+
187
+ $country_code = filter_input(INPUT_POST, 'countryCode');
188
+ $customer_id = filter_input(INPUT_POST, 'customerId');
189
+ $url = 'https://connect.tatvic.com/laravelapi/public/api/products/categories';
190
+
191
+ $data = [
192
+ 'customer_id' => $customer_id,
193
+ 'country_code' => $country_code
194
+ ];
195
+
196
+ $args = array(
197
+ 'headers' => array(
198
+ 'Authorization' => "Bearer MTIzNA==",
199
+ 'Content-Type' => 'application/json'
200
+ ),
201
+ 'body' => wp_json_encode($data)
202
+ );
203
+
204
+ // Send remote request
205
+ $request = wp_remote_post($url, $args);
206
+
207
+ // Retrieve information
208
+ $response_code = wp_remote_retrieve_response_code($request);
209
+ $response_message = wp_remote_retrieve_response_message($request);
210
+ $response_body = json_decode(wp_remote_retrieve_body($request));
211
+
212
+ if((isset($response_body->error) && $response_body->error == '')){
213
+ echo json_encode($response_body->data);
214
+ // return new WP_REST_Response(
215
+ // array(
216
+ // 'status' => $response_code,
217
+ // 'message' => $response_message,
218
+ // 'data' => $response_body->data
219
+ // )
220
+ // );
221
+ }else{
222
+ echo json_encode([]);
223
+ // return new WP_Error($response_code, $response_message, $response_body);
224
+ }
225
+
226
+ // echo json_encode( $categories );
227
+ }
228
+
229
+ // IMPORTANT: don't forget to exit
230
+ exit;
231
+ }
232
+
233
+ /**
234
+ * Returns the sub-categories from a selected category
235
+ */
236
+ public function tvcajax_read_next_categories(){
237
+ // make sure this call is legal
238
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'nextCategoryNonce'), 'tvcajax-next-category-nonce')){
239
+ $file_class = new TVC_File();
240
+
241
+ $channel_id = filter_input(INPUT_POST, 'channelId');
242
+ $requested_level = filter_input(INPUT_POST, 'requestedLevel');
243
+ $parent_category = filter_input(INPUT_POST, 'parentCategory');
244
+ $file_language = filter_input(INPUT_POST, 'fileLanguage');
245
+ $categories = $file_class->get_categories_for_list($channel_id, $requested_level, $parent_category, $file_language);
246
+
247
+ if(!is_array($categories)){
248
+ if('0' === substr($categories, - 1)){
249
+ chop($categories, '0');
250
+ }
251
+ }
252
+
253
+ echo json_encode($categories);
254
+ }
255
+
256
+ // IMPORTANT: don't forget to exit
257
+ exit;
258
+ }
259
+
260
+ /**
261
+ * Read the category list
262
+ */
263
+ public function tvcajax_read_category_lists(){
264
+ // make sure this call is legal
265
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'categoryListsNonce'), 'tvcajax-category-lists-nonce')){
266
+ $file_class = new TVC_File();
267
+
268
+ $channel_id = filter_input(INPUT_POST, 'channelId');
269
+ $main_categories_string = filter_input(INPUT_POST, 'mainCategories');
270
+ $file_language = filter_input(INPUT_POST, 'fileLanguage');
271
+ $categories_array = explode(' > ', $main_categories_string);
272
+ $categories = array();
273
+ $required_levels = count($categories_array) > 0 ? ( count($categories_array) + 1 ) : count($categories_array);
274
+
275
+ for($i = 0; $i < $required_levels; $i ++){
276
+ $parent_category = $i > 0 ? $categories_array[$i - 1] : '';
277
+ $c = $file_class->get_categories_for_list($channel_id, $i, $parent_category, $file_language);
278
+ if($c){
279
+ array_push($categories, $c);
280
+ }
281
+ }
282
+
283
+ echo json_encode($categories);
284
+ }
285
+
286
+ // IMPORTANT: don't forget to exit
287
+ exit;
288
+ }
289
+
290
+ /**
291
+ * Delete a specific feed file
292
+ */
293
+ public function tvcajax_delete_feed_file(){
294
+ // make sure this call is legal
295
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'deleteFeedNonce'), 'tvcajax-delete-feed-nonce')){
296
+ $file_name = filter_input(INPUT_POST, 'fileTitle');
297
+
298
+ if(file_exists(WP_PLUGIN_DIR . '/tvc-product-feed-manager-support/feeds/' . $file_name)){
299
+ $file = WP_PLUGIN_DIR . '/tvc-product-feed-manager-support/feeds/' . $file_name;
300
+ }else{
301
+ $file = TVC_FEEDS_DIR . '/' . $file_name;
302
+ }
303
+
304
+ // only return results when the user is an admin with manage options
305
+ if(is_admin()){
306
+ /* translators: %s: Title of the feed file */
307
+ echo file_exists($file) ? unlink($file) : tvc_show_wp_error(sprintf(esc_html__('Could not find file %s.', 'tvc-product-feed-manager'), $file));
308
+ }else{
309
+ echo tvc_show_wp_error(esc_html__('Error deleting the feed. You do not have the correct authorities to delete the file.', 'tvc-product-feed-manager'));
310
+ }
311
+ }
312
+
313
+ // IMPORTANT: don't forget to exit
314
+ exit;
315
+ }
316
+
317
+ /**
318
+ * This function fetches the posted data and triggers the update of the feed file on the server.
319
+ */
320
+ public function tvcajax_update_feed_file(){
321
+ // make sure this call is legal
322
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'updateFeedFileNonce'), 'tvcajax-update-feed-file-nonce')){
323
+
324
+ // fetch the data from $_POST
325
+ $feed_id = filter_input(INPUT_POST, 'feedId');
326
+ $background_mode_disabled = get_option('tvc_disabled_background_mode', 'false');
327
+
328
+ TVC_Feed_Controller::add_id_to_feed_queue($feed_id);
329
+
330
+ // if there is no feed processing in progress, of background processing is switched off, start updating the current feed
331
+ if(!TVC_Feed_Controller::feed_is_processing() || 'true' === $background_mode_disabled){
332
+ do_action('tvc_manual_feed_update_activated', $feed_id);
333
+
334
+ $feed_master_class = new TVC_Feed_Master_Class($feed_id);
335
+ $feed_master_class->update_feed_file(false);
336
+ }else{
337
+ $data_class = new TVC_Data();
338
+ $data_class->update_feed_status($feed_id, 4); // feed status to waiting in queue
339
+ echo 'pushed_to_queue';
340
+ }
341
+ }
342
+
343
+ // IMPORTANT: don't forget to exit
344
+ exit;
345
+ }
346
+
347
+ /**
348
+ * Logs a message from a javascript call to the server
349
+ */
350
+ public function tvcajax_log_message(){
351
+ // make sure this call is legal
352
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'logMessageNonce'), 'tvcajax-log-message-nonce')){
353
+ // fetch the data from $_POST
354
+ $message = filter_input(INPUT_POST, 'messageList');
355
+ $file_name = filter_input(INPUT_POST, 'fileName');
356
+ $text_message = strip_tags($message);
357
+
358
+ // only return results when the user is an admin with manage options
359
+ if(is_admin()){
360
+ //tvc_write_log_file( $text_message, $file_name );
361
+ }else{
362
+ echo tvc_show_wp_error(esc_html__('Error writing the feed. You do not have the correct authorities to write the file.', 'tvc-product-feed-manager'));
363
+ }
364
+ }
365
+
366
+ // IMPORTANT: don't forget to exit
367
+ exit;
368
+ }
369
+
370
+ /**
371
+ * Changes the Auto Feed Fix setting from the Settings page
372
+ *
373
+ * @since 1.7.0
374
+ */
375
+ public function tvcajax_auto_feed_fix_mode_selection(){
376
+ // make sure this call is legal
377
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'updateAutoFeedFixNonce'), 'tvcajax-auto-feed-fix-nonce')){
378
+ $selection = filter_input(INPUT_POST, 'fix_selection');
379
+ update_option('tvc_auto_feed_fix', $selection);
380
+
381
+ echo get_option('tvc_auto_feed_fix');
382
+ }
383
+
384
+ // IMPORTANT: don't forget to exit
385
+ exit;
386
+ }
387
+
388
+ /**
389
+ * Changes the Disable Background processing setting from the Settings page
390
+ *
391
+ * @since 2.0.7
392
+ */
393
+ public function tvcajax_background_processing_mode_selection(){
394
+ // make sure this call is legal
395
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'backgroundModeNonce'), 'tvcajax-background-mode-nonce')){
396
+ $selection = filter_input(INPUT_POST, 'mode_selection');
397
+ update_option('tvc_disabled_background_mode', $selection);
398
+
399
+ echo get_option('tvc_disabled_background_mode');
400
+ }
401
+
402
+ // IMPORTANT: don't forget to exit
403
+ exit;
404
+ }
405
+
406
+ /**
407
+ * Changes the Feed Process Logger setting from the Settings page.
408
+ *
409
+ * @since 2.8.0
410
+ */
411
+ public function tvcajax_feed_logger_status_selection(){
412
+ // make sure this call is legal
413
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'feedLoggerStatusNonce'), 'tvcajax-logger-status-nonce')){
414
+ $selection = filter_input(INPUT_POST, 'statusSelection');
415
+ update_option('tvc_process_logger_status', $selection);
416
+
417
+ echo get_option('tvc_process_logger_status');
418
+ }
419
+
420
+ // IMPORTANT: don't forget to exit
421
+ exit;
422
+ }
423
+
424
+ /**
425
+ * Changes the Show Product Identifiers setting from the Settings page.
426
+ *
427
+ * @since 2.10.0
428
+ */
429
+ public function tvcajax_show_product_identifiers_selection(){
430
+ // make sure this call is legal
431
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'showPINonce'), 'tvcajax-show-pi-nonce')){
432
+ $selection = filter_input(INPUT_POST, 'showPiSelection');
433
+ update_option('tvc_show_product_identifiers', $selection);
434
+
435
+ echo get_option('tvc_show_product_identifiers');
436
+ }
437
+
438
+ // IMPORTANT: don't forget to exit
439
+ exit;
440
+ }
441
+
442
+ /**
443
+ * Changes the Debug setting from the Settings page
444
+ *
445
+ * @since 1.9.0
446
+ */
447
+ public function tvcajax_debug_mode_selection(){
448
+ // make sure this call is legal
449
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'debugNonce'), 'tvcajax-debug-nonce')){
450
+ $selection = filter_input(INPUT_POST, 'debug_selection');
451
+ update_option('tvc_debug_mode', $selection);
452
+
453
+ echo get_option('tvc_debug_mode');
454
+ }
455
+
456
+ // IMPORTANT: don't forget to exit
457
+ exit;
458
+ }
459
+
460
+ public function tvcajax_set_third_party_attribute_keywords(){
461
+ // make sure this call is legal
462
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'thirdPartyKeywordsNonce'), 'tvcajax-set-third-party-keywords-nonce')){
463
+ $keywords = filter_input(INPUT_POST, 'keywords');
464
+ update_option('tvc_third_party_attribute_keywords', $keywords);
465
+
466
+ echo get_option('tvc_third_party_attribute_keywords');
467
+ }
468
+
469
+ // IMPORTANT: don't forget to exit
470
+ exit;
471
+ }
472
+
473
+ public function tvcajax_set_notice_mailaddress(){
474
+ // make sure this call is legal
475
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'noticeMailaddressNonce'), 'tvcajax-set-notice-mailaddress-nonce')){
476
+ $mailaddress = filter_input(INPUT_POST, 'mailaddress');
477
+ update_option('tvc_notice_mailaddress', $mailaddress);
478
+
479
+ echo get_option('tvc_notice_mailaddress');
480
+ }
481
+
482
+ // IMPORTANT: don't forget to exit
483
+ exit;
484
+ }
485
+
486
+ /**
487
+ * Re-initiates the plugin, updates the database and loads all cron jobs
488
+ *
489
+ * @since 1.9.0
490
+ */
491
+ public function tvcajax_reinitiate_plugin(){
492
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'reInitiateNonce'), 'tvcajax-reinitiate-nonce')){
493
+
494
+ if(tvc_reinitiate_plugin()){
495
+ echo 'Plugin re-initiated';
496
+ }else{
497
+ echo 'Re-initiation failed!';
498
+ }
499
+ }
500
+
501
+ // IMPORTANT: don't forget to exit
502
+ exit;
503
+ }
504
+
505
+ /**
506
+ * Clears all option data that is related to the feed processing
507
+ *
508
+ * @since 1.10.0
509
+ */
510
+ public function tvcajax_clear_feed_process_data(){
511
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'clearFeedNonce'), 'tvcajax-clear-feed-nonce')){
512
+
513
+ if(tvc_clear_feed_process_data()){
514
+ echo esc_html__('Feed processing data cleared', 'tvc-product-feed-manager');
515
+ }else{
516
+ /* translators: clearing the feed data failed */
517
+ echo esc_html__('Clearing failed!', 'tvc-product-feed-manager');
518
+ }
519
+ }
520
+
521
+ // IMPORTANT: don't forget to exit
522
+ exit;
523
+ }
524
+
525
+ /**
526
+ * Returns the campaign categories from a selected country
527
+ */
528
+ public function tvcajax_get_gmc_categories(){
529
+ // make sure this call is legal
530
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'gmcCategoryListsNonce'), 'tvcajax-gmc-category-lists-nonce')){
531
+
532
+ $country_code = filter_input(INPUT_POST, 'countryCode');
533
+ $customer_id = filter_input(INPUT_POST, 'customerId');
534
+ $parent = filter_input(INPUT_POST, 'parent');
535
+ //$url = 'https://connect.tatvic.com/laravelapi/public/api/products/gmc-categories';
536
+ //$url = 'http://127.0.0.1:8000/api/products/gmc-categories';
537
+ $url = 'https://connect.tatvic.com/laravelapi/public/api/products/gmc-categories';
538
+
539
+ $data = [
540
+ 'customer_id' => $customer_id,
541
+ 'country_code' => $country_code,
542
+ 'parent' => $parent
543
+ ];
544
+
545
+ $args = array(
546
+ 'headers' => array(
547
+ 'Authorization' => "Bearer MTIzNA==",
548
+ 'Content-Type' => 'application/json'
549
+ ),
550
+ 'body' => wp_json_encode($data)
551
+ );
552
+
553
+ // Send remote request
554
+ $request = wp_remote_post($url, $args);
555
+
556
+ // Retrieve information
557
+ $response_code = wp_remote_retrieve_response_code($request);
558
+ $response_message = wp_remote_retrieve_response_message($request);
559
+ $response_body = json_decode(wp_remote_retrieve_body($request));
560
+
561
+ if((isset($response_body->error) && $response_body->error == '')){
562
+ echo json_encode($response_body->data);
563
+ // return new WP_REST_Response(
564
+ // array(
565
+ // 'status' => $response_code,
566
+ // 'message' => $response_message,
567
+ // 'data' => $response_body->data
568
+ // )
569
+ // );
570
+ }else{
571
+ echo json_encode([]);
572
+ // return new WP_Error($response_code, $response_message, $response_body);
573
+ }
574
+
575
+ // echo json_encode( $categories );
576
+ }
577
+
578
+ // IMPORTANT: don't forget to exit
579
+ exit;
580
+ }
581
+
582
+ public function getPostMetaData($id){
583
+ $queries = new TVC_Queries();
584
+ $column2 = json_decode(json_encode($queries->getTablePostMeta($id)), true);
585
+ $arr = array();
586
+ foreach($column2 as $val){
587
+ $arr[$val['meta_key']] = $val['meta_value'];
588
+ }
589
+ return $arr;
590
+ }
591
+
592
+ /**
593
+ * create product batch for product sync up
594
+ */
595
+ public function tvcajax_product_syncup(){
596
+ // make sure this call is legal
597
+
598
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'productSyncupNonce'), 'tvcajax-product-syncup-nonce')){
599
+
600
+
601
+ if(!class_exists('CustomApi')){
602
+ include(ENHANCAD_PLUGIN_DIR . 'includes/setup/CustomApi.php');
603
+ }
604
+ $customObj = new CustomApi();
605
+
606
+ $batchId = time();
607
+ $merchantId = filter_input(INPUT_POST, 'merchantId');
608
+ $customerId = filter_input(INPUT_POST, 'customerId');
609
+ $accountId = filter_input(INPUT_POST, 'accountId');
610
+ $subscriptionId = filter_input(INPUT_POST, 'subscriptionId');
611
+ $platformCustomerId = filter_input(INPUT_POST, 'platformCustomerId');
612
+ $data = filter_input(INPUT_POST, 'data');
613
+ /* echo "=============="; */
614
+ // echo "<pre>";
615
+ parse_str($data, $formArray);
616
+ //print_r($formArray); // Only for print array
617
+ $mappedCatsDB = [];
618
+ $mappedCats = [];
619
+ $mappedAttrs = [];
620
+ foreach($formArray as $key => $value){
621
+ if(preg_match("/^category-name-/i", $key)){
622
+ if($value != ''){
623
+ $keyArray = explode("name-", $key);
624
+ $mappedCatsDB[$keyArray[1]]['name'] = $value;
625
+ }
626
+ }else if(preg_match("/^category-/i", $key)){
627
+ if($value != '' && $value > 0){
628
+ $keyArray = explode("-", $key);
629
+ $mappedCats[$keyArray[1]] = $value;
630
+ $mappedCatsDB[$keyArray[1]]['id'] = $value;
631
+ }
632
+ }else{
633
+ if($value){
634
+ $mappedAttrs[$key] = $value;
635
+ }
636
+ }
637
+ }
638
+ update_option("ee_prod_mapped_cats", serialize($mappedCatsDB));
639
+ update_option("ee_prod_mapped_attrs", serialize($mappedAttrs));
640
+
641
+ if(!empty($mappedCats)){
642
+ $catMapRequest = [];
643
+ $catMapRequest['subscription_id'] = $subscriptionId;
644
+ $catMapRequest['customer_id'] = $customerId;
645
+ $catMapRequest['merchant_id'] = $merchantId;
646
+ $catMapRequest['category'] = $mappedCats;
647
+ $catMapResponse = $customObj->setGmcCategoryMapping($catMapRequest);
648
+ }
649
+
650
+ if(!empty($mappedAttrs)){
651
+ $attrMapRequest = [];
652
+ $attrMapRequest['subscription_id'] = $subscriptionId;
653
+ $attrMapRequest['customer_id'] = $customerId;
654
+ $attrMapRequest['merchant_id'] = $merchantId;
655
+ $attrMapRequest['attribute'] = $mappedAttrs;
656
+ $attrMapResponse = $customObj->setGmcAttributeMapping($attrMapRequest);
657
+ }
658
+
659
+ $entries = [];
660
+ if(!empty($mappedCats)){
661
+ foreach($mappedCats as $key => $mappedCat){
662
+ $all_products = get_posts(array(
663
+ 'post_type' => 'product',
664
+ 'numberposts' => -1,
665
+ 'post_status' => 'publish',
666
+ 'tax_query' => array(
667
+ array(
668
+ 'taxonomy' => 'product_cat',
669
+ 'field' => 'term_id',
670
+ 'terms' => $key, /* category name */
671
+ 'operator' => 'IN',
672
+ )
673
+ ),'meta_query' => array(
674
+ 'relation' => 'AND',
675
+ array(
676
+ 'key' => '_stock_status',
677
+ 'value' => 'instock'
678
+ ),
679
+ array(
680
+ 'relation' => 'or',
681
+ array(
682
+ 'key' => '_sale_price',
683
+ 'value' => '',
684
+ 'compare' => '!=',
685
+ ),
686
+ array(
687
+ 'key' => '_price',
688
+ 'value' => '',
689
+ 'compare' => '!=',
690
+ )
691
+ )
692
+ )
693
+ ));
694
+ foreach($all_products as $postkey => $postvalue){
695
+ $postmeta = [];
696
+ $postmeta = $this->getPostMetaData($postvalue->ID);
697
+ $prd = wc_get_product($postvalue->ID);
698
+ $postObj = (object) array_merge((array) $postvalue, (array) $postmeta);
699
+ $product = [];
700
+ foreach($formArray as $key => $value){
701
+
702
+ // $product['content_language'] = 'en';
703
+ // $product['target_country'] = 'US';
704
+ $product['channel'] = 'online';
705
+ $product['google_product_category'] = $mappedCat;
706
+ $product['link'] = get_permalink($postvalue->ID);
707
+ if($key == 'image_link'){
708
+ $image_id = $prd->get_image_id();
709
+ $product['image_link'] = wp_get_attachment_image_url($image_id, 'full');
710
+ }else if($key == 'price'){
711
+ $product[$key]['value'] = $postObj->_price;
712
+ $product[$key]['currency'] = (get_option('woocommerce_currency') != '' ? get_option('woocommerce_currency') : 'USD');
713
+ }else if($key == 'sale_price'){
714
+ $product[$key]['value'] = $postObj->_sale_price;
715
+ $product[$key]['currency'] = (get_option('woocommerce_currency') != '' ? get_option('woocommerce_currency') : 'USD');
716
+ }else if($key == 'target_country'){
717
+ $product[$key] = ($postObj->$value != '' ? $postObj->$value : (isset($this->woo_country()[0]) ? $this->woo_country()[0] : ''));
718
+ //$product[$key] = ($postObj->$value != '' ? $postObj->$value : get_option('woocommerce_default_country'));
719
+ }else if($key == 'content_language'){
720
+ $product[$key] = ($postObj->$value != '' ? $postObj->$value : 'en');
721
+ }else if(isset($postObj->$value)){
722
+ // echo $product[$key]."==".$postObj->$value."<br>";
723
+ $product[$key] = $postObj->$value;
724
+ }
725
+ }
726
+
727
+ $entrie = [
728
+ 'merchant_id' => $merchantId,
729
+ 'batch_id' => ++$batchId,
730
+ 'method' => 'insert',
731
+ 'product' => $product
732
+ ];
733
+ $entries[] = $entrie;
734
+ }
735
+
736
+ wp_reset_query();
737
+ }
738
+ }else{
739
+ $qArgs = array(
740
+ 'post_type' => 'product',
741
+ 'post_status' => 'publish',
742
+ 'meta_query' => array(
743
+ 'relation' => 'AND',
744
+ array(
745
+ 'key' => '_stock_status',
746
+ 'value' => 'instock'
747
+ ),
748
+ array(
749
+ 'relation' => 'or',
750
+ array(
751
+ 'key' => '_sale_price',
752
+ 'value' => '',
753
+ 'compare' => '!=',
754
+ ),
755
+ array(
756
+ 'key' => '_price',
757
+ 'value' => '',
758
+ 'compare' => '!=',
759
+ )
760
+ )
761
+ )
762
+ );
763
+ $loop = new WP_Query($qArgs);
764
+ foreach($loop->posts as $postkey => $postvalue){
765
+ $postmeta = [];
766
+ $postmeta = $this->getPostMetaData($postvalue->ID);
767
+ $postObj = (object) array_merge((array) $postvalue, (array) $postmeta);
768
+
769
+ $product = [];
770
+ foreach($formArray as $key => $value){
771
+ $product['content_language'] = 'en';
772
+ //$product['target_country'] = 'US';
773
+ $product['target_country'] = (isset($this->woo_country()[0]) ? $this->woo_country()[0] : '');
774
+ $product['channel'] = 'online';
775
+ if($key == 'price'){
776
+ $product[$key]['value'] = $postObj->_price;
777
+ // $product[$key]['currency'] = 'USD';
778
+ $product[$key]['currency'] = (get_option('woocommerce_currency') != '' ? get_option('woocommerce_currency') : 'USD');
779
+ }else if($key == 'sale_price'){
780
+ $product[$key]['value'] = $postObj->_sale_price;
781
+ //$product[$key]['currency'] = 'USD';
782
+ $product[$key]['currency'] = (get_option('woocommerce_currency') != '' ? get_option('woocommerce_currency') : 'USD');
783
+ }else if($key == 'target_country'){
784
+ $product[$key] = ($postObj->$value != '' ? $postObj->$value : (isset($this->woo_country()[0]) ? $this->woo_country()[0] : ''));
785
+ }else if(isset($postObj->$value)){
786
+ $product[$key] = $postObj->$value;
787
+ }
788
+ }
789
+
790
+ $entrie = [
791
+ 'merchant_id' => $merchantId,
792
+ 'batch_id' => ++$batchId,
793
+ 'method' => 'insert',
794
+ 'product' => $product
795
+ ];
796
+ $entries[] = $entrie;
797
+ }
798
+ wp_reset_query();
799
+ }
800
+
801
+ $data = [
802
+ 'merchant_id' => $accountId,
803
+ 'account_id' => $merchantId,
804
+ //'platform_customer_id' => $platformCustomerId,
805
+ 'subscription_id' => $subscriptionId,
806
+ 'entries' => $entries,
807
+ ];
808
+
809
+ $url = 'https://connect.tatvic.com/laravelapi/public/api/products/batch';
810
+ //$url = 'http://127.0.0.1:8000/api/products/batch';
811
+
812
+ $args = array(
813
+ 'headers' => array(
814
+ 'Authorization' => "Bearer MTIzNA==",
815
+ 'Content-Type' => 'application/json',
816
+ 'AccessToken' => $this->generateAccessToken($_SESSION['access_token'], $_SESSION['refresh_token'])
817
+ ),
818
+ 'body' => wp_json_encode($data)
819
+ );
820
+
821
+ // Send remote request
822
+ /* echo "<pre>";
823
+ print_r($args); */
824
+ $request = wp_remote_post($url, $args);
825
+
826
+ /* print_r($request); */
827
+ /* die; */
828
+ // Retrieve information
829
+ $response_code = wp_remote_retrieve_response_code($request);
830
+ $response_message = wp_remote_retrieve_response_message($request);
831
+ $response_body = json_decode(wp_remote_retrieve_body($request));
832
+
833
+ if((isset($response_body->error) && $response_body->error == '')){
834
+ echo json_encode(['status' => 'success']);
835
+ // return new WP_REST_Response(
836
+ // array(
837
+ // 'status' => $response_code,
838
+ // 'message' => $response_message,
839
+ // 'data' => $response_body->data
840
+ // )
841
+ // );
842
+ }else{
843
+ foreach($response_body->errors as $err){
844
+ $message = $err;
845
+ break;
846
+ }
847
+ echo json_encode(['status' => 'error', 'message' => $message]);
848
+ // return new WP_Error($response_code, $response_message, $response_body);
849
+ }
850
+
851
+ // echo json_encode( $categories );
852
+ }
853
+
854
+ // IMPORTANT: don't forget to exit
855
+ exit;
856
+ }
857
+
858
+ /**
859
+ * create product batch for product sync up
860
+ */
861
+ public function tvcajax_custom_metrics_dimension(){
862
+ // make sure this call is legal
863
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'customMetricsDimensionNonce'), 'tvcajax-custom-metrics-dimension-nonce')){
864
+
865
+ if(!class_exists('CustomApi')){
866
+ include(ENHANCAD_PLUGIN_DIR . 'includes/setup/CustomApi.php');
867
+ }
868
+ $customObj = new CustomApi();
869
+
870
+ $accountId = filter_input(INPUT_POST, 'accountId');
871
+ // $accountId = '184918792';
872
+ $webPropertyId = filter_input(INPUT_POST, 'webPropertyId');
873
+ // $webPropertyId = 'UA-184918792-5';
874
+ $subscriptionId = filter_input(INPUT_POST, 'subscriptionId');
875
+ $data = filter_input(INPUT_POST, 'data');
876
+ parse_str($data, $formArray);
877
+ //print_r($formArray); // Only for print array
878
+
879
+ $customDimension = [];
880
+ $customMetrics = [];
881
+ $dimensions = [];
882
+ $metrics = [];
883
+
884
+ for($i = 1; $i <= 12; $i++){
885
+ $dimension['id'] = "";
886
+ $dimension['index'] = $formArray['did-' . $i];
887
+ $dimension['active'] = true;
888
+ $dimension['kind'] = "";
889
+ $dimension['name'] = $formArray['dname-' . $i];
890
+ $dimension['scope'] = $formArray['dscope-' . $i];
891
+ $dimension['created'] = "";
892
+ $dimension['updated'] = "";
893
+ $dimension['self_link'] = "";
894
+ $dimension['parent_link']['href'] = "";
895
+ $dimension['parent_link']['parent_link_type'] = "";
896
+ $dimensions[] = $dimension;
897
+ }
898
+
899
+ for($i = 1; $i <= 7; $i++){
900
+ $metric['id'] = "";
901
+ $metric['index'] = $formArray['mid-' . $i];
902
+ $metric['active'] = true;
903
+ $metric['kind'] = "";
904
+ $metric['name'] = $formArray['mname-' . $i];
905
+ $metric['scope'] = $formArray['mscope-' . $i];
906
+ $metric['created'] = "";
907
+ $metric['updated'] = "";
908
+ $metric['self_link'] = "";
909
+ $metric['max_value'] = "";
910
+ $metric['min_value'] = "";
911
+ $metric['type'] = "INTEGER";
912
+ $metric['parent_link']['href'] = "";
913
+ $metric['parent_link']['parent_link_type'] = "";
914
+ $metrics[] = $metric;
915
+ }
916
+
917
+ if(!empty($dimensions)){
918
+ $dimenRequest = [];
919
+ $dimenRequest['account_id'] = $accountId;
920
+ $dimenRequest['web_property_id'] = $webPropertyId;
921
+ $dimenRequest['subscription_id'] = $subscriptionId;
922
+ $dimenRequest['data'] = $dimensions;
923
+ $dimenResponse = $customObj->createCustomDimensions($dimenRequest);
924
+ }
925
+ if(!empty($metrics)){
926
+ $metrRequest = [];
927
+ $metrRequest['account_id'] = $accountId;
928
+ $metrRequest['web_property_id'] = $webPropertyId;
929
+ $metrRequest['subscription_id'] = $subscriptionId;
930
+ $metrRequest['data'] = $metrics;
931
+ $metrResponse = $customObj->createCustomMetrics($metrRequest);
932
+ }
933
+
934
+
935
+ // Retrieve information
936
+ /* $response_code = wp_remote_retrieve_response_code($request);
937
+ $response_message = wp_remote_retrieve_response_message($request);
938
+ $response_body = json_decode(wp_remote_retrieve_body($request)); */
939
+
940
+ // print_r($dimenResponse);
941
+ // echo "=======";
942
+ // print_r($metrResponse);
943
+ // exit;
944
+
945
+
946
+ if((isset($dimenResponse->error) && $dimenResponse->error == '' && isset($metrResponse->error) && $metrResponse->error == '')){
947
+ echo json_encode(['status' => 'success']);
948
+ // return new WP_REST_Response(
949
+ // array(
950
+ // 'status' => $response_code,
951
+ // 'message' => $response_message,
952
+ // 'data' => $response_body->data
953
+ // )
954
+ // );
955
+ }else{
956
+ $metrError = '';
957
+ $dimenError = '';
958
+ $message = NULL;
959
+ if($dimenResponse->errors){
960
+ /* print_r($dimenResponse->errors); */
961
+ $dimenError = $dimenResponse->errors[0];
962
+ $message = str_replace('this entity', 'dimensions ', $dimenError);
963
+ }
964
+ if($metrResponse->errors){
965
+ /* print_r($metrResponse->errors); */
966
+ $metrError = str_replace('this entity', 'metrics ', $metrResponse->errors[0]);
967
+ $message = is_null($message) ? $metrError : $message . ' ' . $metrError;
968
+ }
969
+ echo json_encode(['status' => 'error', 'message' => $message]);
970
+ }
971
+ }
972
+
973
+ // IMPORTANT: don't forget to exit
974
+ exit;
975
+ }
976
+
977
+ public function tvcajax_store_time_taken(){
978
+ // make sure this call is legal
979
+ if($this->safe_ajax_call(filter_input(INPUT_POST, 'campaignCategoryListsNonce'), 'tvcajax-store-time-taken-nonce')){
980
+ $ee_options_data = unserialize(get_option('ee_options'));
981
+ if(isset($ee_options_data['subscription_id'])) {
982
+ $ee_subscription_id = $ee_options_data['subscription_id'];
983
+ } else {
984
+ $ee_subscription_id = null;
985
+ }
986
+ $url = 'https://connect.tatvic.com/laravelapi/public/api/customer-subscriptions/update-setup-time';
987
+ $data = [
988
+ 'subscription_id' => $ee_subscription_id,
989
+ 'setup_start_time' => date('Y-m-d H:i:s'),
990
+ ];
991
+ $args = array(
992
+ 'headers' => array(
993
+ 'Authorization' => "Bearer MTIzNA==",
994
+ 'Content-Type' => 'application/json'
995
+ ),
996
+ 'body' => wp_json_encode($data)
997
+ );
998
+ // Send remote request
999
+ $request = wp_remote_post($url, $args);
1000
+ // Retrieve information
1001
+ $response_code = wp_remote_retrieve_response_code($request);
1002
+ $response_message = wp_remote_retrieve_response_message($request);
1003
+ $response_body = json_decode(wp_remote_retrieve_body($request));
1004
+ if((isset($response_body->error) && $response_body->error == '')){
1005
+ echo json_encode($response_body->data);
1006
+ // return new WP_REST_Response(
1007
+ // array(
1008
+ // 'status' => $response_code,
1009
+ // 'message' => $response_message,
1010
+ // 'data' => $response_body->data
1011
+ // )
1012
+ // );
1013
+ }else{
1014
+ echo json_encode([]);
1015
+ // return new WP_Error($response_code, $response_message, $response_body);
1016
+ }
1017
+
1018
+ // echo json_encode( $categories );
1019
+ }
1020
+
1021
+ // IMPORTANT: don't forget to exit
1022
+ exit;
1023
+ }
1024
+ public function generateAccessToken($access_token, $refresh_token) {
1025
+ $request = "https://www.googleapis.com/oauth2/v1/tokeninfo?"
1026
+ . "access_token=" . $access_token;
1027
+
1028
+ $ch = curl_init();
1029
+ curl_setopt($ch, CURLOPT_URL, $request);
1030
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1031
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1032
+ $response = curl_exec($ch);
1033
+ $result = json_decode($response);
1034
+
1035
+ if (isset($result->error) && $result->error) {
1036
+ $credentials_file = ENHANCAD_PLUGIN_DIR . 'includes/setup/json/client-secrets.json';
1037
+ $str = file_get_contents($credentials_file);
1038
+ $credentials = $str ? json_decode($str, true) : [];
1039
+ $url = 'https://www.googleapis.com/oauth2/v4/token';
1040
+ $header = array("content-type: application/json");
1041
+ $clientId = $credentials['web']['client_id'];
1042
+ $clientSecret = $credentials['web']['client_secret'];
1043
+ $refreshToken = $refresh_token;
1044
+ $data = [
1045
+ "grant_type" => 'refresh_token',
1046
+ "client_id" => $clientId,
1047
+ 'client_secret' => $clientSecret,
1048
+ 'refresh_token' => $refreshToken,
1049
+ ];
1050
+
1051
+ $postData = json_encode($data);
1052
+ $ch = curl_init();
1053
+ curl_setopt_array($ch, array(
1054
+ CURLOPT_URL => $url, //esc_url($this->curl_url),
1055
+ CURLOPT_RETURNTRANSFER => true,
1056
+ CURLOPT_TIMEOUT => 0,
1057
+ CURLOPT_HTTPHEADER => $header,
1058
+ CURLOPT_POSTFIELDS => $postData
1059
+ ));
1060
+ $response = curl_exec($ch);
1061
+ $response = json_decode($response);
1062
+ return $response->access_token;
1063
+ } else {
1064
+ return $access_token;
1065
+ }
1066
+ }
1067
+ public function woo_country(){
1068
+ // The country/state
1069
+ $store_raw_country = get_option('woocommerce_default_country');
1070
+ // Split the country/state
1071
+ $split_country = explode(":", $store_raw_country);
1072
+ return $split_country;
1073
+ }
1074
+
1075
+ }
1076
+
1077
+ // End of TVC_Ajax_File_Class
1078
+
1079
+ endif;
1080
+
1081
+ $tvcajax_file_class = new TVC_Ajax_File();
includes/data/class-tvc-backup.php ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Backup Class.
5
+ *
6
+ * @package WP Product Feed Manager/Data/Classes
7
+ * @version 1.0.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Backup' ) ) :
15
+
16
+ class TVC_Backup {
17
+
18
+ private $_wpdb;
19
+
20
+ /**
21
+ * @var string placeholder containing the wp table prefix
22
+ */
23
+ private $_table_prefix;
24
+
25
+ /**
26
+ * TVC_Queries Constructor
27
+ */
28
+ public function __construct() {
29
+ // get global WordPress database functions
30
+ global $wpdb;
31
+
32
+ // assign the global wpdb to a variable
33
+ $this->_wpdb = &$wpdb;
34
+
35
+ // assign the wp table prefix to a variable
36
+ $this->_table_prefix = $this->_wpdb->prefix;
37
+ }
38
+
39
+ /**
40
+ * Reads the data from all plugin related tables ands stores the data in a sql like string
41
+ * The return string contains a timestamp, the database version, the option settings and the table content
42
+ *
43
+ * @since 1.7.0
44
+ * @return string sql like string with the backup data
45
+ */
46
+ public function read_full_backup_data() {
47
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
48
+ $meta_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
49
+ $channel_table = $this->_table_prefix . 'feedmanager_channel';
50
+
51
+ $main_table_columns = $this->_wpdb->get_col( "DESC {$main_table}", 0 );
52
+ $meta_table_columns = $this->_wpdb->get_col( "DESC {$meta_table}", 0 );
53
+ $channel_table_columns = $this->_wpdb->get_col( "DESC {$channel_table}", 0 );
54
+
55
+ $main_table_content = $this->make_table_backup_string( $this->_wpdb->get_results( "SELECT * FROM $main_table", ARRAY_N ), $main_table_columns );
56
+ $meta_table_content = $this->make_table_backup_string( $this->_wpdb->get_results( "SELECT * FROM $meta_table", ARRAY_N ), $meta_table_columns );
57
+ $channel_table_content = $this->make_table_backup_string( $this->_wpdb->get_results( "SELECT * FROM $channel_table", ARRAY_N ), $channel_table_columns );
58
+
59
+ $db_version = get_option( 'tvc_db_version' );
60
+ $ftp_passive = 'inactive';
61
+ $auto_fix = get_option( 'tvc_auto_feed_fix', 'false' );
62
+ $third_party_attributes = get_option( 'tvc_third_party_attribute_keywords', '%wpmr%,%cpf%,%unit%,%bto%,%yoast%' );
63
+ $disabled_background_mode = get_option( 'tvc_disabled_background_mode', 'false' ); // @since 2.0.7
64
+ $process_logger_option = get_option( 'tvc_process_logger_status', 'false' ); // @since 2.9.0
65
+ $show_pi_option = get_option( 'tvc_show_product_identifiers', 'false' ); // @since 2.10.0
66
+ $sep_string = '# backup string for database ->';
67
+ $time_stamp = current_time( 'timestamp' );
68
+
69
+ $table_content = "$time_stamp#$db_version#$ftp_passive#$auto_fix#$third_party_attributes#$disabled_background_mode#$process_logger_option#$show_pi_option";
70
+ $table_content .= "$sep_string $main_table # <- # $main_table_content ";
71
+ $table_content .= "$sep_string $meta_table # <- # $meta_table_content ";
72
+ $table_content .= "$sep_string $channel_table # <- # $channel_table_content";
73
+
74
+ return $table_content;
75
+ }
76
+
77
+ /**
78
+ * Restores the data in the database tables
79
+ *
80
+ * @since 1.7.0
81
+ *
82
+ * @param array $table_queries
83
+ *
84
+ * @return boolean
85
+ */
86
+ public function restore_backup_data( $table_queries ) {
87
+ // retrieve the initial data strings
88
+ $product_feed_table_data = explode( ' # ', $table_queries[0][1] );
89
+ $product_feedmeta_table_data = explode( ' # ', $table_queries[1][1] );
90
+ $channel_table_data = explode( ' # ', $table_queries[2][1] );
91
+
92
+ // table names
93
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
94
+ $meta_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
95
+ $channel_table = $this->_table_prefix . 'feedmanager_channel';
96
+
97
+ // clear the current data
98
+ $this->_wpdb->query( "TRUNCATE TABLE $main_table" );
99
+ $this->_wpdb->query( "TRUNCATE TABLE $meta_table" );
100
+ $this->_wpdb->query( "TRUNCATE TABLE $channel_table" );
101
+
102
+ // get the columns
103
+ $product_feed_table_columns = explode( ', ', $product_feed_table_data[0] );
104
+ $product_feedmeta_table_columns = explode( ', ', $product_feedmeta_table_data[0] );
105
+ $channel_table_columns = explode( ', ', $channel_table_data[0] );
106
+
107
+ // get the data
108
+ $product_feed_table_queries = explode( PHP_EOL, $product_feed_table_data[1] );
109
+ $product_feedmeta_table_queries = explode( PHP_EOL, $product_feedmeta_table_data[1] );
110
+ $channel_table_queries = explode( PHP_EOL, $channel_table_data[1] );
111
+
112
+ // restore the feedmanager_product_feed table
113
+ foreach ( $product_feed_table_queries as $table_data ) {
114
+ $product_feed_data = explode( "\t", $table_data );
115
+
116
+ if ( count( $product_feed_table_columns ) === count( $product_feed_data ) ) {
117
+ $data = array();
118
+
119
+ for ( $i = 0; $i < count( $product_feed_data ); $i ++ ) {
120
+ $data[ $product_feed_table_columns[ $i ] ] = $product_feed_data[ $i ];
121
+ }
122
+
123
+ $this->_wpdb->replace( $main_table, $data );
124
+ }
125
+ }
126
+
127
+ // restore the feedmanager_product_feedmeta table
128
+ foreach ( $product_feedmeta_table_queries as $table_metadata ) {
129
+ $product_feed_metadata = explode( "\t", $table_metadata );
130
+
131
+ if ( count( $product_feedmeta_table_columns ) === count( $product_feed_metadata ) ) {
132
+ $data = array();
133
+
134
+ for ( $i = 0; $i < count( $product_feed_metadata ); $i ++ ) {
135
+ $data[ $product_feedmeta_table_columns[ $i ] ] = $product_feed_metadata[ $i ];
136
+ }
137
+
138
+ $this->_wpdb->replace( $meta_table, $data );
139
+ }
140
+ }
141
+
142
+ // restore the feedmanager_channel table
143
+ foreach ( $channel_table_queries as $table_channeldata ) {
144
+ $channel_data = explode( "\t", $table_channeldata );
145
+
146
+ if ( count( $channel_table_columns ) === count( $channel_data ) ) {
147
+ $data = array();
148
+
149
+ for ( $i = 0; $i < count( $channel_data ); $i ++ ) {
150
+ $data[ $channel_table_columns[ $i ] ] = $channel_data[ $i ];
151
+ }
152
+
153
+ $this->_wpdb->replace( $channel_table, $data );
154
+ }
155
+ }
156
+
157
+ return true;
158
+ }
159
+
160
+ /**
161
+ * Returns a tab separated string with the query results.
162
+ *
163
+ * @param (string) $query_result
164
+ * @param {array} $columns
165
+ *
166
+ * @return (string) backup string
167
+ */
168
+ private function make_table_backup_string( $query_result, $columns ) {
169
+ $string = implode( $columns, ', ' ) . ' # ';
170
+
171
+ foreach ( $query_result as $row ) {
172
+ $string .= implode( "\t", $row ) . "\r\n";
173
+ }
174
+
175
+ return $string;
176
+ }
177
+ }
178
+
179
+ // end of TVC_Backup class
180
+
181
+ endif;
includes/data/class-tvc-channel-ftp.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Product Feed Manager Channel FTP Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 2.2.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+
15
+ if ( ! class_exists( 'TVC_Channel_FTP' ) ) :
16
+
17
+ /**
18
+ * Channel FTP Class
19
+ */
20
+ class TVC_Channel_FTP {
21
+
22
+ /**
23
+ * Gets the correct channel zip file from the wp server
24
+ *
25
+ * @since 1.9.3 - switched from ftp to cURL procedures
26
+ *
27
+ * @param string $channel
28
+ * @param string $code
29
+ *
30
+ * @return boolean
31
+ */
32
+
33
+ }
34
+
35
+ // end of TVC_Channel_FTP class
36
+
37
+ endif;
includes/data/class-tvc-channel.php ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Channels Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.6.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Channel' ) ) :
15
+
16
+ /**
17
+ * Channel Class
18
+ */
19
+ class TVC_Channel {
20
+ /**
21
+ * Placeholder for the Channel Classes
22
+ *
23
+ * @var string
24
+ */
25
+ private $_channels;
26
+
27
+ public function __construct() {
28
+ // TVC_CHANNEL_RELATED
29
+ $this->_channels = array(
30
+ new Channel( '0', 'usersetup', 'Free User Setup' ),
31
+ new Channel( '1', 'google', 'Google Merchant Centre' ),
32
+ new Channel( '2', 'bing', 'Bing Merchant Centre' ),
33
+ new Channel( '3', 'beslis', 'Beslis.nl' ),
34
+ new Channel( '4', 'pricegrabber', 'PriceGrabber' ),
35
+ new Channel( '5', 'shopping', 'Shopping.com (eBay)' ),
36
+ new Channel( '6', 'amazon', 'Amazon product ads' ),
37
+ new Channel( '7', 'connexity', 'Connexity' ),
38
+ new Channel( '8', 'become', 'Become' ),
39
+ // Become has been taken over by Connexity, https://merchants.become.com/DataFeedSpecification.html links to Connexity
40
+ new Channel( '9', 'nextag', 'Nextag' ),
41
+ new Channel( '10', 'kieskeurig', 'Kieskeurig.nl' ),
42
+ new Channel( '11', 'vergelijk', 'Vergelijk.nl' ),
43
+ new Channel( '12', 'koopjespakker', 'Koopjespakker.nl' ),
44
+ new Channel( '13', 'avantlink', 'AvantLink' ),
45
+ new Channel( '14', 'zbozi', 'Zbozi' ),
46
+ new Channel( '15', 'comcon', 'Commerce Connector' ),
47
+ new Channel( '16', 'facebook', 'Facebook' ),
48
+ new Channel( '17', 'bol', 'Bol.com' ),
49
+ new Channel( '18', 'adtraction', 'Adtraction' ),
50
+ new Channel( '19', 'ricardo', 'Ricardo.ch' ),
51
+ new Channel( '20', 'ebay', 'eBay' ),
52
+ new Channel( '21', 'shopzilla', 'Shopzilla' ),
53
+ new Channel( '22', 'converto', 'Converto' ),
54
+ new Channel( '23', 'idealo', 'Idealo' ),
55
+ new Channel( '24', 'heureka', 'Heureka' ),
56
+ new Channel( '25', 'pepperjam', 'Pepperjam' ),
57
+ new Channel( '26', 'galaxus_data', 'Galaxus Product Data' ),
58
+ new Channel( '27', 'galaxus_properties', 'Galaxus Product Properties' ),
59
+ new Channel( '28', 'galaxus_stock_pricing', 'Galaxus Product Stock Pricing' ),
60
+ new Channel( '996', '_tsv', 'Custom TSV Export' ),
61
+ new Channel( '997', '_txt', 'Custom TXT Export' ),
62
+ new Channel( '998', '_csv', 'Custom CSV Export' ),
63
+ new Channel( '999', '', 'Custom XML Export' ),
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Returns channel data from a specific channel
69
+ *
70
+ * @param string $channel_name channel name
71
+ *
72
+ * @return string Channel class
73
+ */
74
+ public function get_active_channel_details( $channel_name ) {
75
+ foreach ( $this->_channels as $channel ) {
76
+ if ( $channel->channel_short === $channel_name ) {
77
+ return $channel;
78
+ }
79
+ }
80
+ return false;
81
+ }
82
+
83
+ public function get_channel_short_name( $channel_id ) {
84
+ foreach ( $this->_channels as $channel ) {
85
+ if ( $channel->channel_id === $channel_id ) {
86
+ return $channel->channel_short;
87
+ }
88
+ }
89
+ return false;
90
+ }
91
+
92
+ public function get_channel_name( $channel_id ) {
93
+ foreach ( $this->_channels as $channel ) {
94
+ if ( $channel->channel_id === $channel_id ) {
95
+ return $channel->channel_name;
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+
101
+ public function get_installed_channel_names() {
102
+ $file_class = new TVC_File();
103
+
104
+ return $file_class->get_installed_channels_from_file();
105
+ }
106
+
107
+ public function remove_channel( $channel, $nonce ) {
108
+ if ( wp_verify_nonce( $nonce, 'delete-channel-nonce' ) ) {
109
+ $this->remove_channel_source( $channel );
110
+ }
111
+ }
112
+
113
+ public function update_channel( $channel, $code, $nonce ) {
114
+ if ( wp_verify_nonce( $nonce, 'update-channel-nonce' ) ) {
115
+ $this->update_channel_source( $channel, $code );
116
+ } else {
117
+ tvc_write_log_file( sprintf( 'Failed to update channel %s because then nonce was not accepted. Given nonce = %s', $channel, $nonce ) );
118
+ }
119
+ }
120
+
121
+ public function install_channel( $channel, $code, $nonce ) {
122
+ if ( wp_verify_nonce( $nonce, 'install-channel-nonce' ) ) {
123
+ $this->install_channel_source( $channel, $code );
124
+ } else {
125
+ tvc_write_log_file( sprintf( 'Failed to install channel %s because then nonce was not accepted. Given nonce = %s', $channel, $nonce ) );
126
+ }
127
+ }
128
+
129
+ public function get_channels_from_server() {
130
+ $response = "Google Merchant Centre";
131
+ return $response;
132
+ }
133
+
134
+ public function get_number_of_updates_from_server( $channel_updated ) {
135
+ if ( date( 'Ymd' ) === get_option( 'tvc_channel_update_check_date' ) ) {
136
+ if ( $channel_updated ) {
137
+ tvc_decrease_update_ready_channels();
138
+ }
139
+
140
+ return get_option( 'tvc_channels_to_update' );
141
+ } else {
142
+ $response = $this->get_channels_from_server();
143
+
144
+ if ( ! is_wp_error( $response ) ) {
145
+ $available_channels = json_decode( $response['body'] );
146
+
147
+ if ( $available_channels ) {
148
+ $installed_channels_names = $this->get_installed_channel_names();
149
+
150
+ $this->add_status_data_to_available_channels( $available_channels, $installed_channels_names, false );
151
+
152
+ $stored_count = $this->count_updatable_channels( $available_channels );
153
+
154
+ $count = $channel_updated ? ( $stored_count - 1 ) : $stored_count;
155
+ update_option( 'tvc_channels_to_update', $count > 0 ? $count : 0 );
156
+ update_option( 'tvc_channel_update_check_date', date( 'Ymd' ) );
157
+
158
+ return $count;
159
+ }
160
+ } else {
161
+ echo tvc_handle_wp_errors_response(
162
+ $response,
163
+ sprintf(
164
+ /* translators: %s: url to the support page */
165
+ esc_html__(
166
+ '2141 - Please open a support ticket at %s for support on this issue.',
167
+ 'tvc-product-feed-manager'
168
+ ),
169
+ TVC_SUPPORT_PAGE_URL
170
+ )
171
+ );
172
+
173
+ return false;
174
+ }
175
+ }
176
+
177
+ return 0;
178
+ }
179
+
180
+ public function add_status_data_to_available_channels( &$available_channels, $installed_channels, $updated ) {
181
+ for ( $i = 0; $i < count( $available_channels ); $i ++ ) {
182
+ if ( in_array( $available_channels[ $i ]->short_name, $installed_channels ) ) {
183
+ $available_channels[ $i ]->status = 'installed';
184
+
185
+ $available_channels[ $i ]->installed_version = $available_channels[ $i ]->short_name === $updated ? $available_channels[ $i ]->version
186
+ : $this->get_channel_file_version( $available_channels[ $i ]->short_name, 0 );
187
+ } else {
188
+ $available_channels[ $i ]->status = 'not installed';
189
+ $available_channels[ $i ]->installed_version = '0';
190
+ }
191
+ }
192
+ }
193
+
194
+ private function get_channel_file_version( $channel_name, $rerun_counter ) {
195
+ if ( $rerun_counter < 3 ) {
196
+ if ( class_exists( 'TVC_' . ucfirst( $channel_name ) . '_Feed_Class' ) ) {
197
+ $class_var = 'TVC_' . ucfirst( $channel_name ) . '_Feed_Class';
198
+
199
+ $channel_class = new $class_var();
200
+
201
+ return $channel_class->get_version();
202
+ } else {
203
+ // reset the registered channels in the channel table
204
+ $db_class = new TVC_Database_Management();
205
+ $db_class->reset_channel_registration();
206
+
207
+ include_channels(); // include the channel classes
208
+
209
+ $rerun_counter ++;
210
+
211
+ return $this->get_channel_file_version( $channel_name, $rerun_counter );
212
+ }
213
+ } else {
214
+ if ( tvc_on_any_own_plugin_page() ) {
215
+ /* translators: %s: Name of a channel */
216
+ echo tvc_show_wp_error( sprintf( esc_html__( 'Channel %s is not installed correctly. Please try to Deactivate and then Activate the Feed Manager Plugin in your Plugins page.', 'tvc-product-feed-manager' ), $channel_name ) );
217
+ tvc_write_log_file( sprintf( 'Error: Channel %s is not installed correctly.', $channel_name ) );
218
+ }
219
+
220
+ return 'unknown';
221
+ }
222
+ }
223
+
224
+ private function count_updatable_channels( $channel_data ) {
225
+ $counter = 0;
226
+
227
+ foreach ( $channel_data as $channel ) {
228
+ if ( 'installed' === $channel->status && ( $channel->version > $channel->installed_version ) ) {
229
+ $counter ++;
230
+ }
231
+ }
232
+
233
+ return $counter;
234
+ }
235
+
236
+ private function update_channel_source( $channel, $code ) {
237
+ $file_class = new TVC_File();
238
+ $ftp_class = new TVC_Channel_FTP();
239
+
240
+ // remove the out dated channel source files from the server
241
+ $file_class->delete_channel_source_files( $channel );
242
+
243
+ $get_result = $ftp_class->get_channel_source_files( $channel, $code );
244
+
245
+ // get the update files from .com
246
+ if ( false !== $get_result ) {
247
+ // unzip the file
248
+ $file_class->unzip_channel_file( $channel );
249
+
250
+ // register the update
251
+ tvc_decrease_update_ready_channels();
252
+ }
253
+ }
254
+
255
+ private function remove_channel_source( $channel_short ) {
256
+ $data_class = new TVC_Data();
257
+ $file_class = new TVC_File();
258
+
259
+ // get the channel id that needs to be removed
260
+ $channel_id = $data_class->get_channel_id_from_short_name( $channel_short );
261
+
262
+ // unregister the channel
263
+ wp_dequeue_script( 'tvc_' . $channel_short . '-source-script' );
264
+
265
+ if ( $channel_id ) {
266
+ // remove channel related feed files
267
+ $file_class->delete_channel_feed_files( $channel_id );
268
+
269
+ // remove any channel related feed data and feed meta
270
+ $data_class->delete_channel_feeds( $channel_id );
271
+ }
272
+
273
+ // remove the channel from the feedmanager_channel table
274
+ $data_class->delete_channel( $channel_short );
275
+
276
+ // remove the channel source files from the server
277
+ $file_class->delete_channel_source_files( $channel_short );
278
+ }
279
+
280
+ private function install_channel_source( $channel_name, $code ) {
281
+ $ftp_class = new TVC_Channel_FTP();
282
+ $file_class = new TVC_File();
283
+ $data_class = new TVC_Data();
284
+
285
+ if ( plugin_version_supports_channel( $channel_name ) ) {
286
+ $get_result = $ftp_class->get_channel_source_files( $channel_name, $code );
287
+
288
+ // get the update files from .com
289
+ if ( false !== $get_result ) {
290
+
291
+ // unzip the file
292
+ $file_class->unzip_channel_file( $channel_name );
293
+
294
+ // register the new channel
295
+ $channel_details = $this->get_active_channel_details( $channel_name );
296
+
297
+ if ( false !== $channel_details ) {
298
+ $data_class->register_channel( $channel_name, $channel_details );
299
+ } else {
300
+ tvc_write_log_file( sprintf( 'Unable to register channel %s' . $channel_name ) );
301
+ }
302
+ } else {
303
+ tvc_write_log_file(
304
+ sprintf(
305
+ 'Could not get the %s channel file from the server. Get_result message is %s.',
306
+ $channel_name,
307
+ $get_result
308
+ )
309
+ );
310
+ }
311
+ } else {
312
+ echo tvc_show_wp_warning(
313
+ sprintf(
314
+ /* translators: %s: Name of the selected channel */
315
+ esc_html__(
316
+ 'Channel %s is not supported by your current plugin version. Please update your plugin to the latest version and try uploading this channel again.',
317
+ 'tvc-product-feed-manager'
318
+ ),
319
+ $channel_name
320
+ ),
321
+ 'tvc-product-feed-manager'
322
+ );
323
+ }
324
+ }
325
+ }
326
+
327
+ // end of TVC_Channel class
328
+
329
+ class Channel {
330
+ public $channel_id;
331
+ public $channel_short;
332
+ public $channel_name;
333
+
334
+ public function __construct( $id, $short, $name ) {
335
+ $this->channel_id = $id;
336
+ $this->channel_short = $short;
337
+ $this->channel_name = $name;
338
+ }
339
+ }
340
+
341
+ // end of Channel class
342
+ endif;
includes/data/class-tvc-data.php ADDED
@@ -0,0 +1,713 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * WP Data Class.
5
+ *
6
+ * @package WP Product Feed Manager/Data/Classes
7
+ * @version 3.5.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Data' ) ) :
15
+
16
+ /**
17
+ * Data Class
18
+ */
19
+ class TVC_Data {
20
+
21
+ private $_queries_class;
22
+ private $_files_class;
23
+
24
+ public function __construct() {
25
+ $this->_queries_class = new TVC_Queries();
26
+ $this->_files_class = new TVC_File();
27
+ }
28
+
29
+ public function get_countries() {
30
+ return $this->_queries_class->read_countries();
31
+ }
32
+
33
+ /**
34
+ * @param $channel_short_name
35
+ * @return string|null
36
+ */
37
+ public function get_channel_id_from_short_name( $channel_short_name ) {
38
+ return $this->_queries_class->get_channel_id( $channel_short_name );
39
+ }
40
+
41
+ public function get_channels() {
42
+ return $this->_queries_class->read_channels();
43
+ }
44
+
45
+ /**
46
+ * @param $channel_short
47
+ * @return bool|false|int
48
+ */
49
+ public function delete_channel( $channel_short ) {
50
+ $result = $this->_queries_class->remove_channel_from_db( $channel_short );
51
+
52
+ if ( ! $result || 0 == $result ) {
53
+ $result = $this->_queries_class->clean_channel_table();
54
+ }
55
+
56
+ return $result;
57
+ }
58
+
59
+ /**
60
+ * @param $channel_id
61
+ */
62
+ public function delete_channel_feeds( $channel_id ) {
63
+ $feeds = $this->_queries_class->get_feeds_from_specific_channel( $channel_id );
64
+
65
+ foreach ( $feeds as $feed_id ) {
66
+ $this->_queries_class->delete_meta( $feed_id['product_feed_id'] );
67
+ $this->_queries_class->delete_feed( $feed_id['product_feed_id'] );
68
+ }
69
+ }
70
+
71
+ public function get_sources() {
72
+ return $this->_queries_class->read_sources();
73
+ }
74
+
75
+ /**
76
+ * @param $country_code
77
+ * @return array|object|stdClass|void|null
78
+ */
79
+ public function get_country_id_from_short_code( $country_code ) {
80
+ if ( '0' !== $country_code && 0 !== $country_code ) {
81
+ return $this->_queries_class->get_country_id( $country_code );
82
+ } else {
83
+ $id = new stdClass();
84
+ $id->country_id = '233';
85
+
86
+ return $id;
87
+ }
88
+ }
89
+
90
+ public function get_schedule_data() {
91
+ return $this->_queries_class->read_active_schedule_data();
92
+ }
93
+
94
+ public function get_failed_feeds() {
95
+ return $this->_queries_class->read_failed_feeds();
96
+ }
97
+
98
+ /**
99
+ * @param $feed_id
100
+ * @return mixed
101
+ */
102
+ public function get_feed_status( $feed_id ) {
103
+ $feed_status = $this->_queries_class->get_current_feed_status( $feed_id );
104
+
105
+ return $feed_status[0]->status_id;
106
+ }
107
+
108
+ /**
109
+ * @param $feed_id
110
+ * @param $nr
111
+ * @return false|int
112
+ */
113
+ public function set_nr_of_feed_products( $feed_id, $nr ) {
114
+ return $this->_queries_class->set_nr_feed_products( $feed_id, $nr );
115
+ }
116
+
117
+ /**
118
+ * @param $feed_id
119
+ * @return array|object|void|null
120
+ */
121
+ public function get_nr_of_feed_products( $feed_id ) {
122
+ return $this->_queries_class->get_nr_feed_products( $feed_id );
123
+ }
124
+
125
+ /**
126
+ * @param $feed_id
127
+ * @param $feed_url
128
+ * @param $nr_products
129
+ * @return false|int
130
+ */
131
+ public function update_feed_data( $feed_id, $feed_url, $nr_products ) {
132
+ return $this->_queries_class->update_feed_update_data( $feed_id, $feed_url, $nr_products );
133
+ }
134
+
135
+ /**
136
+ * Sets the status id of a feed
137
+ *
138
+ * 0 = unknown
139
+ * 1 = OK (will be updated automatically)
140
+ * 2 = On hold (will not be updated automatically)
141
+ * 3 = Processing
142
+ * 4 = In processing queue
143
+ * 5 = Has errors
144
+ * 6 = Failed processing
145
+ *
146
+ * @param string $feed_id
147
+ * @param int $status
148
+ *
149
+ * @return bool True if the update succeeded.
150
+ */
151
+ public function update_feed_status( $feed_id, $status ) {
152
+
153
+ $message_level = 'MESSAGE';
154
+
155
+ switch ( $status ) {
156
+ case 1:
157
+ $message = sprintf( 'The feed status of feed %s has been set to OK (1)', $feed_id );
158
+ break;
159
+
160
+ case 2:
161
+ $message = sprintf( 'The feed status of feed %s has been set to On Hold (2)', $feed_id );
162
+ break;
163
+
164
+ case 3:
165
+ $message = sprintf( 'The feed status of feed %s has been set to Processing (3)', $feed_id );
166
+ break;
167
+
168
+ case 4:
169
+ $message = sprintf( 'The feed status of feed %s has been set to In processing queue (4)', $feed_id );
170
+ break;
171
+
172
+ case 5:
173
+ $message = sprintf( 'The feed status of feed %s has been set to Has errors (5)', $feed_id );
174
+ $message_level = 'ERROR';
175
+ break;
176
+
177
+ case 6:
178
+ $message = sprintf( 'The feed status of feed %s has been set to Failed processing (6)', $feed_id );
179
+ $message_level = 'ERROR';
180
+ break;
181
+
182
+ default:
183
+ $message = sprintf( 'Tried to update the status of feed %s but the status is unknown!', $feed_id );
184
+ $message_level = 'ERROR';
185
+ }
186
+
187
+ do_action( 'tvc_feed_generation_message', $feed_id, $message, $message_level );
188
+
189
+ return $this->_queries_class->update_feed_file_status( $feed_id, $status );
190
+ }
191
+
192
+ /**
193
+ * Fills output fields with stored meta data
194
+ *
195
+ * @access public
196
+ *
197
+ * @param string $feed_id
198
+ * @param array $outputs
199
+ *
200
+ * @return array
201
+ */
202
+ public function fill_output_fields_with_metadata( $feed_id, $outputs ) {
203
+ // read the meta data from the database
204
+ $metadata = $this->_queries_class->read_metadata( $feed_id );
205
+
206
+ // loop through the output rows
207
+ for ( $i = 0; $i < count( $outputs ); $i ++ ) {
208
+ // check if there is specific meta data for this output row
209
+ if ( count( $metadata ) > 0 ) {
210
+ foreach ( $metadata as $meta ) {
211
+ // look for a match
212
+ if ( $meta['meta_key'] === $outputs[ $i ]->field_label ) {
213
+ // put the meta data in the value variable of the output row
214
+ $outputs[ $i ]->value = $meta['meta_value'];
215
+ break; // break is required to stop the foreach loop and prevent the following loop from clearing the value
216
+ } else {
217
+ // as long as there is no match, leave the value empty
218
+ $outputs[ $i ]->value = '';
219
+ }
220
+ }
221
+ } else {
222
+ $outputs[ $i ]->value = '';
223
+ }
224
+ }
225
+
226
+ return $outputs;
227
+ }
228
+
229
+ /**
230
+ * Collects the source fields from all the different attributes.
231
+ *
232
+ * @param string $source_id The source id (not in use at the moment). Default 1.
233
+ *
234
+ * @return mixed|void|null
235
+ */
236
+ public function get_source_fields( $source_id = '1' ) {
237
+ $source_fields = null;
238
+
239
+ switch ( $source_id ) {
240
+ case '1':
241
+ $data_class = new TVC_Data();
242
+
243
+ $custom_product_attributes = $this->_queries_class->get_custom_product_attributes();
244
+ $custom_product_fields = $this->_queries_class->get_custom_product_fields();
245
+ $product_attributes = $this->_queries_class->get_all_product_attributes();
246
+ $product_taxonomies = get_taxonomies();
247
+ $third_party_custom_fields = $data_class->get_third_party_custom_fields();
248
+
249
+ $combined_source_fields = $this->combine_custom_attributes_and_feeds(
250
+ $custom_product_attributes,
251
+ $custom_product_fields,
252
+ $product_attributes,
253
+ $product_taxonomies,
254
+ $third_party_custom_fields
255
+ );
256
+
257
+ $source_fields = apply_filters( 'tvc_all_source_fields', $combined_source_fields );
258
+ break;
259
+
260
+ default:
261
+ if ( 'valid' === get_option( 'tvc_lic_status' ) ) { // error message for paid versions
262
+ echo '<div id="error">' . __(
263
+ 'Could not add custom fields because I could not identify the channel.
264
+ If not already done add the correct channel in the Manage Channels page.
265
+ Also try to deactivate and then activate the plugin.',
266
+ 'tvc-product-feed-manager'
267
+ ) . '</div>';
268
+
269
+ tvc_write_log_file( sprintf( 'Could not define the channel in a valid Premium plugin version. Feed id = %s', $source_id ) );
270
+ } else { // error message for free version
271
+ echo '<div id="error">' . __(
272
+ 'Could not identify the channel.
273
+ Try to deactivate and then activate the plugin.
274
+ If that does not work remove the plugin through the WordPress Plugins page and than reinstall and activate it again.',
275
+ 'tvc-product-feed-manager'
276
+ ) . '</div>';
277
+
278
+ tvc_write_log_file( sprintf( 'Could not define the channel in a free plugin version. Feed id = %s', $source_id ) );
279
+ }
280
+ break;
281
+ }
282
+ return $source_fields;
283
+ }
284
+
285
+ /**
286
+ * Get the attribute data of a specific feed.
287
+ *
288
+ * @param string $feed_id The id of the feed from which the attribute data is needed.
289
+ * @param string $channel_id The id of the channel of the feed.
290
+ *
291
+ * @return array The attribute data.
292
+ */
293
+ public function get_attribute_data( $feed_id, $channel_id ) {
294
+ $is_custom = function_exists( 'tvc_channel_is_custom_channel' ) ? tvc_channel_is_custom_channel( $channel_id ) : false;
295
+ $channel_name = trim( $this->_queries_class->get_channel_short_name_from_db( $channel_id ) );
296
+
297
+ if ( ! $is_custom ) {
298
+ // read the output fields
299
+ $attributes_data = $this->_files_class->get_output_fields_for_specific_channel( $channel_name );
300
+
301
+ // if the feed is a stored feed, look for meta data to add (a feed an id of -1 is a new feed that not yet has been saved)
302
+ if ( $feed_id >= 0 ) {
303
+ // add meta data to the feeds output fields
304
+ $attributes_data = $this->fill_output_fields_with_metadata( $feed_id, $attributes_data );
305
+ }
306
+ } else {
307
+ $attributes_data = $this->get_custom_fields_with_metadata( $feed_id );
308
+ }
309
+ return $attributes_data;
310
+ }
311
+
312
+ /**
313
+ * @param $feed_id
314
+ * @return array|bool|object|null
315
+ */
316
+ public function get_filter_query( $feed_id ) {
317
+ return $this->_queries_class->get_product_filter_query( $feed_id );
318
+ }
319
+
320
+ /**
321
+ * @param $variation_id
322
+ * @return array
323
+ */
324
+ public function get_own_variation_data( $variation_id ) {
325
+ return $this->_queries_class->get_own_variable_product_attributes( $variation_id );
326
+ }
327
+
328
+ /**
329
+ * @param $product_data
330
+ * @param $parent_id
331
+ * @param $post_columns_query_string
332
+ */
333
+ public function add_parent_data( &$product_data, $parent_id, $post_columns_query_string ) {
334
+ $parent_product_data = (array) $this->_queries_class->read_post_data( $parent_id, $post_columns_query_string );
335
+ $sources_that_always_use_parent_data = apply_filters( 'sources_that_always_use_data_from_parent', array( 'post_excerpt' ) );
336
+
337
+ $columns = explode( ', ', $post_columns_query_string );
338
+
339
+ foreach ( $columns as $column ) {
340
+ if ( ( '' === $product_data[ $column ] && array_key_exists( $column, $parent_product_data ) && '' !== $parent_product_data[ $column ] )
341
+ || in_array( $column, $sources_that_always_use_parent_data ) ) {
342
+ $product_data[ $column ] = $parent_product_data[ $column ];
343
+ }
344
+ }
345
+ }
346
+
347
+ /**
348
+ * @param $feed_id
349
+ * @return array
350
+ */
351
+ public function get_custom_fields_with_metadata( $feed_id ) {
352
+ // read the meta data from the database
353
+ $metadata = $this->_queries_class->read_metadata( $feed_id );
354
+ $outputs = array();
355
+
356
+ // loop through the output rows
357
+ for ( $i = 0; $i < count( $metadata ); $i ++ ) {
358
+ $object = new stdClass();
359
+
360
+ $object->field_id = $i + 1;
361
+ $object->category_id = '5';
362
+ $object->field_label = $metadata[ $i ]['meta_key'];
363
+ $object->value = $metadata[ $i ]['meta_value'];
364
+
365
+ array_push( $outputs, $object );
366
+ }
367
+
368
+ return $outputs;
369
+ }
370
+
371
+ public function get_third_party_custom_fields() {
372
+ $custom_fields = array();
373
+
374
+ // YITH Brands plugin
375
+ $yith_brand_label = get_option( 'yith_wcbr_brands_label' );
376
+ if ( $yith_brand_label ) {
377
+ array_push( $custom_fields, $yith_brand_label );
378
+ }
379
+
380
+ // WooCommerce Brands
381
+ if ( in_array(
382
+ 'woocommerce-brands/woocommerce-brands.php',
383
+ apply_filters(
384
+ 'active_plugins',
385
+ get_option( 'active_plugins' )
386
+ )
387
+ ) ) {
388
+ array_push( $custom_fields, 'Brand' );
389
+ }
390
+
391
+ return $custom_fields;
392
+ }
393
+
394
+ /**
395
+ * Checks if other feeds than the active feed are still on processing status. If so, set these feeds to error
396
+ *
397
+ * @param string $active_feed_id
398
+ *
399
+ * @since 1.10.0
400
+ *
401
+ */
402
+ public function check_for_failed_feeds( $active_feed_id ) {
403
+ $processing_feeds = $this->_queries_class->get_feed_ids_with_specific_status( '3' );
404
+ $failed_feed_ids = '';
405
+
406
+ foreach ( $processing_feeds as $feed ) {
407
+ if ( $active_feed_id !== $feed->product_feed_id ) {
408
+ $this->update_feed_status( $feed->product_feed_id, 6 );
409
+ $failed_feed_ids .= ', ' . $feed->product_feed_id;
410
+ }
411
+ }
412
+
413
+ if ( $failed_feed_ids ) {
414
+ $message = sprintf( 'Starting the update of feed %s, the following feeds where still registered as being active: %s and are now set to the status FAIL.', $active_feed_id, $failed_feed_ids );
415
+ do_action( 'tvc_feed_generation_message', $active_feed_id, $message, 'ERROR' );
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Converts feed data items that are send through an ajax call to the corresponding database names.
421
+ *
422
+ * @param $feed_data
423
+ *
424
+ * @return array
425
+ * @since 2.5.0
426
+ *
427
+ */
428
+ public function convert_ajax_feed_data_to_database_format( $feed_data ) {
429
+ $result = array();
430
+
431
+ foreach ( $feed_data as $data_item ) {
432
+ if ( 'product_feed_id' !== $data_item->name ) {
433
+
434
+ if ( 'url' === $data_item->name ) {
435
+ $data_item->value = $this->verify_url( $data_item->value );
436
+ }
437
+
438
+ $result[ $data_item->name ] = $data_item->value;
439
+ }
440
+ }
441
+
442
+ return $result;
443
+ }
444
+
445
+ /**
446
+ * Gets the correct data types from the feed data and puts them into an array in the correct order.
447
+ *
448
+ * @param $feed_data
449
+ * @param $ajax_feed_data
450
+ *
451
+ * @return array
452
+ * @since 2.5.0
453
+ *
454
+ */
455
+ public function get_types_from_feed_data( $feed_data, $ajax_feed_data ) {
456
+ $result = array();
457
+
458
+ foreach ( $feed_data as $data_key => $value ) {
459
+ $feed_item = array_filter(
460
+ $ajax_feed_data,
461
+ function ( $item ) use ( $data_key ) {
462
+ return $item->name == $data_key;
463
+ }
464
+ );
465
+
466
+ array_push( $result, reset( $feed_item )->type );
467
+ }
468
+
469
+ return $result;
470
+ }
471
+
472
+ /**
473
+ * @param $feed_id
474
+ * @return bool|stdClass
475
+ */
476
+ public function get_feed_data( $feed_id ) {
477
+ // get the main data
478
+ $main_feed_data = $this->_queries_class->read_feed( $feed_id );
479
+ $main_data = $this->convert_data_to_feed_data( $main_feed_data[0] );
480
+
481
+ if ( false === $main_data ) {
482
+ return $main_data;
483
+ }
484
+
485
+ $main_data->attributes = array();
486
+
487
+ $channel = trim( $this->_queries_class->get_channel_short_name_from_db( $main_feed_data[0]['channel'] ) );
488
+ $is_custom = function_exists( 'tvc_channel_is_custom_channel' ) ? tvc_channel_is_custom_channel( $channel ) : false;
489
+
490
+ // read the output fields
491
+ if ( ! $is_custom ) {
492
+ $outputs = apply_filters( 'tvc_get_feed_attributes', $this->_files_class->get_output_fields_for_specific_channel( $channel ), $feed_id, $main_feed_data[0]['feed_type_id'] );
493
+ } else {
494
+ $outputs = $this->get_custom_fields_with_metadata( $feed_id );
495
+ }
496
+
497
+ // add meta data to the feeds output fields
498
+ $output_fields = $this->fill_output_fields_with_metadata( $feed_id, $outputs );
499
+ $inputs = $this->get_advised_inputs( $main_data->channel, $main_feed_data[0]['feed_type_id'] );
500
+
501
+ for ( $i = 0; $i < count( $output_fields ); $i ++ ) {
502
+ $output_title = $output_fields[ $i ]->field_label;
503
+ $is_active = false;
504
+
505
+ if ( $output_fields[ $i ]->category_id > 0 && $output_fields[ $i ]->category_id < 3 ) {
506
+ $is_active = true;
507
+ }
508
+ if ( ! empty( $output_fields[ $i ]->value ) && 'undefined' !== $output_fields[ $i ]->value ) {
509
+ $is_active = true;
510
+ }
511
+
512
+ $advised_source = property_exists( $inputs, $output_title ) ? $advised_source = $inputs->{$output_title} : '';
513
+ $this->add_attribute( $main_data->attributes, $i, $output_title, $advised_source, $output_fields[ $i ]->value, $output_fields[ $i ]->category_id, $is_active, 0, 0, 0 );
514
+ }
515
+
516
+ $this->set_output_attribute_levels( $main_data );
517
+
518
+ return $main_data;
519
+ }
520
+
521
+ /**
522
+ * @param $main_data
523
+ */
524
+ // ALERT has a relation with the tvc_setOutputAttributeLevels() function in the logic.js file
525
+ private function set_output_attribute_levels( &$main_data ) {
526
+ $channel_base_class = new TVC_Channel();
527
+ $channel_short_name = $channel_base_class->get_channel_short_name( $main_data->channel );
528
+
529
+ if ( class_exists( 'TVC_' . ucfirst( $channel_short_name ) . '_Feed_Class' ) ) {
530
+ $class_name = 'TVC_' . ucfirst( $channel_short_name ) . '_Feed_Class';
531
+ $feed_class = new $class_name();
532
+
533
+ if ( method_exists( $feed_class, 'set_feed_output_attribute_levels' ) ) {
534
+ $feed_class->set_feed_output_attribute_levels( $main_data );
535
+ }
536
+ }
537
+ }
538
+
539
+ /**
540
+ * @param $attribute
541
+ * @param $id
542
+ * @param $title
543
+ * @param $advised_source
544
+ * @param $value
545
+ * @param $field_level
546
+ * @param $is_active
547
+ * @param $nr_queries
548
+ * @param $nr_value_edits
549
+ * @param $nr_value_conditions
550
+ */
551
+ private function add_attribute(
552
+ &$attribute, $id, $title, $advised_source, $value, $field_level, $is_active,
553
+ $nr_queries, $nr_value_edits, $nr_value_conditions
554
+ ) {
555
+
556
+ $attribute_object = new stdClass();
557
+
558
+ $attribute_object->rowId = $id;
559
+ $attribute_object->fieldName = $title;
560
+ $attribute_object->advisedSource = $advised_source;
561
+ $attribute_object->value = $value;
562
+ $attribute_object->fieldLevel = $field_level;
563
+ $attribute_object->isActive = $is_active;
564
+ $attribute_object->nrQueries = $nr_queries;
565
+ $attribute_object->nrValueEdits = $nr_value_edits;
566
+ $attribute_object->nrValueConditions = $nr_value_conditions;
567
+
568
+ array_push( $attribute, $attribute_object );
569
+ }
570
+
571
+ /**
572
+ * @param $data
573
+ * @return bool|stdClass
574
+ */
575
+ private function convert_data_to_feed_data( $data ) {
576
+
577
+ if ( ! key_exists( 'product_feed_id', $data ) ) {
578
+ return false;
579
+ }
580
+
581
+ $feed = new stdClass();
582
+
583
+ $feed->feedId = $data['product_feed_id'];
584
+ $feed->title = $data['title'];
585
+ $feed->mainCategory = $data['main_category'];
586
+ $feed->categoryMapping = $data['category_mapping'];
587
+ $feed->isAggregator = $data['is_aggregator'];
588
+ $feed->includeVariations = $data['include_variations'];
589
+ $feed->feedTitle = $data['feed_title'] !== null ? $data['feed_title'] : '';
590
+ $feed->feedDescription = $data['feed_description'] !== null ? $data['feed_description'] : '';
591
+ $feed->url = $data['url'];
592
+ $feed->dataSource = $data['source'];
593
+ $feed->channel = $data['channel'];
594
+ $feed->country = $data['country'];
595
+ $feed->status = $data['status_id'];
596
+ $feed->baseStatusId = $data['base_status_id'];
597
+ $feed->feedTypeId = $data['feed_type_id'];
598
+ $feed->updateSchedule = $data['schedule'];
599
+ $feed->language = $data['language'] !== null ? $data['language'] : '';
600
+
601
+ return $feed;
602
+ }
603
+
604
+ /**
605
+ * @param $channel_id
606
+ * @param $feed_type_id
607
+ * @return mixed|void
608
+ */
609
+ // TVC_CHANNEL_RELATED
610
+ private function get_advised_inputs( $channel_id, $feed_type_id ) {
611
+ $feed_class = new TVC_Google_Feed_Class();
612
+ // as long as only WooCommerce is supported, I can get away with only switching on a specific channel
613
+ $advised_inputs = $feed_class->woocommerce_to_feed_fields();
614
+ return apply_filters( 'tvc_advised_inputs', $advised_inputs, $feed_type_id );
615
+ }
616
+
617
+ /**
618
+ * Makes sure that the url is correct and has no forbidden characters before it's being stored in the database
619
+ *
620
+ * @param $url string complete url
621
+ *
622
+ * @return string verified url
623
+ */
624
+ private function verify_url( $url ) {
625
+ $forbidden_name_chars = tvc_forbidden_file_name_characters();
626
+ $last_slash = strrpos( $url, '/' );
627
+ $url_string = substr( $url, 0, $last_slash + 1 );
628
+ $feed_name = substr( $url, $last_slash + 1 );
629
+ $correct_feed_name = str_replace( $forbidden_name_chars, '-', $feed_name );
630
+ return $url_string . $correct_feed_name;
631
+ }
632
+
633
+ /**
634
+ * @param $channel_short_name
635
+ * @param $channel_data
636
+ */
637
+ public function register_channel( $channel_short_name, $channel_data ) {
638
+ if ( ! $this->_queries_class->get_channel_id( $channel_short_name ) ) { // make sure the channel is not yet registered
639
+ $this->_queries_class->register_a_channel( $channel_short_name, $channel_data->channel_id, $channel_data->channel_name );
640
+ }
641
+ }
642
+
643
+ /**
644
+ * @param $attributes
645
+ * @param $feeds
646
+ * @param $product_attributes
647
+ * @param $product_taxonomies
648
+ * @param $third_party_fields
649
+ * @return mixed
650
+ */
651
+ private function combine_custom_attributes_and_feeds( $attributes, $feeds, $product_attributes, $product_taxonomies, $third_party_fields ) {
652
+ $prev_dup_array = array(); // used to prevent doubles
653
+
654
+ foreach ( $feeds as $feed ) {
655
+ $obj = new stdClass();
656
+
657
+ $obj->attribute_name = $feed;
658
+ $obj->attribute_label = $feed;
659
+
660
+ array_push( $attributes, $obj );
661
+ array_push( $prev_dup_array, $obj->attribute_label );
662
+ }
663
+
664
+ foreach ( $product_taxonomies as $taxonomy ) {
665
+ if ( ! in_array( $taxonomy, $prev_dup_array ) ) {
666
+ $obj = new stdClass();
667
+ $obj->attribute_name = $taxonomy;
668
+ $obj->attribute_label = $taxonomy;
669
+
670
+ array_push( $attributes, $obj );
671
+ array_push( $prev_dup_array, $taxonomy );
672
+ }
673
+ }
674
+
675
+ foreach ( $product_attributes as $attribute_string ) {
676
+ $attribute_object = maybe_unserialize( $attribute_string->meta_value );
677
+
678
+ if ( $attribute_object && ( is_object( $attribute_object ) || is_array( $attribute_object ) ) ) {
679
+ foreach ( $attribute_object as $attribute ) {
680
+ if ( ! in_array( $attribute['name'], $prev_dup_array ) ) {
681
+ $obj = new stdClass();
682
+ $obj->attribute_name = $attribute['name'];
683
+ $obj->attribute_label = $attribute['name'];
684
+
685
+ array_push( $attributes, $obj );
686
+ array_push( $prev_dup_array, $attribute['name'] );
687
+ }
688
+ }
689
+ } else {
690
+ if ( $attribute_object ) {
691
+ tvc_write_log_file( $attribute_object, 'debug' );
692
+ }
693
+ }
694
+ }
695
+
696
+ foreach ( $third_party_fields as $field_label ) {
697
+ if ( ! in_array( $field_label, $prev_dup_array ) ) {
698
+ $obj = new stdClass();
699
+ $obj->attribute_name = $field_label;
700
+ $obj->attribute_label = $field_label;
701
+
702
+ array_push( $attributes, $obj );
703
+ array_push( $prev_dup_array, $field_label );
704
+ }
705
+ }
706
+ return $attributes;
707
+ }
708
+ }
709
+ // end of TVC_Data_Class
710
+
711
+ endif;
712
+
713
+ $dataclass = new TVC_Data();
includes/data/class-tvc-db-management.php ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Db Management Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.9.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Db_Management' ) ) :
15
+
16
+ /**
17
+ * Db Management Class
18
+ */
19
+ class TVC_Db_Management {
20
+
21
+ public static function table_exists( $table_name ) {
22
+ global $wpdb;
23
+
24
+ if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->prefix . $table_name ) ) === $wpdb->prefix . $table_name ) {
25
+ return true;
26
+ } else {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Makes a duplicate of a selected feed and stores it in the database.
33
+ *
34
+ * @param string $feed_id Feed id of the feed that needs to be duplicated.
35
+ *
36
+ * @return boolean False if duplication process failed.
37
+ */
38
+ public static function duplicate_feed( $feed_id ) {
39
+ $queries_class = new TVC_Queries();
40
+ $support_class = new TVC_Feed_Support();
41
+
42
+ // Get the feed data.
43
+ $feed_data = $queries_class->get_feed_row( $feed_id );
44
+
45
+ // Get the meta data.
46
+ $meta_data = $queries_class->read_metadata( $feed_id );
47
+
48
+ // Get the Feed Filter data.
49
+ $feed_filter_data = $queries_class->get_product_filter_query( $feed_id );
50
+
51
+ // Get the category mapping.
52
+ $category_mapping = $queries_class->read_category_mapping( $feed_id );
53
+
54
+ // Generate a new unique feed name.
55
+ $feed_data->title = $support_class->next_unique_feed_name( $feed_data->title );
56
+ $feed_data->url = esc_html__( 'Feed needs to be generated first', 'tvc-product-feed-manager' );
57
+
58
+ $feed_data_to_store = array(
59
+ 'channel_id' => $feed_data->channel_id,
60
+ 'language' => $feed_data->language,
61
+ 'is_aggregator' => $feed_data->is_aggregator,
62
+ 'include_variations' => $feed_data->include_variations,
63
+ 'country_id' => $feed_data->country_id,
64
+ 'source_id' => $feed_data->source_id,
65
+ 'title' => $feed_data->title,
66
+ 'feed_title' => $feed_data->feed_title,
67
+ 'feed_description' => $feed_data->feed_description,
68
+ 'main_category' => $feed_data->main_category,
69
+ 'url' => $feed_data->url,
70
+ 'status_id' => $feed_data->status_id,
71
+ 'schedule' => $feed_data->schedule,
72
+ 'products' => 0,
73
+ 'feed_type_id' => $feed_data->feed_type_id,
74
+ 'aggregator_name' => $feed_data->aggregator_name,
75
+ 'publisher_name' => $feed_data->publisher_name,
76
+ 'publisher_favicon_url' => $feed_data->publisher_favicon_url,
77
+ );
78
+
79
+ $feed_data_types = array(
80
+ '%d',
81
+ '%s',
82
+ '%d',
83
+ '%d',
84
+ '%d',
85
+ '%d',
86
+ '%s',
87
+ '%s',
88
+ '%s',
89
+ '%s',
90
+ '%s',
91
+ '%d',
92
+ '%s',
93
+ '%d',
94
+ '%d',
95
+ '%s',
96
+ '%s',
97
+ '%s',
98
+ );
99
+
100
+ // Store a copy of the new feed in the database.
101
+ $new_feed_id = $queries_class->create_feed( $feed_data_to_store, $feed_data_types );
102
+
103
+ return $new_feed_id > 0 ? $queries_class->insert_meta_data( $new_feed_id, $meta_data, $feed_filter_data, $category_mapping ) : false;
104
+ }
105
+
106
+ /**
107
+ * Backups all plugin related data from the database to a file
108
+ *
109
+ * @since 1.7.2
110
+ *
111
+ * @param string $backup_file_name
112
+ *
113
+ * @return boolean
114
+ */
115
+ public static function backup_database_tables( $backup_file_name ) {
116
+ $backup_class = new TVC_Backup();
117
+ $file_class = new TVC_File();
118
+
119
+ $backup_file = TVC_BACKUP_DIR . '/' . $backup_file_name . '.sql';
120
+ $backup_path = str_replace( '\\', '/', $backup_file );
121
+
122
+ // prepare the folder structure to support saving backup files
123
+ if ( ! file_exists( TVC_BACKUP_DIR ) ) {
124
+ TVC_Folders::make_backup_folder();
125
+ }
126
+
127
+ if ( ! file_exists( $backup_path ) ) {
128
+ $backup_file_text = $backup_class->read_full_backup_data();
129
+
130
+ return $file_class->write_full_backup_file( $backup_path, $backup_file_text );
131
+ } else {
132
+ echo tvc_show_wp_warning( esc_html__( 'A backup file with the selected name already exists. Please choose an other name or delete the existing file first.', 'tvc-product-feed-manager' ) );
133
+
134
+ return false;
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Checks the existing backup files for non compliant versions
140
+ *
141
+ * @since 1.8.0
142
+ *
143
+ * @return boolean true if a non compliant backup file exists
144
+ */
145
+ public static function invalid_backup_exist() {
146
+ if ( ! file_exists( TVC_BACKUP_DIR ) ) {
147
+ return false;
148
+ }
149
+
150
+ $files = tvc_list_sql_files( TVC_BACKUP_DIR );
151
+
152
+ if ( count( $files ) === 0 ) {
153
+ return false;
154
+ }
155
+
156
+ foreach ( $files as $file ) {
157
+ $backup_string = file_get_contents( $file );
158
+
159
+ // get the db version
160
+ $backup_version_string = ltrim( substr( $backup_string, stripos( $backup_string, '#' ) ), '#' );
161
+ $backup_db_version = substr( $backup_version_string, 0, strpos( $backup_version_string, '#' ) );
162
+
163
+ if ( $backup_db_version < get_option( 'tvc_db_version' ) ) {
164
+ return true;
165
+ }
166
+ }
167
+
168
+ return false;
169
+ }
170
+
171
+ /**
172
+ * Restores the data from a backup file
173
+ *
174
+ * @since 1.7.2
175
+ *
176
+ * @param string name of the backup file
177
+ *
178
+ * @return boolean if restored successfully, string when not
179
+ */
180
+ public static function restore_backup( $backup_file_name ) {
181
+ $backup_class = new TVC_Backup();
182
+
183
+ $backup_file = TVC_BACKUP_DIR . '/' . $backup_file_name;
184
+ $backup_path = str_replace( '\\', '/', $backup_file );
185
+
186
+ $current_db_version = get_option( 'tvc_db_version' );
187
+
188
+ if ( file_exists( $backup_path ) ) {
189
+ $table_queries = array();
190
+ $backup_string = file_get_contents( $backup_file );
191
+
192
+ // remove the date string
193
+ $backup_string = substr( $backup_string, stripos( $backup_string, '#' ) );
194
+
195
+ // get the db version
196
+ $backup_db_version = ltrim( $backup_string, '#' );
197
+ $backup_db_version = substr( $backup_db_version, 0, strpos( $backup_db_version, '#' ) );
198
+
199
+ if ( $backup_db_version < $current_db_version ) {
200
+ return esc_html__( 'The backup file is of an older version of the database and can not be restored as it is not compatible with the current database.', 'tvc-product-feed-manager' );
201
+ }
202
+
203
+ // remove the version
204
+ $backup_string = self::remove_left_data_part( $backup_string );
205
+
206
+ // remove the ftp passive setting
207
+ $backup_string = self::remove_left_data_part( $backup_string );
208
+
209
+ // reset the auto feed fix setting
210
+ $auto_feed_fix_setting = ltrim( $backup_string, '#' );
211
+ $auto_feed_fix_setting = substr( $auto_feed_fix_setting, 1, strpos( $auto_feed_fix_setting, '#' ) );
212
+ update_option( 'tvc_auto_feed_fix', $auto_feed_fix_setting );
213
+
214
+ // remove the auto feed fix setting
215
+ $backup_string = self::remove_left_data_part( $backup_string );
216
+
217
+ // reset the disable background option
218
+ $disable_background_setting = ltrim( $backup_string, '#' );
219
+ $disable_background_setting = substr( $disable_background_setting, 1, strpos( $disable_background_setting, '#' ) );
220
+ update_option( 'tvc_disabled_background_mode', $disable_background_setting );
221
+
222
+ // remove the disable background option string
223
+ $backup_string = self::remove_left_data_part( $backup_string );
224
+
225
+ // reset the show product identifiers option string
226
+ $show_product_identifiers_setting = ltrim( $backup_string, '#' );
227
+ $show_product_identifiers_setting = substr( $show_product_identifiers_setting, 1, strpos( $show_product_identifiers_setting, '#' ) );
228
+ update_option( 'tvc_show_product_identifiers', $show_product_identifiers_setting );
229
+
230
+ // remove the show product identifiers option string
231
+ $backup_string = self::remove_left_data_part( $backup_string );
232
+
233
+ // split the string in table specific rows
234
+ $table_strings = explode( '# backup string for database -> ', $backup_string );
235
+
236
+ foreach ( $table_strings as $string ) {
237
+ $table_name = substr( $string, 0, stripos( $string, '#' ) );
238
+ $query_string = substr( $string, stripos( $string, '#' ), strlen( $string ) );
239
+ array_push( $table_queries, [ trim( $table_name ), ltrim( $query_string, '# <- # ' ) ] );
240
+ }
241
+
242
+ // remove the first (empty) element
243
+ array_shift( $table_queries );
244
+
245
+ return $backup_class->restore_backup_data( $table_queries );
246
+ } else {
247
+ return esc_html__( 'A backup file with the selected name does not exists.', 'tvc-product-feed-manager' );
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Deletes an existing backup file
253
+ *
254
+ * @since 1.7.2
255
+ *
256
+ * @param string name of the backup file to be deleted
257
+ */
258
+ public static function delete_backup_file( $backup_file_name ) {
259
+ $backup_file = TVC_BACKUP_DIR . '/' . $backup_file_name;
260
+
261
+ // only return results when the user is an admin with manage options
262
+ if ( is_admin() ) {
263
+ /* translators: %s: Selected backup file */
264
+ echo file_exists( $backup_file ) ? unlink( $backup_file ) : tvc_show_wp_error( sprintf( esc_html__( 'Could not find file %s.', 'tvc-product-feed-manager' ), $backup_file ) );
265
+ } else {
266
+ echo tvc_show_wp_error( esc_html__( 'Error deleting the feed. You do not have the correct authorities to delete the file.', 'tvc-product-feed-manager' ) );
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Duplicate an existing backup file
272
+ *
273
+ * @since 1.7.2
274
+ *
275
+ * @param string name of the backup file to be duplicated
276
+ */
277
+ public static function duplicate_backup_file( $backup_file_name ) {
278
+ $support_class = new TVC_Feed_Support();
279
+
280
+ $backup_file_name_without_extension = rtrim( $backup_file_name, '.sql' );
281
+ $new_backup_file_title = $support_class->next_unique_feed_name( $backup_file_name_without_extension );
282
+ $new_backup_file_name = $new_backup_file_title . '.sql';
283
+
284
+ if ( ! copy( TVC_BACKUP_DIR . '/' . $backup_file_name, TVC_BACKUP_DIR . '/' . $new_backup_file_name ) ) {
285
+ /* translators: %s: selected backup file name */
286
+ sprintf( esc_html__( 'Failed to make a copy of %s', 'tvc-product-feed-manager' ), $backup_file_name );
287
+ } else {
288
+ echo true;
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Clears several options that could hinder a new feed process.
294
+ */
295
+ public static function clean_options_table() {
296
+ // @since 2.10.0.
297
+ delete_option( 'tvc_processed_products' );
298
+
299
+ $queries_class = new TVC_Queries();
300
+ $queries_class->clear_feed_batch_options();
301
+ // also clear the multi site feed batch data
302
+ if ( is_multisite() ) {
303
+ $queries_class->clear_feed_batch_sitemeta();
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Resets the status_id's of failed feeds.
309
+ *
310
+ * @since 2.7.0
311
+ */
312
+ public static function reset_status_of_failed_feeds() {
313
+ $queries_class = new TVC_Queries();
314
+ $queries_class->reset_all_feed_status();
315
+ }
316
+
317
+ private static function remove_left_data_part( $data_string ) {
318
+ $ds = ltrim( $data_string, '#' );
319
+
320
+ return substr( $ds, stripos( $ds, '#' ) );
321
+ }
322
+ }
323
+
324
+
325
+ endif;
includes/data/class-tvc-feed-crud-handler.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Feed CRUD Handler class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.0.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Feed_CRUD_Handler' ) ) :
15
+
16
+ class TVC_Feed_CRUD_Handler {
17
+
18
+ /**
19
+ * @param $feed_data
20
+ * @param $meta_data_encoded
21
+ * @param $feed_filter
22
+ * @return int
23
+ */
24
+ public static function create_or_update_feed_data( $feed_data, $meta_data_encoded, $feed_filter ) {
25
+ $data_class = new TVC_Data();
26
+ $queries_class = new TVC_Queries();
27
+
28
+ $feed_id = self::get_feed_id_from_feed_data( $feed_data );
29
+
30
+ // convert the feed data to a database format
31
+ $feed_data_to_store = $data_class->convert_ajax_feed_data_to_database_format( $feed_data );
32
+ $feed_data_types = $data_class->get_types_from_feed_data( $feed_data_to_store, $feed_data );
33
+
34
+ // convert country code to country id
35
+ $feed_data_to_store['country_id'] = $data_class->get_country_id_from_short_code( $feed_data_to_store['country_id'] )->country_id;
36
+
37
+ self::add_fixed_data_fields( $feed_data_to_store, $feed_data_types, $feed_id );
38
+
39
+ // decode the meta data
40
+ $meta_data = json_decode( $meta_data_encoded );
41
+
42
+ // create or update the feed
43
+ if ( $feed_id < 0 ) {
44
+ $actual_feed_id = $queries_class->create_feed( $feed_data_to_store, $feed_data_types );
45
+ } else {
46
+ $update_result = $queries_class->update_feed( $feed_id, $feed_data_to_store, $feed_data_types );
47
+ $actual_feed_id = $update_result ? $feed_id : 0;
48
+ }
49
+
50
+ if ( count( $meta_data ) > 0 ) {
51
+ $queries_class->update_meta_data( $actual_feed_id, $meta_data );
52
+ }
53
+
54
+ $queries_class->store_feed_filter( $actual_feed_id, $feed_filter );
55
+
56
+ return $actual_feed_id;
57
+ }
58
+
59
+ /**
60
+ * @param $feed_data
61
+ * @return mixed
62
+ */
63
+ private static function get_feed_id_from_feed_data( $feed_data ) {
64
+ // use the array_filter to select the feed data element with product_feed_id as name
65
+ $feed_id_item = array_filter(
66
+ $feed_data,
67
+ function( $element ) {
68
+ return 'product_feed_id' === $element->name;
69
+ }
70
+ );
71
+ // return the feed id
72
+ return reset( $feed_id_item )->value;
73
+ }
74
+
75
+ /**
76
+ * @param $feed_data
77
+ * @param $data_types
78
+ * @param $feed_id
79
+ */
80
+ private static function add_fixed_data_fields( &$feed_data, &$data_types, $feed_id ) {
81
+ $feed_data['updated'] = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
82
+ if ( $feed_id < 0 ) {
83
+ $feed_data['products'] = 0; }
84
+ array_push( $data_types, '%s', '%d' );
85
+ }
86
+ }
87
+ // end of TVC_Feed_CRUD_Handler class
88
+ endif;
includes/data/class-tvc-file.php ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * TVC Product Feed File Class.
4
+ *
5
+ * @package TVC Product Feed Manager/Data/Classes
6
+ * @version 1.3.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ if ( ! class_exists( 'TVC_File' ) ) :
14
+
15
+ /**
16
+ * The File Class
17
+ */
18
+ class TVC_File {
19
+
20
+ private $_queries;
21
+
22
+ public function __construct() {
23
+ $this->_queries = new TVC_Queries();
24
+ }
25
+
26
+ /**
27
+ * Reads the correct categories from a channel specific taxonomy text file
28
+ *
29
+ * @param int $channel_id
30
+ * @param string $search_level
31
+ * @param string $parent_category
32
+ * @param string $language_code
33
+ *
34
+ * @return array|string containing the categories
35
+ */
36
+ public function get_categories_for_list( $channel_id, $search_level, $parent_category, $language_code ) {
37
+ $channel_class = new TVC_Channel();
38
+
39
+ $last_cat = '';
40
+ $categories = array();
41
+ $channel_name = $channel_class->get_channel_short_name( $channel_id );
42
+
43
+ $path = TVC_CHANNEL_DATA_DIR . "/$channel_name/taxonomy.$language_code.txt";
44
+
45
+ if ( file_exists( $path ) ) {
46
+ $file = fopen( $path, 'r' )
47
+ or die( esc_html__( 'Unable to open the file containing the categories', 'tvc-product-feed-manager' ) );
48
+
49
+ // step over the first lines that do not contain categories
50
+ while ( strpos( fgets( $file ), '#' ) ) {
51
+ continue;
52
+ }
53
+
54
+ // step through all the lines in the file
55
+ while ( ! feof( $file ) ) {
56
+ // get the line
57
+ $line = trim( fgets( $file ) );
58
+
59
+ // split the line into pieces using the > separator
60
+ $category_line_array = explode( '>', $line );
61
+
62
+ if ( 0 === $search_level ) {
63
+ if ( trim( $category_line_array [ $search_level ] ) !== $last_cat ) {
64
+ array_push( $categories, trim( $category_line_array [ $search_level ] ) );
65
+ $last_cat = trim( $category_line_array [ $search_level ] );
66
+ }
67
+ } elseif ( count( $category_line_array ) > $search_level && $search_level > 0 && trim( $category_line_array [ $search_level - 1 ] ) === trim( $parent_category ) ) {
68
+ if ( trim( $category_line_array [ $search_level ] ) !== $last_cat ) {
69
+ array_push( $categories, trim( $category_line_array [ $search_level ] ) );
70
+ $last_cat = trim( $category_line_array [ $search_level ] );
71
+ }
72
+ }
73
+ }
74
+
75
+ // don't forget to free the resources
76
+ fclose( $file );
77
+ }
78
+
79
+ return $categories;
80
+ }
81
+
82
+ public function get_output_fields_for_specific_channel( $channel ) {
83
+ $fields = array();
84
+
85
+ $path = TVC_CHANNEL_DATA_DIR . "/$channel/$channel.txt";
86
+
87
+ if ( file_exists( $path ) ) {
88
+ $file = fopen( $path, 'r' )
89
+ or die( esc_html__( 'Unable to open the file containing the categories', 'tvc-product-feed-manager' ) );
90
+
91
+ // step through all the lines in the file
92
+ while ( ! feof( $file ) ) {
93
+ $field_object = new stdClass();
94
+
95
+ // get the line
96
+ $line = fgetcsv( $file, 0, "\t" );
97
+
98
+ if ( is_array( $line ) && ! empty( $line[0] ) ) {
99
+ $field_object->field_id = $line[0];
100
+ $field_object->category_id = $line[1];
101
+ $field_object->field_label = $line[2];
102
+
103
+ array_push( $fields, $field_object );
104
+ }
105
+ }
106
+ }
107
+
108
+ return $fields;
109
+ }
110
+
111
+ /**
112
+ * Check the standard backup folder and return the .sql file names in it
113
+ *
114
+ * @return array
115
+ */
116
+ public function make_list_of_active_backups() {
117
+ $backups = array();
118
+
119
+ $path = TVC_BACKUP_DIR;
120
+
121
+ foreach ( glob( $path . '/*.sql' ) as $file ) {
122
+ $feed = fopen( $file, 'r' );
123
+ $line = fgets( $feed );
124
+ fclose( $feed );
125
+
126
+ $file_name = str_replace( TVC_BACKUP_DIR . '/', '', $file );
127
+ $date_string = strtok( $line, '#' );
128
+ $file_date = strlen( $date_string ) < 15 ? date( 'Y-m-d H:i:s', $date_string ) : 'unknown';
129
+
130
+ array_push( $backups, $file_name . '&&' . $file_date );
131
+ }
132
+
133
+ return $backups;
134
+ }
135
+
136
+ public function write_full_backup_file( $backup_file, $backup_string ) {
137
+ if ( is_writable( TVC_BACKUP_DIR ) ) {
138
+ $feed = fopen( $backup_file, 'w' );
139
+ } else {
140
+ /* translators: %s: Folder that holds the backup files */
141
+ return sprintf( esc_html__( '1432 - %s is not a writable folder. Make sure you have admin rights to this folder.', 'tvc-product-feed-manager' ), TVC_BACKUP_DIR );
142
+ }
143
+
144
+ if ( false !== $feed ) {
145
+ fwrite( $feed, $backup_string );
146
+ fclose( $feed );
147
+
148
+ return true;
149
+ } else {
150
+ /* translators: %s: Selected backup file */
151
+ return sprintf( esc_html__( '1433 - Could not write the %s file.', 'tvc-product-feed-manager' ), $backup_file );
152
+ }
153
+ }
154
+
155
+ public function get_installed_channels_from_file() {
156
+ $active_channels = array();
157
+
158
+ if ( file_exists( TVC_CHANNEL_DATA_DIR ) ) {
159
+ $dir_iterator = new RecursiveDirectoryIterator( TVC_CHANNEL_DATA_DIR );
160
+ $iterator = new RecursiveIteratorIterator( $dir_iterator, RecursiveIteratorIterator::SELF_FIRST );
161
+
162
+ foreach ( $iterator as $folder ) {
163
+ if ( $folder->isDir() && $folder->getFilename() !== '.' & $folder->getFilename() !== '..' ) {
164
+ array_push( $active_channels, $folder->getBaseName() );
165
+ }
166
+ }
167
+ }
168
+
169
+ return $active_channels;
170
+ }
171
+
172
+ /**
173
+ * Takes the installed channel .zip file and unzips it in the channels folder
174
+ *
175
+ * @param string $channel_name
176
+ *
177
+ * @return bool false if installing the channel failed
178
+ */
179
+ public function unzip_channel_file( $channel_name ) {
180
+ if ( ! file_exists( TVC_CHANNEL_DATA_DIR ) ) {
181
+ TVC_Folders::make_channels_support_folder();
182
+ }
183
+
184
+ WP_Filesystem();
185
+
186
+ $zip_file = TVC_CHANNEL_DATA_DIR . '/' . $channel_name . '.zip';
187
+ $destination_path = TVC_CHANNEL_DATA_DIR . '/';
188
+
189
+ if ( ! file_exists( $zip_file ) ) {
190
+ tvc_write_log_file( sprintf( 'Failed installing the Channel %s. Could not download the .zip file from the server.', $channel_name ) );
191
+
192
+ return false;
193
+ }
194
+
195
+ $unzip_result = unzip_file( $zip_file, $destination_path );
196
+
197
+ if ( is_wp_error( $unzip_result ) ) {
198
+ tvc_handle_wp_errors_response( $unzip_result, sprintf( 'The installation of channel %s failed. Unable to unpack the channel file in folder %s.', $channel_name, TVC_CHANNEL_DATA_DIR ) );
199
+ }
200
+
201
+ unlink( $zip_file ); // clean up the zip file
202
+
203
+ return true;
204
+ }
205
+
206
+ /**
207
+ * @param $channel_short_name
208
+ */
209
+ public function delete_channel_source_files( $channel_short_name ) {
210
+ $channel_folder = TVC_CHANNEL_DATA_DIR . '/' . $channel_short_name;
211
+
212
+ if ( file_exists( $channel_folder ) && is_dir( $channel_folder ) ) {
213
+ // remove the channel definition files
214
+ TVC_Folders::delete_folder( $channel_folder );
215
+ }
216
+
217
+ if ( 'google' === $channel_short_name ) {
218
+ $free_version_google_folder = ENHANCAD_PLUGIN_DIR . 'includes/application/google';
219
+
220
+ if ( file_exists( $free_version_google_folder ) && is_dir( $free_version_google_folder ) ) {
221
+ TVC_Folders::delete_folder( $free_version_google_folder );
222
+ }
223
+ }
224
+ }
225
+
226
+ /**
227
+ * @param $channel_id
228
+ */
229
+ public function delete_channel_feed_files( $channel_id ) {
230
+ $feeds = $this->_queries->get_feeds_from_specific_channel( $channel_id );
231
+
232
+ foreach ( $feeds as $feed_id ) {
233
+ $file_url = $this->_queries->get_file_url_from_feed( $feed_id['product_feed_id'] );
234
+ $file_name = basename( $file_url );
235
+ $file_path = TVC_FEEDS_DIR . '/' . $file_name;
236
+
237
+ if ( file_exists( $file_path ) ) {
238
+ unlink( $file_path );
239
+ }
240
+ }
241
+ }
242
+ }
243
+
244
+ // end of TVC_File_Class
245
+
246
+ endif;
includes/data/class-tvc-queries.php ADDED
@@ -0,0 +1,970 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Queries Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 4.11.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Queries' ) ) :
15
+
16
+ /**
17
+ * WP Queries Class
18
+ */
19
+ class TVC_Queries {
20
+
21
+ private $_wpdb;
22
+
23
+ /**
24
+ * @var string placeholder containing the wp table prefix
25
+ */
26
+ private $_table_prefix;
27
+
28
+ /**
29
+ * TVC_Queries Constructor
30
+ */
31
+ public function __construct() {
32
+ // get global WordPress database functions
33
+ global $wpdb;
34
+
35
+ // assign the global wpdb to a variable
36
+ $this->_wpdb = &$wpdb;
37
+
38
+ // assign the wp table prefix to a variable
39
+ $this->_table_prefix = $this->_wpdb->prefix;
40
+ }
41
+
42
+ public function get_feeds_list() {
43
+ // filter out all non product feeds when no special feed add-on plugin is active
44
+ $feed_type_filter = ! apply_filters( 'tvc_special_feeds_add_on_active', false ) ? " WHERE p.feed_type_id = '1'" : '';
45
+
46
+ return $this->_wpdb->get_results(
47
+ "SELECT p.product_feed_id, p.title, p.url, p.updated, p.feed_type_id, p.products, s.status AS status, s.color AS color FROM {$this->_table_prefix}feedmanager_product_feed AS p
48
+ INNER JOIN {$this->_table_prefix}feedmanager_feed_status AS s on p.status_id = s.status_id{$feed_type_filter}"
49
+ );
50
+ }
51
+
52
+ public function get_all_feed_names() {
53
+ return $this->_wpdb->get_results( "SELECT title FROM {$this->_table_prefix}feedmanager_product_feed" );
54
+ }
55
+
56
+ public function get_feed_row( $feed_id ) {
57
+ return $this->_wpdb->get_row( "SELECT * FROM {$this->_table_prefix}feedmanager_product_feed WHERE product_feed_id = {$feed_id}" );
58
+ }
59
+
60
+ /**
61
+ * Get a list of all existing countries
62
+ *
63
+ * @return array|object|null of the query
64
+ */
65
+ public function read_countries() {
66
+ return $this->_wpdb->get_results( "SELECT name_short, name FROM {$this->_table_prefix}feedmanager_country ORDER BY name", ARRAY_A );
67
+ }
68
+
69
+ public function get_feedmanager_channel_table() {
70
+ return $this->_wpdb->get_results( "SELECT * FROM {$this->_table_prefix}feedmanager_channel", ARRAY_A );
71
+ }
72
+
73
+ public function get_feedmanager_product_feed_table() {
74
+ return $this->_wpdb->get_results( "SELECT * FROM {$this->_table_prefix}feedmanager_product_feed", ARRAY_A );
75
+ }
76
+
77
+ public function get_feedmanager_product_feedmeta_table() {
78
+ return $this->_wpdb->get_results( "SELECT * FROM {$this->_table_prefix}feedmanager_product_feedmeta", ARRAY_A );
79
+ }
80
+
81
+ public function get_feed_type_id( $feed_id ) {
82
+ return $this->_wpdb->get_var( "SELECT feed_type_id FROM {$this->_table_prefix}feedmanager_product_feed WHERE product_feed_id = '{$feed_id}'" );
83
+ }
84
+
85
+ public function read_channels() {
86
+ $google = array( 'channel_id' => '1', 'name' => 'Google Merchant Centre', 'short' => 'google' );
87
+ return array( $google );
88
+ }
89
+ public function get_set_merchant_id(){
90
+ return $this->_wpdb->get_var( "SELECT * FROM {$this->_table_prefix}feedmanager_default_center WHERE status = 1" );
91
+ }
92
+
93
+ public function get_merchant_info(){
94
+ return $this->_wpdb->get_row( "SELECT * FROM {$this->_table_prefix}feedmanager_default_center WHERE status = 1");
95
+ }
96
+
97
+ public function get_set_ads_account_id($merchantId = ''){
98
+ if($merchantId == '') {
99
+ return $this->_wpdb->get_var( "SELECT * FROM {$this->_table_prefix}adsmanager_default_center WHERE status = 1" );
100
+ } else {
101
+ return $this->_wpdb->get_var( "SELECT * FROM {$this->_table_prefix}adsmanager_default_center WHERE status = 1 AND merchant_id = {$merchantId}" );
102
+ }
103
+
104
+ }
105
+
106
+ public function get_merchant_center_linked_flag($adsId = '') {
107
+ return $this->_wpdb->get_row( "SELECT * FROM {$this->_table_prefix}adsmanager_default_center WHERE status = 1 AND merchant_center_linked = 1 AND account_id = {$adsId}" );
108
+ }
109
+
110
+ public function get_claim(){
111
+ return $this->_wpdb->get_var( "SELECT * FROM {$this->_table_prefix}feedmanager_default_center WHERE claim = 1" );
112
+ }
113
+
114
+ /**
115
+ * @param $channel_short_name
116
+ * @param $channel_id
117
+ * @param $channel_name
118
+ * @return bool|int
119
+ */
120
+ public function register_a_channel( $channel_short_name, $channel_id, $channel_name ) {
121
+ return $this->_wpdb->query(
122
+ $this->_wpdb->prepare(
123
+ "INSERT INTO {$this->_table_prefix}feedmanager_channel (channel_id, name, short) VALUES
124
+ ( %d, '%s', '%s' )",
125
+ $channel_id,
126
+ $channel_name,
127
+ $channel_short_name
128
+ )
129
+ );
130
+ }
131
+
132
+ /**
133
+ * @param $channel_short_name
134
+ * @return string|null
135
+ */
136
+ public function get_channel_id( $channel_short_name ) {
137
+ return $this->_wpdb->get_var( "SELECT channel_id FROM {$this->_table_prefix}feedmanager_channel WHERE short = '{$channel_short_name}'" );
138
+ }
139
+
140
+ /**
141
+ * @param $channel_id
142
+ * @return bool|string|null
143
+ */
144
+ public function get_channel_short_name_from_db( $channel_id ) {
145
+ if ( 'undefined' !== $channel_id ) { // make sure the selected channel is installed
146
+ return $this->_wpdb->get_var( "SELECT short FROM {$this->_table_prefix}feedmanager_channel WHERE channel_id = {$channel_id}" );
147
+ } else {
148
+ return false;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * @param $channel_short
154
+ * @return false|int
155
+ */
156
+ public function remove_channel_from_db( $channel_short ) {
157
+ $main_table = $this->_table_prefix . 'feedmanager_channel';
158
+
159
+ return $this->_wpdb->delete( $main_table, array( 'short' => $channel_short ) );
160
+ }
161
+
162
+ /**
163
+ * @return bool|int
164
+ */
165
+ public function clean_channel_table() {
166
+ return $this->_wpdb->query(
167
+ $this->_wpdb->prepare(
168
+ "DELETE FROM {$this->_table_prefix}feedmanager_channel WHERE channel_id = %d OR name = %s",
169
+ 0,
170
+ ''
171
+ )
172
+ );
173
+ }
174
+
175
+ public function read_active_schedule_data() {
176
+ return $this->_wpdb->get_results( "SELECT product_feed_id, updated, schedule FROM {$this->_table_prefix}feedmanager_product_feed WHERE status_id=1", ARRAY_A );
177
+ }
178
+
179
+ public function read_failed_feeds() {
180
+ return $this->_wpdb->get_results( "SELECT product_feed_id, updated, schedule FROM {$this->_table_prefix}feedmanager_product_feed WHERE status_id=5 OR status_id=6", ARRAY_A );
181
+ }
182
+
183
+ public function read_sources() {
184
+ return $this->_wpdb->get_results( "SELECT source_id, name FROM {$this->_table_prefix}feedmanager_source ORDER BY name", ARRAY_A );
185
+ }
186
+
187
+ public function get_feeds_from_specific_channel( $channel_id ) {
188
+ return $this->_wpdb->get_results( "SELECT product_feed_id FROM {$this->_table_prefix}feedmanager_product_feed WHERE channel_id = {$channel_id}", ARRAY_A );
189
+ }
190
+
191
+ /**
192
+ * @param $feed_id
193
+ * @return array|object|null
194
+ */
195
+ public function get_meta_parents( $feed_id ) {
196
+ return $this->_wpdb->get_results( "SELECT ID FROM {$this->_table_prefix}posts WHERE post_parent = {$feed_id}", ARRAY_A );
197
+ }
198
+
199
+ /**
200
+ * @param $feed_id
201
+ * @return array|object|null
202
+ */
203
+ public function read_feed( $feed_id ) {
204
+ $result = $this->_wpdb->get_results(
205
+ "SELECT p.product_feed_id, p.source_id AS source, p.title, p.feed_title, p.feed_description, p.main_category, "
206
+ . "p.url, p.include_variations, p.is_aggregator, p.status_id, p.base_status_id, p.updated, p.products, p.feed_type_id, p.schedule, c.name_short "
207
+ . "AS country, m.channel_id AS channel, p.language "
208
+ . "FROM {$this->_table_prefix}feedmanager_product_feed AS p "
209
+ . "INNER JOIN {$this->_table_prefix}feedmanager_country AS c ON p.country_id = c.country_id "
210
+ . "INNER JOIN {$this->_table_prefix}feedmanager_channel AS m ON p.channel_id = m.channel_id "
211
+ . "WHERE p.product_feed_id = {$feed_id}",
212
+ ARRAY_A
213
+ );
214
+
215
+ $category_mapping = $this->read_category_mapping( $feed_id );
216
+
217
+ if ( isset( $category_mapping[0]['meta_value'] ) && $category_mapping[0]['meta_value'] !== '' ) {
218
+ $result[0]['category_mapping'] = $category_mapping[0]['meta_value'];
219
+ } else {
220
+ $result[0]['category_mapping'] = '';
221
+ }
222
+
223
+ return $result;
224
+ }
225
+
226
+ /**
227
+ * @param $feed_id
228
+ * @return array|object|null
229
+ */
230
+ public function read_category_mapping( $feed_id ) {
231
+ return $this->_wpdb->get_results( "SELECT meta_value FROM {$this->_table_prefix}feedmanager_product_feedmeta WHERE product_feed_id = {$feed_id} AND meta_key = 'category_mapping'", ARRAY_A );
232
+ }
233
+
234
+ /**
235
+ * @param $feed_id
236
+ * @return |null
237
+ */
238
+ public function get_feed_status_data( $feed_id ) {
239
+ $status = $this->_wpdb->get_results(
240
+ "SELECT product_feed_id, channel_id, title, url, status_id, products, feed_type_id "
241
+ . "FROM {$this->_table_prefix}feedmanager_product_feed "
242
+ . "WHERE product_feed_id = '{$feed_id}'",
243
+ ARRAY_A
244
+ );
245
+
246
+ return $status ? $status[0] : null;
247
+ }
248
+
249
+ /**
250
+ * Returns the post ids that belong to the selected categories
251
+ *
252
+ * @param string $category_string A string that contains the selected categories.
253
+ * @param bool $with_variation True if product variations should be included in the feed. Default false.
254
+ *
255
+ * @return array
256
+ */
257
+ public function get_post_ids( $category_string, $with_variation = false ) {
258
+ // If the user has not selected a category, return an empty array.
259
+ if ( empty( $category_string ) ) {
260
+ return array();
261
+ }
262
+
263
+ $start_product_id = get_transient( 'tvc_start_product_id' ) ? get_transient( 'tvc_start_product_id' ) : -1;
264
+
265
+ // Limit the number of products per query to 1000 to prevent a result that is to large to handle by the server.
266
+ // When the limit is reached a next batch will be requested by the fill_the_background_queue function.
267
+ // @since 2.11.0
268
+ $product_query_limit = apply_filters( 'tvc_product_query_limit', 1000 );
269
+
270
+ $products_query = "SELECT DISTINCT {$this->_table_prefix}posts.ID
271
+ FROM {$this->_table_prefix}posts
272
+ LEFT JOIN {$this->_table_prefix}term_relationships ON ({$this->_table_prefix}posts.ID = {$this->_table_prefix}term_relationships.object_id)
273
+ LEFT JOIN {$this->_table_prefix}term_taxonomy ON ({$this->_table_prefix}term_relationships.term_taxonomy_id = {$this->_table_prefix}term_taxonomy.term_taxonomy_id)
274
+ WHERE {$this->_table_prefix}posts.post_type = 'product' AND {$this->_table_prefix}posts.post_status = 'publish'
275
+ AND {$this->_table_prefix}term_taxonomy.term_id IN ($category_string)
276
+ AND {$this->_table_prefix}posts.ID > $start_product_id
277
+ ORDER BY ID LIMIT $product_query_limit";
278
+
279
+ // Get all main product ids (simple and variable, but not the variations).
280
+ $main_products_ids = $this->_wpdb->get_col( $products_query );
281
+
282
+ set_transient( 'tvc_start_product_id', end( $main_products_ids ), TVC_TRANSIENT_LIVE );
283
+
284
+ // if variations should not be included return the main product ids
285
+ if ( ! $with_variation || empty( $main_products_ids ) ) {
286
+ return $main_products_ids;
287
+ }
288
+
289
+ // Put the main ids in a string so it can be attached to a query string.
290
+ $main_products_ids_string = implode( ', ', $main_products_ids );
291
+
292
+ $variation_products_query = "SELECT DISTINCT post_parent FROM {$this->_table_prefix}posts
293
+ WHERE {$this->_table_prefix}posts.post_parent IN ( {$main_products_ids_string} )
294
+ AND {$this->_table_prefix}posts.post_type = 'product_variation'
295
+ AND {$this->_table_prefix}posts.post_status = 'publish'
296
+ ORDER BY ID";
297
+
298
+ // Get the ids of the variable products.
299
+ $variation_products = $this->_wpdb->get_col( $variation_products_query );
300
+
301
+ // If there are no variations, return the main product ids.
302
+ if ( count( $variation_products ) < 1 ) {
303
+ return $main_products_ids;
304
+ }
305
+
306
+ $variation_products_ids_string = implode( ', ', $variation_products );
307
+
308
+ // Remove the main product ids of products that have a valid variable version from the list to keep only the ids of the simple products.
309
+ $simple_products_ids = array_diff( $main_products_ids, $variation_products );
310
+
311
+ $product_variations_query = "SELECT DISTINCT ID FROM {$this->_table_prefix}posts
312
+ WHERE {$this->_table_prefix}posts.post_parent IN ( {$variation_products_ids_string} )
313
+ AND {$this->_table_prefix}posts.post_type = 'product_variation'
314
+ AND {$this->_table_prefix}posts.post_status = 'publish'
315
+ ORDER BY ID";
316
+
317
+ // Now get the variations.
318
+ $product_variations_ids = $this->_wpdb->get_col( $product_variations_query );
319
+
320
+ // Combine the variable product ids with the remaining simple product ids.
321
+ $all_product_ids = array_merge( $simple_products_ids, $product_variations_ids );
322
+ asort( $all_product_ids );
323
+
324
+ return $all_product_ids;
325
+ }
326
+
327
+ /**
328
+ * Gets the required data from the main
329
+ *
330
+ * @param string $post_id
331
+ * @param string $column_string
332
+ *
333
+ * @return array|object|null
334
+ */
335
+ public function read_post_data( $post_id, $column_string ) {
336
+ $selecting_columns = $column_string ? ', ' . $column_string : '';
337
+
338
+ $result = $this->_wpdb->get_results(
339
+ "SELECT DISTINCT ID $selecting_columns
340
+ FROM {$this->_table_prefix}posts
341
+ WHERE ID = $post_id"
342
+ );
343
+
344
+ return $result ? $result[0] : null;
345
+ }
346
+
347
+ /**
348
+ * returns the lowest product id belonging to one or more categories
349
+ *
350
+ * @param string $category_string
351
+ *
352
+ * @return string
353
+ */
354
+ public function get_lowest_product_id( $category_string ) {
355
+ $main_table = $this->_table_prefix . 'posts';
356
+ $term_relationships_table = $this->_table_prefix . 'term_relationships';
357
+ $term_taxonomy_table = $this->_table_prefix . 'term_taxonomy';
358
+
359
+ $result = $this->_wpdb->get_results(
360
+ "SELECT MIN(ID) FROM $main_table
361
+ LEFT JOIN $term_relationships_table ON ($main_table.ID = $term_relationships_table.object_id)
362
+ LEFT JOIN $term_taxonomy_table ON ($term_relationships_table.term_taxonomy_id = $term_taxonomy_table.term_taxonomy_id)
363
+ WHERE $main_table.post_type = 'product' AND $main_table.post_status = 'publish'
364
+ AND $term_taxonomy_table.term_id IN ($category_string)",
365
+ ARRAY_A
366
+ );
367
+
368
+ return $result ? $result[0]['MIN(ID)'] : 0;
369
+ }
370
+
371
+
372
+ /**
373
+ * returns the highest product id belonging to one or more categories
374
+ *
375
+ * @param string $category_string
376
+ *
377
+ * @return string
378
+ */
379
+ public function get_highest_product_id( $category_string ) {
380
+ $main_table = $this->_table_prefix . 'posts';
381
+ $term_relationships_table = $this->_table_prefix . 'term_relationships';
382
+ $term_taxonomy_table = $this->_table_prefix . 'term_taxonomy';
383
+
384
+ $result = $this->_wpdb->get_results(
385
+ "SELECT MAX(ID) FROM $main_table
386
+ LEFT JOIN $term_relationships_table ON ($main_table.ID = $term_relationships_table.object_id)
387
+ LEFT JOIN $term_taxonomy_table ON ($term_relationships_table.term_taxonomy_id = $term_taxonomy_table.term_taxonomy_id)
388
+ WHERE $main_table.post_type = 'product' AND $main_table.post_status = 'publish'
389
+ AND $term_taxonomy_table.term_id IN ($category_string)",
390
+ ARRAY_A
391
+ );
392
+
393
+ return $result ? $result[0]['MAX(ID)'] : 0;
394
+ }
395
+
396
+ /**
397
+ * @param $product_id
398
+ * @param $parent_product_id
399
+ * @param $record_ids
400
+ * @param $meta_columns
401
+ * @return array
402
+ */
403
+ public function read_meta_data( $product_id, $parent_product_id, $record_ids, $meta_columns ) {
404
+ $data = array();
405
+
406
+ foreach ( $meta_columns as $column ) {
407
+ $taxonomy = get_taxonomy( $column );
408
+
409
+ if ( $taxonomy ) {
410
+
411
+ $taxonomy_value = TVC_Taxonomies::make_shop_taxonomies_string( $product_id, $taxonomy->name, ', ' );
412
+
413
+ if ( ! $taxonomy_value ) {
414
+ $taxonomy_value = TVC_Taxonomies::make_shop_taxonomies_string( $parent_product_id, $taxonomy->name, ', ' );
415
+ }
416
+
417
+ if ( $taxonomy_value ) {
418
+ array_push( $data, $this->make_meta_object( $column, $taxonomy_value, $product_id ) );
419
+ }
420
+ }
421
+
422
+ foreach ( $record_ids as $rec_id ) {
423
+ $value = get_post_meta( $rec_id, $column, true );
424
+
425
+ if ( $value || '0' === $value ) {
426
+ array_push( $data, $this->make_meta_object( $column, $value, $rec_id ) );
427
+ break;
428
+ } else {
429
+ $alt_val = maybe_unserialize( get_post_meta( $rec_id, '_product_attributes', true ) );
430
+ $col_name = str_replace( ' ', '-', strtolower( $column ) );
431
+ if ( $alt_val && isset( $alt_val[ $col_name ] ) ) {
432
+ array_push( $data, $this->make_meta_object( $column, $alt_val[ $col_name ]['value'], $rec_id ) );
433
+ } elseif ( $alt_val && is_array( $alt_val ) ) {
434
+ foreach ( $alt_val as $v ) {
435
+ if ( $v['name'] === $column ) {
436
+ array_push( $data, $this->make_meta_object( $column, $v['value'], $rec_id ) );
437
+ }
438
+ }
439
+ }
440
+ }
441
+ }
442
+ }
443
+
444
+ $this->polish_data( $data, $product_id );
445
+
446
+ return $data;
447
+ }
448
+
449
+ /**
450
+ * @param $key
451
+ * @param $value
452
+ * @param $id
453
+ * @return stdClass
454
+ */
455
+ private function make_meta_object( $key, $value, $id ) {
456
+ $obj = new stdClass();
457
+ $obj->meta_key = $key;
458
+ $obj->meta_value = $value;
459
+ $obj->post_id = $id;
460
+
461
+ return $obj;
462
+ }
463
+
464
+ /**
465
+ * @param $data
466
+ * @param $main_post_id
467
+ */
468
+ private function polish_data( &$data, $main_post_id ) {
469
+ $site_url = get_option( 'siteurl' );
470
+
471
+ foreach ( $data as $row ) {
472
+ // make sure the _wp_attached_file data contains a valid url
473
+ if ( '_wp_attached_file' === $row->meta_key ) {
474
+ $row->meta_value = $this->get_post_thumbnail_url( $main_post_id, 'large' );
475
+
476
+ // if the _wp_attached_file data is not a valid url than add the url data
477
+ if ( ! filter_var( $row->meta_value, FILTER_VALIDATE_URL ) ) {
478
+ $row->meta_value = $site_url . '/wp-content/uploads/' . $row->meta_value;
479
+ }
480
+ }
481
+
482
+ // convert the time stamp format to a usable date time format for the feed
483
+ if ( '_sale_price_dates_from' === $row->meta_key || '_sale_price_dates_to' === $row->meta_key ) {
484
+ $row->meta_value = tvc_convert_price_date_to_feed_format( $row->meta_value );
485
+ }
486
+ }
487
+ }
488
+
489
+ /**
490
+ * @param $feed_id
491
+ * @return false|int
492
+ */
493
+ public function delete_feed( $feed_id ) {
494
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
495
+
496
+ return $this->_wpdb->delete( $main_table, array( 'product_feed_id' => $feed_id ) );
497
+ }
498
+
499
+ /**
500
+ * @param $feed_id
501
+ * @return false|int
502
+ */
503
+ public function delete_meta( $feed_id ) {
504
+ $main_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
505
+
506
+ return $this->_wpdb->delete( $main_table, array( 'product_feed_id' => $feed_id ) );
507
+ }
508
+
509
+ /**
510
+ * Gets the meta data from a specific feed. It does not include the category mapping and feed filter data.
511
+ *
512
+ * @param string $feed_id
513
+ *
514
+ * @return array|bool|object|null
515
+ */
516
+ public function read_metadata( $feed_id ) {
517
+ if ( $feed_id ) {
518
+ $main_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
519
+
520
+ return $this->_wpdb->get_results( "SELECT * FROM $main_table WHERE product_feed_id = $feed_id AND meta_key != 'category_mapping' AND meta_key != 'product_filter_query' ORDER BY meta_id", ARRAY_A );
521
+ } else {
522
+ return false;
523
+ }
524
+ }
525
+
526
+ /**
527
+ * Fetches the Feed Filter data from a specific feed.
528
+ *
529
+ * @param string $feed_id
530
+ *
531
+ * @return array|bool|object|null
532
+ */
533
+ public function get_product_filter_query( $feed_id ) {
534
+ if ( $feed_id ) {
535
+ $main_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
536
+
537
+ return $this->_wpdb->get_results( "SELECT meta_value FROM $main_table WHERE product_feed_id = $feed_id AND meta_key = 'product_filter_query'", ARRAY_A );
538
+ } else {
539
+ tvc_write_log_file( sprintf( 'Function get_filter_query returned false on feed %s', $feed_id ) );
540
+
541
+ return false;
542
+ }
543
+ }
544
+
545
+ public function get_columns_from_post_table() {
546
+ return $this->_wpdb->get_results( "SHOW COLUMNS FROM {$this->_table_prefix}posts" );
547
+ }
548
+
549
+ public function get_custom_product_attributes() {
550
+ $main_table = $this->_table_prefix . 'woocommerce_attribute_taxonomies';
551
+
552
+ return $this->_wpdb->get_results( "SELECT attribute_name, attribute_label FROM $main_table" );
553
+ }
554
+
555
+ public function get_custom_product_fields() {
556
+ $keywords_array = explode( ',', get_option( 'tvc_third_party_attribute_keywords', '%wpmr%,%cpf%,%unit%,%bto%,%yoast%' ) );
557
+ $main_table = $this->_wpdb->postmeta;
558
+
559
+ $query_string = "SELECT DISTINCT meta_key FROM $main_table WHERE meta_key NOT BETWEEN '_' AND '_z'";
560
+
561
+ foreach ( $keywords_array as $keyword ) {
562
+ $query_string .= " OR meta_key LIKE '" . trim( $keyword ) . "'";
563
+ }
564
+
565
+ $query_string .= ' ORDER BY meta_key';
566
+
567
+ return $this->_wpdb->get_col( $query_string );
568
+ }
569
+
570
+ public function clear_feed_batch_options() {
571
+ $this->_wpdb->query( "DELETE FROM {$this->_wpdb->options} WHERE option_name LIKE '%_batch_%'" );
572
+ }
573
+
574
+ /**
575
+ * @since 2.0.11
576
+ */
577
+ public function clear_feed_batch_sitemeta() {
578
+ $this->_wpdb->query( "DELETE FROM {$this->_wpdb->sitemeta} WHERE meta_key LIKE '%_batch_%'" );
579
+ }
580
+
581
+ public function get_own_variable_product_attributes( $variable_id ) {
582
+ $keywords = get_option( 'tvc_third_party_attribute_keywords', '%wpmr%,%cpf%,%unit%,%bto%,%yoast%' );
583
+ $wpmr_attributes = array();
584
+
585
+ if ( $keywords ) {
586
+ $keywords_array = explode( ',', $keywords );
587
+ $main_table = $this->_wpdb->postmeta;
588
+ $query_where_string = count( $keywords_array ) > 0 ? "WHERE (meta_key LIKE '" . trim( $keywords_array[0] ) . "'" : '';
589
+
590
+ for ( $i = 1; $i < count( $keywords_array ); $i ++ ) {
591
+ $query_where_string .= " OR meta_key LIKE '" . trim( $keywords_array[ $i ] ) . "'";
592
+ }
593
+
594
+ $query_where_string .= count( $keywords_array ) > 0 ? ') AND ' : '';
595
+
596
+ foreach ( $this->_wpdb->get_results( "SELECT meta_key, meta_value FROM $main_table $query_where_string (post_id = $variable_id)" ) as $key => $row ) {
597
+ $wpmr_attributes[ $row->meta_key ] = $row->meta_value;
598
+ }
599
+ }
600
+
601
+ return $wpmr_attributes;
602
+ }
603
+
604
+ public function get_all_product_attributes() {
605
+ $main_table = $this->_wpdb->postmeta;
606
+
607
+ return $this->_wpdb->get_results( "SELECT DISTINCT meta_value FROM $main_table WHERE meta_key = '_product_attributes'" );
608
+ }
609
+
610
+ public function get_current_feed_status( $feed_id ) {
611
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
612
+
613
+ return $this->_wpdb->get_results( "SELECT status_id FROM $main_table WHERE product_feed_id = $feed_id" );
614
+ }
615
+
616
+ public function get_country_id( $country_code ) {
617
+ $main_table = $this->_table_prefix . 'feedmanager_country';
618
+
619
+ return $this->_wpdb->get_row( "SELECT country_id FROM $main_table WHERE name_short = '$country_code'" );
620
+ }
621
+
622
+ public function get_feed_ids_with_specific_status( $status_id ) {
623
+ return $this->_wpdb->get_results( "SELECT product_feed_id FROM {$this->_table_prefix}feedmanager_product_feed WHERE status_id = '$status_id'" );
624
+ }
625
+
626
+ public function switch_feed_status( $feed_id, $new_status ) {
627
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
628
+
629
+ return $this->_wpdb->update(
630
+ $main_table,
631
+ array(
632
+ 'status_id' => $new_status,
633
+ 'base_status_id' => $new_status,
634
+ ),
635
+ array( 'product_feed_id' => $feed_id )
636
+ );
637
+ }
638
+
639
+ public function set_nr_feed_products( $feed_id, $nr_products ) {
640
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
641
+
642
+ return $this->_wpdb->update( $main_table, array( 'products' => $nr_products ), array( 'product_feed_id' => $feed_id ) );
643
+ }
644
+
645
+ public function get_nr_feed_products( $feed_id ) {
646
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
647
+
648
+ return $this->_wpdb->get_row( "SELECT products FROM $main_table WHERE product_feed_id = '$feed_id'" );
649
+ }
650
+
651
+ /**
652
+ * Updates a new feed in the product_feed table.
653
+ *
654
+ * @param (string) $feed_id
655
+ * @param (array) $feed_data
656
+ * @param (array) $data_types
657
+ *
658
+ * @return (int|false) nr of affected rows
659
+ * @since 1.0.0
660
+ *
661
+ */
662
+ public function update_feed( $feed_id, $feed_data, $data_types ) {
663
+
664
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
665
+
666
+ return $this->_wpdb->update(
667
+ $main_table,
668
+ $feed_data,
669
+ array(
670
+ 'product_feed_id' => $feed_id,
671
+ ),
672
+ $data_types,
673
+ array(
674
+ '%d',
675
+ )
676
+ );
677
+ }
678
+
679
+ /**
680
+ * Update Feed update Meta Data
681
+ * @param $feed_id
682
+ * @param $feed_url
683
+ * @param $nr_products
684
+ * @return false|int
685
+ */
686
+ public function update_feed_update_data( $feed_id, $feed_url, $nr_products ) {
687
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
688
+
689
+ return $this->_wpdb->update(
690
+ $main_table,
691
+ array(
692
+ 'updated' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
693
+ 'url' => $feed_url,
694
+ 'products' => $nr_products,
695
+ ),
696
+ array( 'product_feed_id' => $feed_id ),
697
+ array( '%s', '%s', '%s' ),
698
+ array( '%d' )
699
+ );
700
+ }
701
+
702
+ /**
703
+ * @param $feed_id
704
+ * @return mixed
705
+ */
706
+ public function get_file_url_from_feed( $feed_id ) {
707
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
708
+ $result = $this->_wpdb->get_row( "SELECT url FROM $main_table WHERE product_feed_id = $feed_id", ARRAY_A );
709
+
710
+ return $result['url'];
711
+ }
712
+
713
+ /**
714
+ * Sets the status id of a feed
715
+ *
716
+ * @param string $feed_id
717
+ * @param int $status
718
+ *
719
+ * @return bool
720
+ */
721
+ public function update_feed_file_status( $feed_id, $status ) {
722
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
723
+
724
+ return $this->_wpdb->update( $main_table, array( 'status_id' => $status ), array( 'product_feed_id' => $feed_id ), array( '%d' ), array( '%d' ) );
725
+ }
726
+
727
+ /**
728
+ * @param $feed_id
729
+ * @param $meta_data
730
+ * @return false|int
731
+ */
732
+ public function update_meta_data( $feed_id, $meta_data ) {
733
+ // TODO: Onderstaande proces is nog niet echt efficient. In plaats van het standaard verwijderen
734
+ // van elke bestaande regel met het geselecteerde id nummer, zou ik eerst moeten kijken of
735
+ // deze regel wel is gewijzigd. Indien een regel niet is gewijzigd zou ik hem ook niet moeten
736
+ // verwijderen.
737
+
738
+ $main_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
739
+
740
+ // first remove all meta data belonging to this feed except the product_filter_query
741
+ //$this->_wpdb->delete( $main_data, array( 'product_feed_id' => $feed_id ) ); // could not use it because it can't work with !=
742
+ $this->_wpdb->query( "DELETE FROM $main_table WHERE product_feed_id = $feed_id AND meta_key != 'product_filter_query'" );
743
+
744
+ $counter = 0;
745
+
746
+ for ( $i = 0; $i < count( $meta_data ); $i ++ ) {
747
+ if ( ! empty( $meta_data[ $i ]->value ) && '{}' !== $meta_data[ $i ]->value ) {
748
+ $result = $this->_wpdb->insert(
749
+ $main_table,
750
+ array(
751
+ 'product_feed_id' => $feed_id,
752
+ 'meta_key' => $meta_data[ $i ]->key,
753
+ 'meta_value' => $meta_data[ $i ]->value,
754
+ ),
755
+ array(
756
+ '%d',
757
+ '%s',
758
+ '%s',
759
+ )
760
+ );
761
+
762
+ $counter += $result;
763
+ }
764
+ }
765
+
766
+ return $counter;
767
+ }
768
+
769
+ /**
770
+ * Resets the status_id's of failed feeds.
771
+ *
772
+ * @since 2.7.0
773
+ */
774
+ public function reset_all_feed_status() {
775
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
776
+ $failed_ids = $this->_wpdb->get_results( "SELECT product_feed_id FROM $main_table WHERE status_id > '2' OR status_id = '0'", 'ARRAY_A' );
777
+
778
+ foreach ( $failed_ids as $feed_id ) {
779
+ $id = $feed_id['product_feed_id'];
780
+ $base_status = $this->_wpdb->get_var( "SELECT base_status_id FROM $main_table WHERE product_feed_id = '$id'" );
781
+ $new_status = '1' === $base_status || '2' === $base_status ? $base_status : '2';
782
+
783
+ $this->_wpdb->update(
784
+ $main_table,
785
+ array(
786
+ 'status_id' => $new_status,
787
+ 'products' => 0,
788
+ ),
789
+ array(
790
+ 'product_feed_id' => $id,
791
+ ),
792
+ array(
793
+ '%s',
794
+ '%d',
795
+ )
796
+ );
797
+ }
798
+ }
799
+
800
+ public function store_feed_filter( $feed_id, $filter ) {
801
+ $main_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
802
+
803
+ if ( $filter ) {
804
+ $exists = $this->_wpdb->get_results( "SELECT meta_id FROM $main_table WHERE product_feed_id = $feed_id AND meta_key = 'product_filter_query'" );
805
+
806
+ if ( $exists ) {
807
+ $this->_wpdb->update(
808
+ $main_table,
809
+ array(
810
+ 'meta_value' => $filter,
811
+ ),
812
+ array(
813
+ 'product_feed_id' => $feed_id,
814
+ 'meta_key' => 'product_filter_query',
815
+ ),
816
+ array(
817
+ '%s',
818
+ ),
819
+ array(
820
+ '%d',
821
+ '%s',
822
+ )
823
+ );
824
+ } else {
825
+ $this->_wpdb->insert(
826
+ $main_table,
827
+ array(
828
+ 'product_feed_id' => $feed_id,
829
+ 'meta_key' => 'product_filter_query',
830
+ 'meta_value' => $filter,
831
+ ),
832
+ array(
833
+ '%d',
834
+ '%s',
835
+ '%s',
836
+ )
837
+ );
838
+ }
839
+ } else {
840
+ $this->_wpdb->query( "DELETE FROM $main_table WHERE product_feed_id = $feed_id AND meta_key = 'product_filter_query'" );
841
+ }
842
+ }
843
+
844
+ public function insert_meta_data( $feed_id, $meta_data, $feed_filter_data, $category_mapping ) {
845
+ $main_table = $this->_table_prefix . 'feedmanager_product_feedmeta';
846
+
847
+ $counter = 0;
848
+
849
+ for ( $i = 0; $i < count( $meta_data ); $i ++ ) {
850
+ $result = $this->_wpdb->insert(
851
+ $main_table,
852
+ array(
853
+ 'product_feed_id' => $feed_id,
854
+ 'meta_key' => $meta_data[ $i ]['meta_key'],
855
+ 'meta_value' => $meta_data[ $i ]['meta_value'],
856
+ ),
857
+ array(
858
+ '%d',
859
+ '%s',
860
+ '%s',
861
+ )
862
+ );
863
+
864
+ $counter += $result;
865
+ }
866
+
867
+ for ( $i = 0; $i < count( $feed_filter_data ); $i++ ) {
868
+ $this->store_feed_filter( $feed_id, $feed_filter_data[ $i ]['meta_value'] );
869
+ }
870
+
871
+ $counter += $this->_wpdb->insert(
872
+ $main_table,
873
+ array(
874
+ 'product_feed_id' => $feed_id,
875
+ 'meta_key' => 'category_mapping',
876
+ 'meta_value' => $category_mapping[0]['meta_value'],
877
+ ),
878
+ array(
879
+ '%d',
880
+ '%s',
881
+ '%s',
882
+ )
883
+ );
884
+
885
+ return $counter;
886
+ }
887
+
888
+ public function title_exists( $feed_title ) {
889
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
890
+ $count = $this->_wpdb->get_var( "SELECT COUNT(*) FROM $main_table WHERE title = '$feed_title'" );
891
+
892
+ return $count > 0 ? true : false;
893
+ }
894
+
895
+ /**
896
+ * Inserts a new feed in the product_feed table and returns its new id.
897
+ *
898
+ * @param array $feed_data_to_store
899
+ * @param array $feed_types
900
+ *
901
+ * @return integer containing the id of the new feed
902
+ * @since 1.0.0
903
+ *
904
+ */
905
+ public function create_feed( $feed_data_to_store, $feed_types ) {
906
+
907
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
908
+
909
+ $this->_wpdb->insert(
910
+ $main_table,
911
+ $feed_data_to_store,
912
+ $feed_types
913
+ );
914
+
915
+ return $this->_wpdb->insert_id;
916
+ }
917
+
918
+ public function getCountryID($feed_id){
919
+ $countryID = $this->_wpdb->get_results("SELECT country_id FROM {$this->_table_prefix}feedmanager_product_feed WHERE product_feed_id = ".$feed_id);
920
+
921
+ return $countryID;
922
+ }
923
+
924
+ public function getScheduleTime($feed_id){
925
+ $scheduleTime = $this->_wpdb->get_results("SELECT schedule FROM {$this->_table_prefix}feedmanager_product_feed WHERE product_feed_id = ".$feed_id);
926
+
927
+ return $scheduleTime;
928
+ }
929
+
930
+ public function getFeedData($feed_id){
931
+ $feedData = $this->_wpdb->get_results("SELECT title,feed_description,feed_title FROM {$this->_table_prefix}feedmanager_product_feed WHERE product_feed_id = ".$feed_id);
932
+
933
+ return $feedData;
934
+ }
935
+
936
+ public function getCountryCode($countryID){
937
+ $countryCode = $this->_wpdb->get_results("SELECT name_short FROM {$this->_table_prefix}feedmanager_country WHERE country_id =".$countryID[0]->country_id);
938
+ return $countryCode;
939
+ }
940
+
941
+ public function insertGmcFeedId($feedID,$feed_id){
942
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
943
+ return $this->_wpdb->update( $main_table, array( 'gmc_feed_id' => $feedID ), array( 'product_feed_id' => $feed_id ) );
944
+ }
945
+
946
+ public function getGmcFeedId($feed_id){
947
+ $gmcFeedId = $this->_wpdb->get_results("SELECT gmc_feed_id FROM {$this->_table_prefix}feedmanager_product_feed WHERE product_feed_id =". $feed_id);
948
+ return $gmcFeedId;
949
+ }
950
+
951
+ public function getFeedURL($feed_id){
952
+ $main_table = $this->_table_prefix . 'feedmanager_product_feed';
953
+ return $this->_wpdb->get_results("SELECT url,feed_title,status_id FROM $main_table WHERE product_feed_id =". $feed_id);
954
+ }
955
+
956
+ public function getTableColumns($table) {
957
+ return $this->_wpdb->get_results("SELECT column_name as field FROM information_schema.columns WHERE table_name = '$table'");
958
+ }
959
+
960
+ public function getTableData($table = 'wp_postmeta', $columns = array()) {
961
+ return $this->_wpdb->get_results("SELECT DISTINCT " . implode(',', $columns) . " as field FROM $table");
962
+ }
963
+
964
+ public function getTablePostMeta($post_id) {
965
+ return $this->_wpdb->get_results("SELECT meta_key,meta_value FROM wp_postmeta where post_id=" . $post_id);
966
+ }
967
+ }
968
+ // End of TVC_Queries class
969
+
970
+ endif;
includes/data/class-tvc-tab.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Tab Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.0.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Tab' ) ) :
15
+
16
+ class TVC_Tab {
17
+
18
+ /*
19
+ * Contains the page identifier string
20
+ */
21
+ private $_page_identifier;
22
+
23
+ /*
24
+ * Is the selected tab or not
25
+ */
26
+ private $_tab_status;
27
+
28
+ /*
29
+ * Contains the title of the tab
30
+ */
31
+ private $_tab_title;
32
+
33
+ /*
34
+ * Contains a class identifier
35
+ */
36
+ private $_class_identifier;
37
+
38
+ /**
39
+ * TVC_Tab constructor.
40
+ *
41
+ * @param string $page_identifier
42
+ * @param bool $tab_status
43
+ * @param string $tab_title
44
+ * @param string $class_identifier
45
+ */
46
+ public function __construct( $page_identifier, $tab_status, $tab_title, $class_identifier ) {
47
+
48
+ $this->_page_identifier = $page_identifier;
49
+ $this->_tab_status = $tab_status;
50
+ $this->_tab_title = $tab_title;
51
+ $this->_class_identifier = $class_identifier;
52
+ }
53
+
54
+ /**
55
+ * Returns the tabs url parameters page and tab
56
+ *
57
+ * @return string
58
+ */
59
+ public function get_page_tab_url() {
60
+ return 'page=tvc-product-feed-manager&tab=' . $this->_page_identifier;
61
+ }
62
+
63
+ public function get_page_identifier() {
64
+ return $this->_page_identifier;
65
+ }
66
+
67
+ public function get_class_identifier() {
68
+ return $this->_class_identifier;
69
+ }
70
+
71
+ /**
72
+ * Returns a string that can be used in the tabs html code to identify it as the active tab
73
+ *
74
+ * @return string
75
+ */
76
+ public function tab_selected_string() {
77
+ return $this->_tab_status ? ' nav-tab-active' : '';
78
+ }
79
+
80
+ /**
81
+ * Returns the tab title
82
+ *
83
+ * @return string
84
+ */
85
+ public function get_tab_title() {
86
+ return $this->_tab_title;
87
+ }
88
+
89
+ /**
90
+ * Returns the main input wrapper class name
91
+ *
92
+ * @return string
93
+ */
94
+ public function get_main_input_wrapper_class() {
95
+ return 'TVC_' . $this->_class_identifier . '_Main_Input_Wrapper';
96
+ }
97
+
98
+ /**
99
+ * Returns the category selector wrapper class name
100
+ *
101
+ * @return string
102
+ */
103
+ public function get_category_selector_wrapper_class() {
104
+ return 'TVC_' . $this->_class_identifier . '_Category_Wrapper';
105
+ }
106
+
107
+ /**
108
+ * Returns the attribute mapping wrapper class name
109
+ *
110
+ * @return string
111
+ */
112
+ public function get_attribute_mapping_wrapper_class() {
113
+ return 'TVC_' . $this->_class_identifier . '_Attribute_Mapping_Wrapper';
114
+ }
115
+
116
+ /**
117
+ * Set this tab as the selected tab
118
+ */
119
+ public function set_tab_as_selected() {
120
+ $this->_tab_status = true;
121
+ }
122
+ }
123
+
124
+ // end of TVC_Tab class
125
+
126
+ endif;
includes/data/class-tvc-taxonomies.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Taxonomies Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 5.2.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Taxonomies' ) ) :
15
+
16
+ /**
17
+ * Taxonomies Class
18
+ */
19
+ class TVC_Taxonomies {
20
+
21
+ /**
22
+ * Generates a string of shop taxonomies (like a category string) in the correct order
23
+ *
24
+ * @param string $product_id
25
+ * @param string $tax
26
+ * @param string $separator
27
+ *
28
+ * @return string
29
+ */
30
+ public static function make_shop_taxonomies_string( $product_id, $tax = 'product_cat', $separator = ' > ' ) {
31
+ $args = array(
32
+ 'taxonomy' => $tax,
33
+ 'orderby' => 'parent',
34
+ 'order' => 'DESC',
35
+ );
36
+
37
+ // get the post term ordered with the last child cat first
38
+ $cats = wp_get_post_terms( $product_id, $tax, $args );
39
+
40
+ $result = array();
41
+
42
+ if ( count( $cats ) === 0 ) {
43
+ return '';
44
+ }
45
+
46
+ // anonymous function to get the correct taxonomy string
47
+ $cat_string = function ( $id ) use ( &$result, &$cat_string, $tax ) {
48
+ // get the first term
49
+ $term = get_term_by( 'id', $id, $tax, 'ARRAY_A' );
50
+
51
+ // check if the term has a parent
52
+ if ( $term['parent'] ) {
53
+ // start the anonymous function again with the parent id
54
+ $cat_string( $term['parent'] );
55
+ }
56
+
57
+ // add the terms name to the result
58
+ $result[] = $term['name'];
59
+ };
60
+
61
+ // activate the anonymous function with the first categories term_id
62
+ $cat_string( $cats[0]->term_id );
63
+
64
+ return implode( $separator, $result );
65
+ }
66
+
67
+ /**
68
+ * Generates a string with all selected categories
69
+ *
70
+ * @param string $post_id
71
+ * @param string $separator
72
+ *
73
+ * @return string
74
+ */
75
+ public static function get_shop_categories( $post_id, $separator = ', ' ) {
76
+ $return_string = '';
77
+
78
+ $args = array(
79
+ 'taxonomy' => 'product_cat',
80
+ 'orderby' => 'term_id',
81
+ );
82
+
83
+ $cats = wp_get_post_terms( $post_id, 'product_cat', $args );
84
+
85
+ foreach ( $cats as $cat ) {
86
+ $return_string .= $cat->name . $separator;
87
+ }
88
+
89
+ return rtrim( $return_string, $separator );
90
+ }
91
+
92
+ /**
93
+ * Returns the product category that is selected as primary (only when Yoast plugin is installed)
94
+ *
95
+ * @param string $id
96
+ *
97
+ * @return bool
98
+ */
99
+ public static function get_yoast_primary_cat( $id ) {
100
+ if ( ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) && ! is_plugin_active_for_network( 'wordpress-seo/wp-seo.php' )
101
+ && ! is_plugin_active( 'wordpress-seo-premium/wp-seo-premium.php' ) && ! is_plugin_active_for_network( 'wordpress-seo-premium/wp-seo-premium.php' ) ) {
102
+ return false; // return false if yoast plugin is inactive
103
+ }
104
+
105
+ $primary_cat_id = get_post_meta( $id, '_yoast_wpseo_primary_product_cat', true );
106
+
107
+ if ( $primary_cat_id ) {
108
+ $product_cat[0] = get_term( $primary_cat_id, 'product_cat' );
109
+ if ( isset( $product_cat[0]->term_id ) ) {
110
+ return $product_cat;
111
+ }
112
+ } else {
113
+ return false;
114
+ }
115
+
116
+ return false;
117
+ }
118
+
119
+ public static function get_shop_categories_list() {
120
+ $args = array(
121
+ 'hide_empty' => 0,
122
+ 'taxonomy' => 'product_cat',
123
+ 'hierarchical' => 1,
124
+ 'orderby' => 'name',
125
+ 'order' => 'ASC',
126
+ 'exclude' => apply_filters( 'tvc_category_mapping_exclude', array() ),
127
+ 'exclude_tree' => apply_filters( 'tvc_category_mapping_exclude_tree', array() ),
128
+ 'number' => absint( apply_filters( 'tvc_category_mapping_max_categories', 0 ) ),
129
+ 'child_of' => 0,
130
+ );
131
+
132
+ $args = apply_filters( 'tvc_category_mapping_args', $args );
133
+
134
+ return self::get_cat_hierarchy( 0, $args );
135
+ }
136
+
137
+ private static function get_cat_hierarchy( $parent, $args ) {
138
+ $cats = get_categories( $args );
139
+ $ret = new stdClass;
140
+
141
+ foreach ( $cats as $cat ) {
142
+ if ( $cat->parent == $parent ) {
143
+ $id = $cat->cat_ID;
144
+ $ret->$id = $cat;
145
+ $ret->$id->children = self::get_cat_hierarchy( $id, $args );
146
+ }
147
+ }
148
+ return $ret;
149
+ }
150
+ }
151
+ // end of TVC_Taxonomies_Class
152
+
153
+ endif;
includes/data/class-tvc-variations.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * TVC Product Feed Manager Variations Class.
5
+ *
6
+ * @package TVC Product Feed Manager/Data/Classes
7
+ * @version 1.9.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ if ( ! class_exists( 'TVC_Variations' ) ) :
15
+
16
+ /**
17
+ * Variations Class
18
+ */
19
+ class TVC_Variations {
20
+
21
+ /**
22
+ * Fills the product attributes with the correct variation data
23
+ *
24
+ * @param array $product_data
25
+ * @param WC_Product_Variation $woocommerce_variation_data
26
+ * @param array $wpmr_variation_data
27
+ * @param string $feed_language
28
+ */
29
+ public static function fill_product_data_with_variation_data( &$product_data, $woocommerce_variation_data, $wpmr_variation_data, $feed_language ) {
30
+ $permalink = array_key_exists( 'permalink', $product_data ) ? $product_data['permalink'] : ''; // some channels don't require permalinks
31
+ $conversions = self::variation_conversion_table( $woocommerce_variation_data, $permalink, $feed_language );
32
+
33
+ $variation_attributes = $woocommerce_variation_data->get_variation_attributes();
34
+
35
+ foreach ( $product_data as $key => $field_value ) {
36
+ if ( in_array( $key, array_keys( $conversions ) ) && $field_value !== $conversions[ $key ] && $conversions[ $key ] ) {
37
+ $product_data[ $key ] = $conversions[ $key ];
38
+ }
39
+
40
+ if ( array_key_exists( $key, $variation_attributes ) && $variation_attributes[ $key ] ) {
41
+ $slug_value = $variation_attributes[ $key ];
42
+ $product_data[ $key ] = get_term_by( 'slug', $slug_value, ltrim( $key, 'attribute_' ) )->name;
43
+ continue;
44
+ }
45
+
46
+ if ( array_key_exists( 'attribute_pa_' . $key, $variation_attributes ) && $variation_attributes[ 'attribute_pa_' . $key ] ) {
47
+ $slug_value = $variation_attributes[ 'attribute_pa_' . $key ];
48
+ $product_data[ $key ] = get_term_by( 'slug', $slug_value, 'pa_' . $key )->name;
49
+ continue;
50
+ }
51
+
52
+ if ( $wpmr_variation_data && array_key_exists( $key, $wpmr_variation_data ) ) {
53
+ $product_data[ $key ] = $wpmr_variation_data[ $key ];
54
+ }
55
+ }
56
+ }
57
+
58
+ private static function variation_conversion_table( $variation_data, $main_permalink, $feed_language ) {
59
+ return array(
60
+ 'ID' => (string) $variation_data->get_id(),
61
+ '_downloadable' => $variation_data->get_downloadable( 'feed' ),
62
+ '_virtual' => $variation_data->get_virtual( 'feed' ),
63
+ '_manage_stock' => $variation_data->get_manage_stock( 'feed' ),
64
+ '_stock' => $variation_data->get_stock_quantity( 'feed' ),
65
+ '_backorders' => $variation_data->get_backorders( 'feed' ),
66
+ '_stock_status' => $variation_data->get_stock_status( 'feed' ),
67
+ '_sku' => $variation_data->get_sku( 'feed' ),
68
+ '_weight' => $variation_data->get_weight( 'feed' ),
69
+ '_length' => $variation_data->get_length( 'feed' ),
70
+ '_width' => $variation_data->get_width( 'feed' ),
71
+ '_height' => $variation_data->get_height( 'feed' ),
72
+ 'post_content' => $variation_data->get_description( 'feed' ),
73
+ '_regular_price' => tvc_prep_money_values( $variation_data->get_regular_price( 'feed' ), $feed_language ),
74
+ '_sale_price' => tvc_prep_money_values( $variation_data->get_sale_price( 'feed' ), $feed_language ),
75
+ '_sale_price_dates_from' => $variation_data->get_date_on_sale_from( 'feed' ) && ( $date = $variation_data->get_date_on_sale_from( 'feed' )->getTimestamp() ) ? tvc_convert_price_date_to_feed_format( $date ) : '',
76
+ '_sale_price_dates_to' => $variation_data->get_date_on_sale_to( 'feed' ) && ( $date = $variation_data->get_date_on_sale_to( 'feed' )->getTimestamp() ) ? tvc_convert_price_date_to_feed_format( $date ) : '',
77
+ 'attachment_url' => wp_get_attachment_url( get_post_thumbnail_id( $variation_data->get_id() ) ),
78
+ 'permalink' => $main_permalink,
79
+ );
80
+ }
81
+ }
82
+
83
+ // End of TVC_Variations_Class
84
+
85
+ endif;
includes/data/js/tvc_ajaxdatahandling.js ADDED
@@ -0,0 +1,718 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var myAjaxNonces;
3
+
4
+ function tvc_getFeedList( callback ) {
5
+
6
+ jQuery.post(
7
+ myAjaxNonces.ajaxurl,
8
+ {
9
+ action: 'tvcajax-get-list-of-feeds',
10
+ postFeedsListNonce: myAjaxNonces.postFeedsListNonce,
11
+
12
+ },
13
+ function( response ) {
14
+
15
+ callback( tvc_validateResponse( response ) );
16
+ }
17
+ );
18
+ }
19
+
20
+ function tvc_getBackupsList( callback ) {
21
+ jQuery.post(
22
+ myAjaxNonces.ajaxurl,
23
+ {
24
+ action: 'tvcajax-get-list-of-backups',
25
+ postBackupListNonce: myAjaxNonces.postBackupListNonce,
26
+
27
+ },
28
+ function( response ) {
29
+
30
+ callback( tvc_validateResponse( response ) );
31
+ }
32
+ );
33
+ }
34
+
35
+ function tvc_getSettingsOptions( callback ) {
36
+
37
+ jQuery.post(
38
+ myAjaxNonces.ajaxurl,
39
+ {
40
+ action: 'tvcajax-get-settings-options',
41
+ postSetupOptionsNonce: myAjaxNonces.postSetupOptionsNonce,
42
+
43
+ },
44
+ function( response ) {
45
+
46
+ callback( tvc_validateResponse( response ) );
47
+ }
48
+ );
49
+ }
50
+
51
+ /**
52
+ * Reads and returns all possible output fields from the selected merchant
53
+ *
54
+ * @param {int} feedId
55
+ * @param {int} channelId
56
+ * @param callback
57
+ * @returns list with output fields
58
+ */
59
+ function tvc_getOutputFields( feedId, channelId, callback ) {
60
+
61
+ jQuery.post(
62
+ myAjaxNonces.ajaxurl,
63
+ {
64
+ action: 'tvcajax-get-output-fields',
65
+ feedId: feedId,
66
+ channelId: channelId,
67
+ outputFieldsNonce: myAjaxNonces.outputFieldsNonce,
68
+
69
+ },
70
+ function( response ) {
71
+
72
+ callback( tvc_validateResponse( response ) );
73
+ }
74
+ );
75
+ }
76
+
77
+ /**
78
+ * Reads and returns all possible source fields from the selected source
79
+ *
80
+ * @param {int} sourceId
81
+ * @param callback
82
+ * @returns list with input fields
83
+ */
84
+ function tvc_getSourceFields( sourceId, callback ) {
85
+
86
+ jQuery.post(
87
+ myAjaxNonces.ajaxurl,
88
+ {
89
+ action: 'tvcajax-get-input-fields',
90
+ sourceId: sourceId,
91
+ inputFieldsNonce: myAjaxNonces.inputFieldsNonce,
92
+
93
+ },
94
+ function( response ) {
95
+
96
+ callback( tvc_validateResponse( response ) );
97
+ }
98
+ );
99
+ }
100
+
101
+ /**
102
+ * Get main feed filters
103
+ * @param feedId
104
+ * @param callback
105
+ */
106
+ function tvc_getMainFeedFilters( feedId, callback ) {
107
+
108
+ jQuery.post(
109
+ myAjaxNonces.ajaxurl,
110
+ {
111
+ action: 'tvcajax-get-main-feed-filters',
112
+ feedId: feedId,
113
+ inputFeedFiltersNonce: myAjaxNonces.inputFeedFiltersNonce,
114
+
115
+ },
116
+ function( response ) {
117
+
118
+ callback( tvc_validateResponse( response ) );
119
+ }
120
+ );
121
+ }
122
+
123
+ /**
124
+ * Fetch next category
125
+ * @param channelId
126
+ * @param requestedLevel
127
+ * @param parentCategory
128
+ * @param language
129
+ * @param callback
130
+ */
131
+ function tvc_getNextCategories( channelId, requestedLevel, parentCategory, language, callback ) {
132
+
133
+ jQuery.post(
134
+ myAjaxNonces.ajaxurl,
135
+ {
136
+ action: 'tvcajax-get-next-categories',
137
+ channelId: channelId,
138
+ requestedLevel: requestedLevel,
139
+ parentCategory: parentCategory,
140
+ fileLanguage: language,
141
+ nextCategoryNonce: myAjaxNonces.nextCategoryNonce,
142
+
143
+ },
144
+ function( response ) {
145
+
146
+ response = response.trim();
147
+
148
+ if ( response.substr( response.length - 1 ) === '0' ) {
149
+ response = response.substring( 0, response.length - 1 );
150
+ }
151
+
152
+ callback( tvc_validateResponse( response ) );
153
+ }
154
+ );
155
+ }
156
+
157
+ /**
158
+ * Get Category Listing from String
159
+ * @param channelId
160
+ * @param mainCategoriesString
161
+ * @param language
162
+ * @param callback
163
+ */
164
+ function tvc_getCategoryListsFromString( channelId, mainCategoriesString, language, callback ) {
165
+ jQuery.post(
166
+ myAjaxNonces.ajaxurl,
167
+ {
168
+ action: 'tvcajax-get-category-lists',
169
+ channelId: channelId,
170
+ mainCategories: mainCategoriesString,
171
+ fileLanguage: language,
172
+ categoryListsNonce: myAjaxNonces.categoryListsNonce,
173
+
174
+ },
175
+ function( response ) {
176
+
177
+ callback( tvc_validateResponse( response ) );
178
+ }
179
+ );
180
+ }
181
+
182
+ /**
183
+ * Ajax Call for update feed to database
184
+ * @param feedData
185
+ * @param metaData
186
+ * @param feedFilter
187
+ * @param callback
188
+ */
189
+ function tvc_updateFeedToDb( feedData, metaData, feedFilter, callback ) {
190
+ jQuery.post(
191
+ myAjaxNonces.ajaxurl,
192
+ {
193
+ action: 'tvcajax-update-feed-data',
194
+ feed: JSON.stringify( feedData ),
195
+ feedFilter: feedFilter ? feedFilter[ 0 ][ 'meta_value' ] : '',
196
+ metaData: JSON.stringify( metaData ),
197
+ updateFeedDataNonce: myAjaxNonces.updateFeedDataNonce,
198
+ },
199
+ function( response ) {
200
+ console.log(response);
201
+ callback( tvc_validateResponse( response ) );
202
+ }
203
+ );
204
+ }
205
+
206
+ /**
207
+ * Ajax call for update XML feed file
208
+ * @param feed_id
209
+ * @param callback
210
+ */
211
+ function tvc_updateFeedFile( feed_id, callback ) {
212
+ jQuery.post(
213
+ myAjaxNonces.ajaxurl,
214
+ {
215
+ action: 'tvcajax-update-feed-file',
216
+ dataType: 'text',
217
+ feedId: feed_id,
218
+ updateFeedFileNonce: myAjaxNonces.updateFeedFileNonce,
219
+
220
+ },
221
+ function( response ) {
222
+
223
+ callback( tvc_validateResponse( response ) );
224
+ }
225
+ );
226
+ }
227
+
228
+ /**
229
+ * Update current/selected feed status
230
+ * @param feedId
231
+ * @param callback
232
+ */
233
+ function tvc_getCurrentFeedStatus( feedId, callback ) {
234
+
235
+ jQuery.post(
236
+ myAjaxNonces.ajaxurl,
237
+ {
238
+ action: 'tvcajax-get-feed-status',
239
+ sourceId: feedId,
240
+ feedStatusNonce: myAjaxNonces.feedStatusNonce,
241
+
242
+ },
243
+ function( response ) {
244
+
245
+ callback( tvc_validateResponse( response ) );
246
+ }
247
+ );
248
+ }
249
+
250
+ function tvc_getFeedData( feedId, callback ) {
251
+
252
+ jQuery.post(
253
+ myAjaxNonces.ajaxurl,
254
+ {
255
+ action: 'tvcajax-get-feed-data',
256
+ sourceId: feedId,
257
+ feedDataNonce: myAjaxNonces.feedDataNonce,
258
+
259
+ },
260
+ function( response ) {
261
+
262
+ callback( tvc_validateResponse( response ) );
263
+ }
264
+ );
265
+ }
266
+
267
+ /**
268
+ * Switch feed status auto/manual
269
+ * @param feedId
270
+ * @param callback
271
+ */
272
+ function tvc_switchFeedStatus( feedId, callback ) {
273
+
274
+ jQuery.post(
275
+ myAjaxNonces.ajaxurl,
276
+ {
277
+ action: 'tvcajax-switch-feed-status',
278
+ feedId: feedId,
279
+ switchFeedStatusNonce: myAjaxNonces.switchFeedStatusNonce,
280
+
281
+ },
282
+ function( response ) {
283
+
284
+ tvc_switchStatusAction( feedId, response );
285
+ callback( tvc_validateResponse( response ) );
286
+ }
287
+ );
288
+ }
289
+
290
+ /**
291
+ * Duplicate/Clone existing feed
292
+ * @param feedId
293
+ * @param callback
294
+ */
295
+ function tvc_duplicateExistingFeed( feedId, callback ) {
296
+
297
+ jQuery.post(
298
+ myAjaxNonces.ajaxurl,
299
+ {
300
+ action: 'tvcajax-duplicate-existing-feed',
301
+ feedId: feedId,
302
+ duplicateFeedNonce: myAjaxNonces.duplicateFeedNonce,
303
+
304
+ },
305
+ function( response ) {
306
+
307
+ if ( response.trim() ) {
308
+ tvc_resetFeedList();
309
+ }
310
+
311
+ callback( tvc_validateResponse( response ) );
312
+ }
313
+ );
314
+ }
315
+
316
+ /**
317
+ * Log message on server
318
+ * @param message
319
+ * @param fileName
320
+ * @param callback
321
+ */
322
+ function tvc_logMessageOnServer( message, fileName, callback ) {
323
+
324
+ jQuery.post(
325
+ myAjaxNonces.ajaxurl,
326
+ {
327
+ action: 'tvcajax-log-message',
328
+ messageList: message,
329
+ fileName: fileName,
330
+ logMessageNonce: myAjaxNonces.logMessageNonce,
331
+
332
+ },
333
+ function( result ) {
334
+
335
+ callback( result.trim() );
336
+ }
337
+ );
338
+ }
339
+
340
+ function tvc_auto_feed_fix_mode( selection, callback ) {
341
+
342
+ jQuery.post(
343
+ myAjaxNonces.ajaxurl,
344
+ {
345
+ action: 'tvcajax-auto-feed-fix-mode-selection',
346
+ fix_selection: selection,
347
+ updateAutoFeedFixNonce: myAjaxNonces.setAutoFeedFixNonce,
348
+
349
+ },
350
+ function( response ) {
351
+
352
+ callback( response.trim() );
353
+ }
354
+ );
355
+ }
356
+
357
+ /**
358
+ * Ajax for background process of selected feeds
359
+ * @param selection
360
+ * @param callback
361
+ */
362
+ function tvc_background_processing_mode( selection, callback ) {
363
+
364
+ jQuery.post(
365
+ myAjaxNonces.ajaxurl,
366
+ {
367
+ action: 'tvcajax-background-processing-mode-selection',
368
+ mode_selection: selection,
369
+ backgroundModeNonce: myAjaxNonces.setBackgroundModeNonce,
370
+
371
+ },
372
+ function( response ) {
373
+
374
+ callback( response.trim() );
375
+ }
376
+ );
377
+ }
378
+
379
+ function tvc_feed_logger_status( selection, callback ) {
380
+
381
+ jQuery.post(
382
+ myAjaxNonces.ajaxurl,
383
+ {
384
+ action: 'tvcajax-feed-logger-status-selection',
385
+ statusSelection: selection,
386
+ feedLoggerStatusNonce: myAjaxNonces.setFeedLoggerStatusNonce,
387
+
388
+ },
389
+ function( response ) {
390
+
391
+ callback( response.trim() );
392
+ }
393
+ );
394
+ }
395
+
396
+ /**
397
+ * Sets the Show Product Identifiers option.
398
+ *
399
+ * @since 2.10.0.
400
+ *
401
+ * @param selection
402
+ * @param callback
403
+ */
404
+ function tvc_show_pi_status( selection, callback ) {
405
+
406
+ jQuery.post(
407
+ myAjaxNonces.ajaxurl,
408
+ {
409
+ action: 'tvcajax-show-product-identifiers-selection',
410
+ showPiSelection: selection,
411
+ showPINonce: myAjaxNonces.setShowPINonce,
412
+
413
+ },
414
+ function( response ) {
415
+
416
+ callback( response.trim() );
417
+ }
418
+ );
419
+ }
420
+
421
+ function tvc_change_third_party_attribute_keywords( keywords, callback ) {
422
+
423
+ jQuery.post(
424
+ myAjaxNonces.ajaxurl,
425
+ {
426
+ action: 'tvcajax-third-party-attribute-keywords',
427
+ keywords: keywords,
428
+ thirdPartyKeywordsNonce: myAjaxNonces.setThirdPartyKeywordsNonce,
429
+
430
+ },
431
+ function( response ) {
432
+
433
+ callback( response.trim() );
434
+ }
435
+ );
436
+ }
437
+
438
+ function tvc_change_notice_mailaddress( mailAddress, callback ) {
439
+
440
+ jQuery.post(
441
+ myAjaxNonces.ajaxurl,
442
+ {
443
+ action: 'tvcajax-set-notice-mailaddress',
444
+ mailaddress: mailAddress,
445
+ noticeMailaddressNonce: myAjaxNonces.setNoticeMailaddressNonce,
446
+
447
+ },
448
+ function( response ) {
449
+
450
+ callback( response.trim() );
451
+ }
452
+ );
453
+ }
454
+
455
+ function tvc_change_background_processing_time_limit( limit, callback ) {
456
+
457
+ jQuery.post(
458
+ myAjaxNonces.ajaxurl,
459
+ {
460
+ action: 'tvcajax-background-processing-time-limit',
461
+ limit: limit,
462
+ batchProcessingLimitNonce: myAjaxNonces.setBatchProcessingLimitNonce,
463
+
464
+ },
465
+ function( response ) {
466
+
467
+ callback( response.trim() );
468
+ }
469
+ );
470
+ }
471
+
472
+ function tvc_clear_feed_process_data( callback ) {
473
+ jQuery.post(
474
+ myAjaxNonces.ajaxurl,
475
+ {
476
+ action: 'tvcajax-clear-feed-process-data',
477
+ clearFeedNonce: myAjaxNonces.setClearFeedProcessNonce,
478
+
479
+ },
480
+ function( response ) {
481
+
482
+ callback( response );
483
+ }
484
+ );
485
+ }
486
+
487
+ function tvc_reinitiate_plugin( callback ) {
488
+ jQuery.post(
489
+ myAjaxNonces.ajaxurl,
490
+ {
491
+ action: 'tvcajax-reinitiate-plugin',
492
+ reInitiateNonce: myAjaxNonces.setReInitiateNonce,
493
+
494
+ },
495
+ function( response ) {
496
+
497
+ callback( response );
498
+ }
499
+ );
500
+ }
501
+
502
+ /**
503
+ * Takes the response of an ajax call and checks if it's ok. When not, it will display the error and return
504
+ * an empty list.
505
+ *
506
+ * @param {String} response
507
+ *
508
+ * @returns {String}
509
+ */
510
+ function tvc_validateResponse( response ) {
511
+
512
+ response = response.trim(); // remove php ajax response white spaces
513
+
514
+ // when the response contains no error message
515
+ if ( response.indexOf( '<div id=\'error\'>' ) < 0 && response.indexOf( '<b>Fatal error</b>' ) < 0 && response.indexOf( '<b>Notice</b>' ) < 0 && response.indexOf( '<b>Warning</b>' ) < 0 && response.indexOf( '<b>Catchable fatal error</b>' ) < 0 && response.indexOf( '<div id="error">' ) < 0 ) {
516
+
517
+ if ( response.indexOf( '[]' ) < 0 ) {
518
+
519
+ if ( response !== '' ) {
520
+
521
+ return (
522
+ response
523
+ );
524
+ } else {
525
+
526
+ return (
527
+ '1'
528
+ );
529
+ }
530
+ } else { // if it has an error message
531
+
532
+ // return an empty list
533
+ return (
534
+ '0'
535
+ );
536
+ }
537
+ } else {
538
+
539
+ tvc_show_error_message( response.replace( '[]', '' ) );
540
+ tvc_hideFeedSpinner();
541
+
542
+ tvc_logMessageOnServer(
543
+ response,
544
+ 'error',
545
+ function( result ) {
546
+
547
+ // return an empty list
548
+ return (
549
+ '0'
550
+ );
551
+ }
552
+ );
553
+ }
554
+ }
555
+
556
+ /**
557
+ * Deletes a specific feed file
558
+ *
559
+ * This function first removes the file from the server and than from the feed database.
560
+ * After that it will refresh the Feed List.
561
+ *
562
+ * @param {int} id
563
+ * @param {string} feedTitle
564
+ * @returns nothing
565
+ */
566
+ function tvc_deleteFeed( id, feedTitle ) {
567
+ var feedSpinnerElement = jQuery( '#feed-spinner' );
568
+ var feedListMessageElement = jQuery( '#feed-list-message' );
569
+
570
+ // clear old messages
571
+ feedListMessageElement.empty();
572
+
573
+ // remove the file
574
+ tvc_removeFeedFile(
575
+ function() {
576
+ feedSpinnerElement.show();
577
+
578
+ // delete the file entry in the database
579
+ tvc_deleteFeedFromDb(
580
+ id,
581
+ function( response ) {
582
+ feedSpinnerElement.show();
583
+
584
+ response = response.trim();
585
+
586
+ if ( response === '1' ) {
587
+ // reset the feed list
588
+ tvc_resetFeedList();
589
+ feedSpinnerElement.hide();
590
+ } else {
591
+ // report the result to the user
592
+ feedListMessageElement.append( response );
593
+ feedSpinnerElement.hide();
594
+ }
595
+ },
596
+ id
597
+ );
598
+ },
599
+ feedTitle
600
+ );
601
+ }
602
+
603
+ function tvc_removeFeedFile( callback, feedTitle ) {
604
+
605
+ jQuery.post(
606
+ myAjaxNonces.ajaxurl,
607
+ {
608
+ action: 'tvcajax-delete-feed-file',
609
+ fileTitle: feedTitle,
610
+ deleteFeedNonce: myAjaxNonces.deleteFeedNonce,
611
+
612
+ },
613
+ function( response ) {
614
+
615
+ callback( tvc_validateResponse( response ) );
616
+ }
617
+ );
618
+ }
619
+
620
+ function tvc_deleteFeedFromDb( feedId, callback ) {
621
+
622
+ jQuery.post(
623
+ myAjaxNonces.ajaxurl,
624
+ {
625
+ action: 'tvcajax-delete-feed',
626
+ feedId: feedId,
627
+ deleteFeedNonce: myAjaxNonces.deleteFeedNonce,
628
+
629
+ },
630
+ function( response ) {
631
+
632
+ callback( tvc_validateResponse( response ) );
633
+ }
634
+ );
635
+ }
636
+
637
+ function tvc_checkNextFeedInQueue( callback ) {
638
+ jQuery.post(
639
+ myAjaxNonces.ajaxurl,
640
+ {
641
+ action: 'tvcajax-get-next-feed-in-queue',
642
+ nextFeedInQueueNonce: myAjaxNonces.nextFeedInQueueNonce,
643
+
644
+ },
645
+ function( response ) {
646
+
647
+ callback( tvc_validateResponse( response ) );
648
+ }
649
+ );
650
+ }
651
+
652
+ function tvc_initiateBackup( fileName, callback ) {
653
+
654
+ jQuery.post(
655
+ myAjaxNonces.ajaxurl,
656
+ {
657
+ action: 'tvcajax-backup-current-data',
658
+ fileName: fileName,
659
+ backupNonce: myAjaxNonces.backupNonce,
660
+
661
+ },
662
+ function( response ) {
663
+
664
+ callback( tvc_validateResponse( response ) );
665
+ }
666
+ );
667
+ }
668
+
669
+ function tvc_deleteBackup( fileName, callback ) {
670
+
671
+ jQuery.post(
672
+ myAjaxNonces.ajaxurl,
673
+ {
674
+ action: 'tvcajax-delete-backup-file',
675
+ fileName: fileName,
676
+ deleteBackupNonce: myAjaxNonces.deleteBackupNonce,
677
+
678
+ },
679
+ function( response ) {
680
+
681
+ callback( tvc_validateResponse( response ) );
682
+ }
683
+ );
684
+ }
685
+
686
+ function tvc_restoreBackup( fileName, callback ) {
687
+
688
+ jQuery.post(
689
+ myAjaxNonces.ajaxurl,
690
+ {
691
+ action: 'tvcajax-restore-backup-file',
692
+ fileName: fileName,
693
+ restoreBackupNonce: myAjaxNonces.restoreBackupNonce,
694
+
695
+ },
696
+ function( response ) {
697
+
698
+ callback( tvc_validateResponse( response ) );
699
+ }
700
+ );
701
+ }
702
+
703
+ function tvc_duplicateBackup( fileName, callback ) {
704
+
705
+ jQuery.post(
706
+ myAjaxNonces.ajaxurl,
707
+ {
708
+ action: 'tvcajax-duplicate-backup-file',
709
+ fileName: fileName,
710
+ duplicateBackupNonce: myAjaxNonces.duplicateBackupNonce,
711
+
712
+ },
713
+ function( response ) {
714
+
715
+ callback( tvc_validateResponse( response ) );
716
+ }
717
+ );
718
+ }
includes/data/js/tvc_ajaxdatahandling.min.js ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var myAjaxNonces;
2
+
3
+ function tvc_getFeedList(a) {
4
+ jQuery.post(myAjaxNonces.ajaxurl, {
5
+ action: "tvcajax-get-list-of-feeds",
6
+ postFeedsListNonce: myAjaxNonces.postFeedsListNonce
7
+ }, function (b) {
8
+ a(tvc_validateResponse(b))
9
+ })
10
+ }
11
+
12
+ function tvc_getBackupsList(a) {
13
+ jQuery.post(myAjaxNonces.ajaxurl, {
14
+ action: "tvcajax-get-list-of-backups",
15
+ postBackupListNonce: myAjaxNonces.postBackupListNonce
16
+ }, function (b) {
17
+ a(tvc_validateResponse(b))
18
+ })
19
+ }
20
+
21
+ function tvc_getSettingsOptions(a) {
22
+ jQuery.post(myAjaxNonces.ajaxurl, {
23
+ action: "tvcajax-get-settings-options",
24
+ postSetupOptionsNonce: myAjaxNonces.postSetupOptionsNonce
25
+ }, function (b) {
26
+ a(tvc_validateResponse(b))
27
+ })
28
+ }
29
+
30
+ function tvc_getOutputFields(a, b, c) {
31
+ jQuery.post(myAjaxNonces.ajaxurl, {
32
+ action: "tvcajax-get-output-fields",
33
+ feedId: a,
34
+ channelId: b,
35
+ outputFieldsNonce: myAjaxNonces.outputFieldsNonce
36
+ }, function (d) {
37
+ c(tvc_validateResponse(d))
38
+ })
39
+ }
40
+
41
+ function tvc_getSourceFields(a, b) {
42
+ jQuery.post(myAjaxNonces.ajaxurl, {
43
+ action: "tvcajax-get-input-fields",
44
+ sourceId: a,
45
+ inputFieldsNonce: myAjaxNonces.inputFieldsNonce
46
+ }, function (c) {
47
+ b(tvc_validateResponse(c))
48
+ })
49
+ }
50
+
51
+ function tvc_getMainFeedFilters(a, b) {
52
+ jQuery.post(myAjaxNonces.ajaxurl, {
53
+ action: "tvcajax-get-main-feed-filters",
54
+ feedId: a,
55
+ inputFeedFiltersNonce: myAjaxNonces.inputFeedFiltersNonce
56
+ }, function (c) {
57
+ b(tvc_validateResponse(c))
58
+ })
59
+ }
60
+
61
+ function tvc_getNextCategories(c, b, a, e, d) {
62
+ jQuery.post(myAjaxNonces.ajaxurl, {
63
+ action: "tvcajax-get-next-categories",
64
+ channelId: c,
65
+ requestedLevel: b,
66
+ parentCategory: a,
67
+ fileLanguage: e,
68
+ nextCategoryNonce: myAjaxNonces.nextCategoryNonce
69
+ }, function (f) {
70
+ f = f.trim();
71
+ if (f.substr(f.length - 1) === "0") {
72
+ f = f.substring(0, f.length - 1)
73
+ }
74
+ d(tvc_validateResponse(f))
75
+ })
76
+ }
77
+
78
+ function tvc_getCategoryListsFromString(b, a, d, c) {
79
+ jQuery.post(myAjaxNonces.ajaxurl, {
80
+ action: "tvcajax-get-category-lists",
81
+ channelId: b,
82
+ mainCategories: a,
83
+ fileLanguage: d,
84
+ categoryListsNonce: myAjaxNonces.categoryListsNonce
85
+ }, function (e) {
86
+ c(tvc_validateResponse(e))
87
+ })
88
+ }
89
+
90
+ function tvc_updateFeedToDb(b, a, c, d) {
91
+ jQuery.post(myAjaxNonces.ajaxurl, {
92
+ action: "tvcajax-update-feed-data",
93
+ feed: JSON.stringify(b),
94
+ feedFilter: c ? c[0]["meta_value"] : "",
95
+ metaData: JSON.stringify(a),
96
+ updateFeedDataNonce: myAjaxNonces.updateFeedDataNonce
97
+ }, function (e) {
98
+ d(tvc_validateResponse(e))
99
+ })
100
+ }
101
+
102
+ function tvc_updateFeedFile(a, b) {
103
+ jQuery.post(myAjaxNonces.ajaxurl, {
104
+ action: "tvcajax-update-feed-file",
105
+ dataType: "text",
106
+ feedId: a,
107
+ updateFeedFileNonce: myAjaxNonces.updateFeedFileNonce
108
+ }, function (c) {
109
+ b(tvc_validateResponse(c))
110
+ })
111
+ }
112
+
113
+ function tvc_getCurrentFeedStatus(a, b) {
114
+ jQuery.post(myAjaxNonces.ajaxurl, {
115
+ action: "tvcajax-get-feed-status",
116
+ sourceId: a,
117
+ feedStatusNonce: myAjaxNonces.feedStatusNonce
118
+ }, function (c) {
119
+ b(tvc_validateResponse(c))
120
+ })
121
+ }
122
+
123
+ function tvc_getFeedData(a, b) {
124
+ jQuery.post(myAjaxNonces.ajaxurl, {
125
+ action: "tvcajax-get-feed-data",
126
+ sourceId: a,
127
+ feedDataNonce: myAjaxNonces.feedDataNonce
128
+ }, function (c) {
129
+ b(tvc_validateResponse(c))
130
+ })
131
+ }
132
+
133
+ function tvc_switchFeedStatus(a, b) {
134
+ jQuery.post(myAjaxNonces.ajaxurl, {
135
+ action: "tvcajax-switch-feed-status",
136
+ feedId: a,
137
+ switchFeedStatusNonce: myAjaxNonces.switchFeedStatusNonce
138
+ }, function (c) {
139
+ tvc_switchStatusAction(a, c);
140
+ b(tvc_validateResponse(c))
141
+ })
142
+ }
143
+
144
+ function tvc_duplicateExistingFeed(a, b) {
145
+ jQuery.post(myAjaxNonces.ajaxurl, {
146
+ action: "tvcajax-duplicate-existing-feed",
147
+ feedId: a,
148
+ duplicateFeedNonce: myAjaxNonces.duplicateFeedNonce
149
+ }, function (c) {
150
+ if (c.trim()) {
151
+ tvc_resetFeedList()
152
+ }
153
+ b(tvc_validateResponse(c))
154
+ })
155
+ }
156
+
157
+ function tvc_logMessageOnServer(a, c, b) {
158
+ jQuery.post(myAjaxNonces.ajaxurl, {
159
+ action: "tvcajax-log-message",
160
+ messageList: a,
161
+ fileName: c,
162
+ logMessageNonce: myAjaxNonces.logMessageNonce
163
+ }, function (d) {
164
+ b(d.trim())
165
+ })
166
+ }
167
+
168
+ function tvc_auto_feed_fix_mode(a, b) {
169
+ jQuery.post(myAjaxNonces.ajaxurl, {
170
+ action: "tvcajax-auto-feed-fix-mode-selection",
171
+ fix_selection: a,
172
+ updateAutoFeedFixNonce: myAjaxNonces.setAutoFeedFixNonce
173
+ }, function (c) {
174
+ b(c.trim())
175
+ })
176
+ }
177
+
178
+ function tvc_background_processing_mode(a, b) {
179
+ jQuery.post(myAjaxNonces.ajaxurl, {
180
+ action: "tvcajax-background-processing-mode-selection",
181
+ mode_selection: a,
182
+ backgroundModeNonce: myAjaxNonces.setBackgroundModeNonce
183
+ }, function (c) {
184
+ b(c.trim())
185
+ })
186
+ }
187
+
188
+ function tvc_feed_logger_status(a, b) {
189
+ jQuery.post(myAjaxNonces.ajaxurl, {
190
+ action: "tvcajax-feed-logger-status-selection",
191
+ statusSelection: a,
192
+ feedLoggerStatusNonce: myAjaxNonces.setFeedLoggerStatusNonce
193
+ }, function (c) {
194
+ b(c.trim())
195
+ })
196
+ }
197
+
198
+ function tvc_show_pi_status(a, b) {
199
+ jQuery.post(myAjaxNonces.ajaxurl, {
200
+ action: "tvcajax-show-product-identifiers-selection",
201
+ showPiSelection: a,
202
+ showPINonce: myAjaxNonces.setShowPINonce
203
+ }, function (c) {
204
+ b(c.trim())
205
+ })
206
+ }
207
+
208
+ function tvc_change_third_party_attribute_keywords(a, b) {
209
+ jQuery.post(myAjaxNonces.ajaxurl, {
210
+ action: "tvcajax-third-party-attribute-keywords",
211
+ keywords: a,
212
+ thirdPartyKeywordsNonce: myAjaxNonces.setThirdPartyKeywordsNonce
213
+ }, function (c) {
214
+ b(c.trim())
215
+ })
216
+ }
217
+
218
+ function tvc_change_notice_mailaddress(a, b) {
219
+ jQuery.post(myAjaxNonces.ajaxurl, {
220
+ action: "tvcajax-set-notice-mailaddress",
221
+ mailaddress: a,
222
+ noticeMailaddressNonce: myAjaxNonces.setNoticeMailaddressNonce
223
+ }, function (c) {
224
+ b(c.trim())
225
+ })
226
+ }
227
+
228
+ function tvc_change_background_processing_time_limit(a, b) {
229
+ jQuery.post(myAjaxNonces.ajaxurl, {
230
+ action: "tvcajax-background-processing-time-limit",
231
+ limit: a,
232
+ batchProcessingLimitNonce: myAjaxNonces.setBatchProcessingLimitNonce
233
+ }, function (c) {
234
+ b(c.trim())
235
+ })
236
+ }
237
+
238
+ function tvc_clear_feed_process_data(a) {
239
+ jQuery.post(myAjaxNonces.ajaxurl, {
240
+ action: "tvcajax-clear-feed-process-data",
241
+ clearFeedNonce: myAjaxNonces.setClearFeedProcessNonce
242
+ }, function (b) {
243
+ a(b)
244
+ })
245
+ }
246
+
247
+ function tvc_reinitiate_plugin(a) {
248
+ jQuery.post(myAjaxNonces.ajaxurl, {
249
+ action: "tvcajax-reinitiate-plugin",
250
+ reInitiateNonce: myAjaxNonces.setReInitiateNonce
251
+ }, function (b) {
252
+ a(b)
253
+ })
254
+ }
255
+
256
+ function tvc_validateResponse(a) {
257
+ a = a.trim();
258
+ if (a.indexOf("<div id='error'>") < 0 && a.indexOf("<b>Fatal error</b>") < 0 && a.indexOf("<b>Notice</b>") < 0 && a.indexOf("<b>Warning</b>") < 0 && a.indexOf("<b>Catchable fatal error</b>") < 0 && a.indexOf('<div id="error">') < 0) {
259
+ if (a.indexOf("[]") < 0) {
260
+ if (a !== "") {
261
+ return (a)
262
+ } else {
263
+ return ("1")
264
+ }
265
+ } else {
266
+ return ("0")
267
+ }
268
+ } else {
269
+ tvc_show_error_message(a.replace("[]", ""));
270
+ tvc_hideFeedSpinner();
271
+ tvc_logMessageOnServer(a, "error", function (b) {
272
+ return ("0")
273
+ })
274
+ }
275
+ }
276
+
277
+ function tvc_deleteFeed(d, b) {
278
+ var a = jQuery("#feed-spinner");
279
+ var c = jQuery("#feed-list-message");
280
+ c.empty();
281
+ tvc_removeFeedFile(function () {
282
+ a.show();
283
+ tvc_deleteFeedFromDb(d, function (e) {
284
+ a.show();
285
+ e = e.trim();
286
+ if (e === "1") {
287
+ tvc_resetFeedList();
288
+ a.hide()
289
+ } else {
290
+ c.append(e);
291
+ a.hide()
292
+ }
293
+ }, d)
294
+ }, b)
295
+ }
296
+
297
+ function tvc_removeFeedFile(b, a) {
298
+ jQuery.post(myAjaxNonces.ajaxurl, {
299
+ action: "tvcajax-delete-feed-file",
300
+ fileTitle: a,
301
+ deleteFeedNonce: myAjaxNonces.deleteFeedNonce
302
+ }, function (c) {
303
+ b(tvc_validateResponse(c))
304
+ })
305
+ }
306
+
307
+ function tvc_deleteFeedFromDb(a, b) {
308
+ jQuery.post(myAjaxNonces.ajaxurl, {
309
+ action: "tvcajax-delete-feed",
310
+ feedId: a,
311
+ deleteFeedNonce: myAjaxNonces.deleteFeedNonce
312
+ }, function (c) {
313
+ b(tvc_validateResponse(c))
314
+ })
315
+ }
316
+
317
+ function tvc_checkNextFeedInQueue(a) {
318
+ jQuery.post(myAjaxNonces.ajaxurl, {
319
+ action: "tvcajax-get-next-feed-in-queue",
320
+ nextFeedInQueueNonce: myAjaxNonces.nextFeedInQueueNonce
321
+ }, function (b) {
322
+ a(tvc_validateResponse(b))
323
+ })
324
+ }
325
+
326
+ function tvc_initiateBackup(b, a) {
327
+ jQuery.post(myAjaxNonces.ajaxurl, {
328
+ action: "tvcajax-backup-current-data",
329
+ fileName: b,
330
+ backupNonce: myAjaxNonces.backupNonce
331
+ }, function (c) {
332
+ a(tvc_validateResponse(c))
333
+ })
334
+ }
335
+
336
+ function tvc_deleteBackup(b, a) {
337
+ jQuery.post(myAjaxNonces.ajaxurl, {
338
+ action: "tvcajax-delete-backup-file",
339
+ fileName: b,
340
+ deleteBackupNonce: myAjaxNonces.deleteBackupNonce
341
+ }, function (c) {
342
+ a(tvc_validateResponse(c))
343
+ })
344
+ }
345
+
346
+ function tvc_restoreBackup(b, a) {
347
+ jQuery.post(myAjaxNonces.ajaxurl, {
348
+ action: "tvcajax-restore-backup-file",
349
+ fileName: b,
350
+ restoreBackupNonce: myAjaxNonces.restoreBackupNonce
351
+ }, function (c) {
352
+ a(tvc_validateResponse(c))
353
+ })
354
+ }
355
+
356
+ function tvc_duplicateBackup(b, a) {
357
+ jQuery.post(myAjaxNonces.ajaxurl, {
358
+ action: "tvcajax-duplicate-backup-file",
359
+ fileName: b,
360
+ duplicateBackupNonce: myAjaxNonces.duplicateBackupNonce
361
+ }, function (c) {
362
+ a(tvc_validateResponse(c))
363
+ })
364
+ };
includes/data/js/tvc_data.js ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ /**
3
+ * Returns an array with all possible condition options
4
+ *
5
+ * @return {array} An array with possible condition options
6
+ */
7
+ function tvc_queryOptionsEng() {
8
+
9
+ return [
10
+ 'includes', 'does not include', 'is equal to', 'is not equal to', 'is empty', 'is not empty', 'starts with',
11
+ 'does not start with', 'ends with', 'does not end with', 'is greater than', 'is greater or equal to', 'is smaller than',
12
+ 'is smaller or equal to', 'is between'
13
+ ];
14
+ }
15
+
16
+ function tvc_changeValuesOptions() {
17
+
18
+ return [ 'change nothing', 'overwrite', 'replace', 'remove', 'add prefix', 'add suffix', 'recalculate', 'convert to child-element' ];
19
+ }
20
+
21
+ function tvc_changeValuesRecalculateOptions() {
22
+
23
+ return [ 'add', 'subtract', 'multiply', 'divide' ];
24
+ }
25
+
26
+ function tvc_woocommerceSourceOptions() {
27
+
28
+ return [
29
+ {value: '_backorders', label: 'Allow Backorders', prop: 'meta'},
30
+ //{ value: '_button_text', label: 'Button Text', prop: 'meta' },
31
+ //{value:'', label:'Cross-Sells', prop:'meta'},
32
+ {value: '_height', label: 'Dimensions Height', prop: 'meta'},
33
+ {value: '_length', label: 'Dimensions Length', prop: 'meta'},
34
+ {value: '_width', label: 'Dimensions Width', prop: 'meta'},
35
+ {value: '_downloadable', label: 'Downloadable', prop: 'meta'},
36
+ //{value:'', label:'Enable Reviews', prop:'meta'},
37
+ {value: 'attachment_url', label: 'Featured Image', prop: 'main'}, // in the end this item will be handled procedural
38
+ //{value:'', label:'Grouping', prop:'meta'},
39
+ {value: 'item_group_id', label: 'Item Group Id', prop: 'main'},
40
+ {value: '_wp_attachement_metadata', label: 'Image Library', prop: 'main'},
41
+ {value: '_manage_stock', label: 'Manage Stock?', prop: 'meta'},
42
+ {value: '_max_variation_price', label: 'Max Variation Price', prop: 'meta'},
43
+ {value: '_max_variation_regular_price', label: 'Max Variation Regular Price', prop: 'meta'},
44
+ {value: '_max_variation_sale_price', label: 'Max Variation Sale Price', prop: 'meta'},
45
+ {value: 'menu_order', label: 'Menu Order', prop: 'meta'},
46
+ {value: '_min_variation_price', label: 'Min Variation Price', prop: 'meta'},
47
+ {value: '_min_variation_regular_price', label: 'Min Variation Regular Price', prop: 'meta'},
48
+ {value: '_min_variation_sale_price', label: 'Min Variation Sale Price', prop: 'meta'},
49
+ {value: 'post_author', label: 'Post Author', prop: 'post'},
50
+ {value: 'post_date', label: 'Post Date', prop: 'post'},
51
+ {value: 'post_date_gmt', label: 'Post Date GMT', prop: 'post'},
52
+ {value: 'ID', label: 'Post ID', prop: 'post'},
53
+ {value: 'post_modified', label: 'Post Modified', prop: 'post'},
54
+ {value: 'post_modified_gmt', label: 'Post Modified GMT', prop: 'post'},
55
+ {value: 'product_cat_string', label: 'Product Category String', prop: 'main'},
56
+ {value: 'post_content', label: 'Product Description', prop: 'post'},
57
+ {value: 'post_excerpt', label: 'Product Short Description', prop: 'post'},
58
+ {value: 'product_tags', label: 'Product Tags', prop: 'meta'},
59
+ {value: 'post_title', label: 'Product Title', prop: 'post'},
60
+ {value: 'tvc_product_brand', label: 'Product brand', prop: 'meta'},
61
+ {value: 'tvc_product_gtin', label: 'Product GTIN', prop: 'meta'},
62
+ {value: 'tvc_product_mpn', label: 'Product MPN', prop: 'meta'},
63
+ {value: 'product_variation_title_without_attributes', label: 'Product Title Without Variable Attributes', prop: 'meta'},
64
+ {value: 'product_type', label: 'Product Type', prop: 'meta'},
65
+ {value: 'permalink', label: 'Permalink', prop: 'post'},
66
+ //{value:'', label:'Purchase Note', prop:'meta'},
67
+ {value: '_regular_price', label: 'Regular Price', prop: 'meta'},
68
+ {value: '_sale_price', label: 'Sale Price', prop: 'meta'},
69
+ {value: '_sale_price_dates_from', label: 'Sale Price Dates From', prop: 'meta'},
70
+ {value: '_sale_price_dates_to', label: 'Sale Price Dates To', prop: 'meta'},
71
+ {value: 'product_cat', label: 'Selected Product Categories', prop: 'main'},
72
+ {value: 'fixed_shipping_price', label: 'Fixed Shipping Price', prop: 'main'},
73
+ {value: 'shipping_class', label: 'Shipping Class', prop: 'main'},
74
+ {value: '_sku', label: 'SKU', prop: 'meta'},
75
+ {value: '_sold_individually', label: 'Sold Individually', prop: 'meta'},
76
+ {value: '_stock', label: 'Stock Qty', prop: 'meta'},
77
+ {value: '_stock_status', label: 'Stock Status', prop: 'meta'},
78
+ {value: '_tax_status', label: 'Tax Status', prop: 'meta'},
79
+ {value: '_tax_class', label: 'Tax Class', prop: 'meta'},
80
+ //{value:'', label:'Up-Sells', prop:'meta'},
81
+ {value: '_virtual', label: 'Virtual', prop: 'meta'},
82
+ {value: '_weight', label: 'Weight', prop: 'meta'},
83
+ {value: 'wc_currency', label: 'WooCommerce Currency', prop: 'main'},
84
+ {value: 'last_update', label: 'Last Feed Update', prop: 'main'},
85
+ {value: 'empty', label: 'Remove from feed', prop: 'meta'},
86
+ ];
87
+ }
88
+
89
+ function tvc_sourceOptionsConverter( optionValue ) {
90
+
91
+ var list = tvc_woocommerceSourceOptions();
92
+
93
+ for ( var key in list ) {
94
+
95
+ if ( list[ key ][ 'value' ] === optionValue ) {
96
+ return list[ key ][ 'label' ];
97
+ break;
98
+ }
99
+ }
100
+ }
101
+
102
+ function tvc_validateUrl( url ) {
103
+ var pattern = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
104
+ return ! ! pattern.test( url );
105
+ }
includes/data/js/tvc_data.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function tvc_queryOptionsEng(){return["includes","does not include","is equal to","is not equal to","is empty","is not empty","starts with","does not start with","ends with","does not end with","is greater than","is greater or equal to","is smaller than","is smaller or equal to","is between"]}function tvc_changeValuesOptions(){return["change nothing","overwrite","replace","remove","add prefix","add suffix","recalculate","convert to child-element"]}function tvc_changeValuesRecalculateOptions(){return["add","subtract","multiply","divide"]}function tvc_woocommerceSourceOptions(){return[{value:"_backorders",label:"Allow Backorders",prop:"meta"},{value:"_height",label:"Dimensions Height",prop:"meta"},{value:"_length",label:"Dimensions Length",prop:"meta"},{value:"_width",label:"Dimensions Width",prop:"meta"},{value:"_downloadable",label:"Downloadable",prop:"meta"},{value:"attachment_url",label:"Featured Image",prop:"main"},{value:"item_group_id",label:"Item Group Id",prop:"main"},{value:"_wp_attachement_metadata",label:"Image Library",prop:"main"},{value:"_manage_stock",label:"Manage Stock?",prop:"meta"},{value:"_max_variation_price",label:"Max Variation Price",prop:"meta"},{value:"_max_variation_regular_price",label:"Max Variation Regular Price",prop:"meta"},{value:"_max_variation_sale_price",label:"Max Variation Sale Price",prop:"meta"},{value:"menu_order",label:"Menu Order",prop:"meta"},{value:"_min_variation_price",label:"Min Variation Price",prop:"meta"},{value:"_min_variation_regular_price",label:"Min Variation Regular Price",prop:"meta"},{value:"_min_variation_sale_price",label:"Min Variation Sale Price",prop:"meta"},{value:"post_author",label:"Post Author",prop:"post"},{value:"post_date",label:"Post Date",prop:"post"},{value:"post_date_gmt",label:"Post Date GMT",prop:"post"},{value:"ID",label:"Post ID",prop:"post"},{value:"post_modified",label:"Post Modified",prop:"post"},{value:"post_modified_gmt",label:"Post Modified GMT",prop:"post"},{value:"product_cat_string",label:"Product Category String",prop:"main"},{value:"post_content",label:"Product Description",prop:"post"},{value:"post_excerpt",label:"Product Short Description",prop:"post"},{value:"product_tags",label:"Product Tags",prop:"meta"},{value:"post_title",label:"Product Title",prop:"post"},{value:"tvc_product_brand",label:"Product brand",prop:"meta"},{value:"tvc_product_gtin",label:"Product GTIN",prop:"meta"},{value:"tvc_product_mpn",label:"Product MPN",prop:"meta"},{value:"product_variation_title_without_attributes",label:"Product Title Without Variable Attributes",prop:"meta"},{value:"product_type",label:"Product Type",prop:"meta"},{value:"permalink",label:"Permalink",prop:"post"},{value:"_regular_price",label:"Regular Price",prop:"meta"},{value:"_sale_price",label:"Sale Price",prop:"meta"},{value:"_sale_price_dates_from",label:"Sale Price Dates From",prop:"meta"},{value:"_sale_price_dates_to",label:"Sale Price Dates To",prop:"meta"},{value:"product_cat",label:"Selected Product Categories",prop:"main"},{value:"fixed_shipping_price",label:"Fixed Shipping Price",prop:"main"},{value:"shipping_class",label:"Shipping Class",prop:"main"},{value:"_sku",label:"SKU",prop:"meta"},{value:"_sold_individually",label:"Sold Individually",prop:"meta"},{value:"_stock",label:"Stock Qty",prop:"meta"},{value:"_stock_status",label:"Stock Status",prop:"meta"},{value:"_tax_status",label:"Tax Status",prop:"meta"},{value:"_tax_class",label:"Tax Class",prop:"meta"},{value:"_virtual",label:"Virtual",prop:"meta"},{value:"_weight",label:"Weight",prop:"meta"},{value:"wc_currency",label:"WooCommerce Currency",prop:"main"},{value:"last_update",label:"Last Feed Update",prop:"main"},{value:"empty",label:"Remove from feed",prop:"meta"}]}function tvc_sourceOptionsConverter(c){var b=tvc_woocommerceSourceOptions();for(var a in b){if(b[a]["value"]===c){return b[a]["label"];break}}}function tvc_validateUrl(a){var b=/^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;return !!b.test(a)};
includes/data/js/tvc_feed-queue-string.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ function tvcAddToQueueString( idToAdd ) {
3
+ var listElement = jQuery( '#tvc-feed-list-feeds-in-queue' );
4
+
5
+ if ( tvcQueueStringIsEmpty() ) {
6
+ listElement.text( idToAdd );
7
+ } else {
8
+ listElement.text( listElement.text() + ',' + idToAdd );
9
+ }
10
+ }
11
+
12
+ function tvcRemoveFromQueueString( idToRemove ) {
13
+ var listElement = jQuery( '#tvc-feed-list-feeds-in-queue' );
14
+ var currentString = listElement.text();
15
+
16
+ if ( currentString.indexOf( ',' ) > -1 ) {
17
+ currentString = currentString.endsWith( idToRemove ) ? currentString.replace( idToRemove, '' ) : currentString.replace( idToRemove + ',', '' );
18
+ listElement.text( currentString );
19
+ } else {
20
+ tvcClearQueueString();
21
+ }
22
+ }
23
+
24
+ function tvcQueueStringIsEmpty() {
25
+ return jQuery( '#tvc-feed-list-feeds-in-queue' ).text().length < 1;
26
+ }
27
+
28
+ function tvcClearQueueString() {
29
+ jQuery( '#tvc-feed-list-feeds-in-queue' ).text( '' );
30
+ }
includes/data/js/tvc_feed-queue-string.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function tvcAddToQueueString(b){var a=jQuery("#tvc-feed-list-feeds-in-queue");if(tvcQueueStringIsEmpty()){a.text(b)}else{a.text(a.text()+","+b)}}function tvcRemoveFromQueueString(a){var c=jQuery("#tvc-feed-list-feeds-in-queue");var b=c.text();if(b.indexOf(",")>-1){b=b.endsWith(a)?b.replace(a,""):b.replace(a+",","");c.text(b)}else{tvcClearQueueString()}}function tvcQueueStringIsEmpty(){return jQuery("#tvc-feed-list-feeds-in-queue").text().length<1}function tvcClearQueueString(){jQuery("#tvc-feed-list-feeds-in-queue").text("")};
includes/data/js/tvc_metadatahandling.js ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ "use strict";
3
+ function tvc_storeSourceValue( level, currentMetaValue, type, valueToStore ) {
4
+
5
+ console.log( 'level:', level );
6
+ console.log( 'currentMetaValue:', currentMetaValue );
7
+ console.log( 'type:', type );
8
+ console.log( 'valueToStore:', valueToStore );
9
+
10
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
11
+
12
+ if ( o && 't' in o ) {
13
+ return currentMetaValue;
14
+ } // do not change the meta value if it contains the main category
15
+
16
+ if ( valueToStore && type !== 'clear' ) {
17
+
18
+ var t = {}, s = {};
19
+
20
+ s[ type ] = valueToStore;
21
+
22
+ t.s = s;
23
+
24
+ if ( o.hasOwnProperty( 'm' ) ) {
25
+
26
+ if ( ! o.m[ level ] ) {
27
+
28
+ o.m[ level ] = t;
29
+ } else {
30
+
31
+ o.m[ level ].s = s;
32
+ }
33
+ } else {
34
+ var m = [];
35
+
36
+ m.push( t );
37
+ o.m = m;
38
+ }
39
+ } else if ( type === 'clear' ) {
40
+
41
+ if ( o.hasOwnProperty( 'm' ) ) {
42
+
43
+ if ( o.m.length > 1 ) {
44
+
45
+ if ( ! o.m[ level ].c ) {
46
+
47
+ o.m.splice( level, 1 );
48
+ } else {
49
+
50
+ delete o.m[ level ].s;
51
+ }
52
+ } else {
53
+
54
+ delete o.m;
55
+ }
56
+ } else {
57
+
58
+ o = {};
59
+ }
60
+ }
61
+
62
+ var newValue = typeof (
63
+ o
64
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
65
+
66
+ console.log( 'result:', newValue );
67
+ return newValue;
68
+ }
69
+
70
+ function tvc_storeConditionValue( sourceLevel, conditionLevel, currentMetaValue, newCondition ) {
71
+
72
+ console.log( 'sourceLevel:', sourceLevel );
73
+ console.log( 'conditionLevel:', conditionLevel );
74
+ console.log( 'currentMetaValue:', currentMetaValue );
75
+ console.log( 'newCondition:', newCondition );
76
+
77
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
78
+ var conditionPos = conditionLevel - 1;
79
+ var t = {};
80
+ var q = {};
81
+
82
+ if ( newCondition ) {
83
+
84
+ if ( ! o.hasOwnProperty( 'm' ) ) {
85
+
86
+ var m = [];
87
+
88
+ m.push( t );
89
+ o.m = m;
90
+ }
91
+
92
+ if ( o.m[ sourceLevel ] && o.m[ sourceLevel ].hasOwnProperty( 'c' ) ) {
93
+
94
+ q[ conditionLevel ] = newCondition;
95
+
96
+ if ( o.m[ sourceLevel ].c.hasOwnProperty( conditionPos ) ) {
97
+
98
+ o.m[ sourceLevel ].c[ conditionPos ] = q;
99
+ } else {
100
+
101
+ o.m[ sourceLevel ].c.push( q );
102
+ }
103
+ } else {
104
+
105
+ var c = [];
106
+
107
+ q[ conditionLevel ] = newCondition;
108
+
109
+ c.push( q );
110
+
111
+ t.c = c;
112
+
113
+ o.m[ sourceLevel ].c = c;
114
+ }
115
+ }
116
+
117
+ var newValue = typeof (
118
+ o
119
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
120
+
121
+ console.log( 'result:', newValue );
122
+ return newValue;
123
+ }
124
+
125
+ function tvc_storeCombinedValue( sourceLevel, currentMetaValue, valueToStore ) {
126
+
127
+ console.log( 'sourceLevel:', sourceLevel );
128
+ console.log( 'currentMetaValue:', currentMetaValue );
129
+ console.log( 'valueToStore:', valueToStore );
130
+
131
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
132
+
133
+ if ( valueToStore ) {
134
+
135
+ var m = [], t = {}, s = {};
136
+
137
+ if ( ! o.hasOwnProperty( 'm' ) ) {
138
+
139
+ m.push( t );
140
+ o.m = m;
141
+ }
142
+
143
+ if ( ! o.m[ sourceLevel ].hasOwnProperty( 's' ) ) {
144
+
145
+ s[ 'source' ] = 'combined';
146
+ o.m[ sourceLevel ].s = s;
147
+ }
148
+
149
+ o.m[ sourceLevel ].s.f = valueToStore;
150
+ }
151
+
152
+ var newValue = typeof (
153
+ o
154
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
155
+
156
+ console.log( 'result:', newValue );
157
+
158
+ return newValue;
159
+ }
160
+
161
+ function tvc_storeValueChange( sourceLevel, valueEditorLevel, valueToStore, action, currentMetaValue ) {
162
+
163
+ console.log( 'sourceLevel:', sourceLevel );
164
+ console.log( 'valueEditorLevel:', valueEditorLevel );
165
+ console.log( 'valueToStore:', valueToStore );
166
+ console.log( 'action:', action );
167
+ console.log( 'currentMetaValue:', currentMetaValue );
168
+
169
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
170
+ var t = {};
171
+
172
+ if ( valueToStore && action === 'add' ) {
173
+
174
+ t[ sourceLevel + 1 ] = valueToStore;
175
+
176
+ if ( o.hasOwnProperty( 'v' ) ) {
177
+
178
+ if ( o.v[ sourceLevel ] && o.v[ sourceLevel ].hasOwnProperty( 'q' ) ) {
179
+
180
+ o.v[ sourceLevel ][ valueEditorLevel + 1 ] = valueToStore;
181
+ } else {
182
+
183
+ o.v[ sourceLevel ] = t;
184
+ }
185
+ } else {
186
+
187
+ var v = [];
188
+
189
+ v.push( t );
190
+ o.v = v;
191
+ }
192
+ } else if ( action === 'clear' ) {
193
+
194
+ if ( 'v' in o ) {
195
+
196
+ if ( o.v.length > 1 ) {
197
+
198
+ if ( ! o.v[ sourceLevel ].q ) {
199
+
200
+ o.v.splice( sourceLevel, 1 );
201
+ } else {
202
+
203
+ delete o.v[ sourceLevel ].s;
204
+ }
205
+ } else {
206
+
207
+ delete o.v;
208
+ }
209
+ } else {
210
+
211
+ o = {};
212
+ }
213
+ }
214
+
215
+ var newValue = typeof (
216
+ o
217
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
218
+
219
+ console.log( 'result:', newValue );
220
+
221
+ return newValue;
222
+ }
223
+
224
+ function tvc_removeCombinedValue( sourceLevel, combinedLevel, currentMetaValue ) {
225
+
226
+ console.log( 'sourceLevel:', sourceLevel );
227
+ console.log( 'combinedLevel:', combinedLevel );
228
+ console.log( 'currentMetaValue:', currentMetaValue );
229
+
230
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
231
+
232
+ if ( o.hasOwnProperty( 'm' ) && o.m[ sourceLevel ].hasOwnProperty( 's' ) && o.m[ sourceLevel ].s.hasOwnProperty( 'f' ) ) {
233
+
234
+ if ( o.m[ sourceLevel ].s.f ) {
235
+
236
+ var combinedValues = o.m[ sourceLevel ].s.f.split( '|' );
237
+
238
+ combinedValues.splice( combinedLevel - 1, 1 );
239
+
240
+ o.m[ sourceLevel ].s.f = tvc_makeCombinedValuesStringFromArray( combinedValues );
241
+ }
242
+ }
243
+
244
+ var newValue = typeof (
245
+ o
246
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
247
+
248
+ console.log( 'result:', newValue );
249
+
250
+ return newValue;
251
+ }
252
+
253
+ function tvc_removeConditionValue( sourceLevel, conditionLevel, currentMetaValue ) {
254
+
255
+ console.log( 'sourceLevel:', sourceLevel );
256
+ console.log( 'conditionLevel:', conditionLevel );
257
+ console.log( 'currentMetaValue:', currentMetaValue );
258
+
259
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
260
+ var coi = null;
261
+
262
+ if ( o && o.hasOwnProperty( 'm' ) && o.m[ sourceLevel ] && o.m[ sourceLevel ].hasOwnProperty( 'c' ) ) {
263
+
264
+ if ( o.m[ sourceLevel ].c[ conditionLevel ] ) {
265
+
266
+ if ( o.m[ sourceLevel ].c.length > 1 ) {
267
+
268
+ // remove the correct condition
269
+ o.m[ sourceLevel ].c.splice( conditionLevel, 1 );
270
+
271
+ // and resort the remaining conditions
272
+ o.m[ sourceLevel ].c = tvc_resortObject( o.m[ sourceLevel ].c );
273
+ } else {
274
+
275
+ // check what is left in the mapping part
276
+ coi = tvc_countObjectItems( o.m );
277
+
278
+ if ( coi > 2 ) {
279
+
280
+ o.m.splice( [ sourceLevel ], 1 );
281
+ } else {
282
+
283
+ if ( coi < 1 ) {
284
+
285
+ if ( o.hasOwnProperty( 'v' ) ) {
286
+
287
+ // when the object also has a v element only remove the m element
288
+ delete o.m[ sourceLevel ];
289
+ } else {
290
+
291
+ // but when the object only has an m element then empty the object
292
+ o = {};
293
+ }
294
+ } else {
295
+
296
+ if ( o.m[ sourceLevel ].hasOwnProperty( 's' ) ) {
297
+
298
+ // remove the condition
299
+ delete o.m[ sourceLevel ].c;
300
+
301
+ // and remove the source that was selected as the condition would be met
302
+ o.m.splice( [ sourceLevel + 1 ], 1 );
303
+ } else {
304
+
305
+ if ( o.hasOwnProperty( 'v' ) ) {
306
+
307
+ // when the object also has a v element only remove the m element
308
+ delete o.m[ sourceLevel ];
309
+ } else {
310
+
311
+ // but when the object only has an m element then empty the object
312
+ o = {};
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
319
+ } else if ( o && o.hasOwnProperty( 'm' ) && o.m[ sourceLevel ] && o.m[ sourceLevel ].hasOwnProperty( 's' ) ) {
320
+
321
+ coi = tvc_countObjectItems( o.m );
322
+
323
+ if ( coi > 1 ) {
324
+
325
+ o.m.splice( [ sourceLevel ], 1 );
326
+ } else {
327
+
328
+ if ( o.hasOwnProperty( 'v' ) ) {
329
+
330
+ // when the object also has a v element only remove the m element
331
+ delete o.m[ sourceLevel ];
332
+ } else {
333
+
334
+ // but when the object only has an m element then empty the object
335
+ o = {};
336
+ }
337
+ }
338
+ }
339
+
340
+ var newValue = typeof (
341
+ o
342
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
343
+
344
+ console.log( 'result:', newValue );
345
+
346
+ return newValue;
347
+ }
348
+
349
+ function tvc_removeQueryValue( sourceLevel, conditionLevel, currentMetaValue ) {
350
+
351
+ console.log( 'sourceLevel:', sourceLevel );
352
+ console.log( 'conditionLevel:', conditionLevel );
353
+ console.log( 'currentMetaValue:', currentMetaValue );
354
+
355
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
356
+
357
+ if ( o && o.hasOwnProperty( 'v' ) && o.v[ sourceLevel ] && o.v[ sourceLevel ].hasOwnProperty( 'q' ) ) {
358
+
359
+ if ( o.v[ sourceLevel ].q[ conditionLevel - 1 ] ) {
360
+
361
+ if ( o.v[ sourceLevel ].q.length > 1 ) {
362
+
363
+ // remove the correct condition
364
+ o.v[ sourceLevel ].q.splice( ( conditionLevel - 1 ), 1 );
365
+
366
+ // and resort the remaining conditions
367
+ o.v[ sourceLevel ].q = tvc_resortObject( o.v[ sourceLevel ].q );
368
+ } else {
369
+
370
+ // check what is left in the mapping part
371
+ var coi = tvc_countObjectItems( o.v );
372
+
373
+ if ( coi > 2 ) {
374
+
375
+ o.v.splice( [ sourceLevel ], 1 );
376
+ } else {
377
+
378
+ if ( coi < 1 ) {
379
+
380
+ if ( o.hasOwnProperty( 'm' ) ) {
381
+
382
+ // when the object also has an m element only remove the v element
383
+ delete o.v[ sourceLevel ];
384
+ } else {
385
+
386
+ // but when the object only has a v element then empty the object
387
+ o = {};
388
+ }
389
+ } else {
390
+
391
+ if ( o.v[ sourceLevel ].hasOwnProperty( '1' ) ) {
392
+
393
+ // remove the condition
394
+ delete o.v[ sourceLevel ].q;
395
+ } else {
396
+
397
+ if ( o.hasOwnProperty( 'm' ) ) {
398
+
399
+ // when the object also has an m element only remove the v element
400
+ delete o.v[ sourceLevel ];
401
+ } else {
402
+
403
+ // but when the object only has an m element then empty the object
404
+ o = {};
405
+ }
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ }
412
+
413
+ var newValue = typeof (
414
+ o
415
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
416
+
417
+ console.log( 'result:', newValue );
418
+
419
+ return newValue;
420
+ }
421
+
422
+ function tvc_removeEditValuesValue( sourceLevel, valueEditorLevel, currentMetaValue ) {
423
+
424
+ console.log( 'sourceLevel:', sourceLevel );
425
+ console.log( 'valueEditorLevel:', valueEditorLevel );
426
+ console.log( 'currentMetaValue:', currentMetaValue );
427
+
428
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
429
+
430
+ if ( 'v' in o ) {
431
+
432
+ if ( o.v.length > 1 ) {
433
+
434
+ o.v.splice( sourceLevel, 1 );
435
+ } else {
436
+
437
+ delete o.v;
438
+ }
439
+ } else {
440
+
441
+ o = {};
442
+ }
443
+
444
+ var newValue = typeof (
445
+ o
446
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
447
+
448
+ console.log( 'result:', newValue );
449
+
450
+ return newValue;
451
+
452
+ }
453
+
454
+ function tvc_storeQueryValue( sourceLevel, queryLevel, currentMetaValue, newQuery ) {
455
+
456
+ console.log( 'sourceLevel:', sourceLevel );
457
+ console.log( 'queryLevel:', queryLevel );
458
+ console.log( 'currentMetaValue:', currentMetaValue );
459
+ console.log( 'newQuery:', newQuery );
460
+
461
+ var o = currentMetaValue ? JSON.parse( currentMetaValue ) : {};
462
+ var conditionPos = queryLevel - 1;
463
+ var t = {};
464
+ var vq = {};
465
+
466
+ if ( newQuery ) {
467
+
468
+ if ( ! o.hasOwnProperty( 'v' ) ) {
469
+
470
+ var v = [];
471
+
472
+ v.push( t );
473
+ o.v = v;
474
+ }
475
+
476
+ if ( o.v[ sourceLevel ] && o.v[ sourceLevel ].hasOwnProperty( 'q' ) ) {
477
+
478
+ vq[ queryLevel ] = newQuery;
479
+
480
+ if ( o.v[ sourceLevel ].q.hasOwnProperty( conditionPos ) ) {
481
+
482
+ o.v[ sourceLevel ].q[ conditionPos ] = vq;
483
+ } else {
484
+
485
+ o.v[ sourceLevel ].q.push( vq );
486
+ }
487
+ } else {
488
+
489
+ var q = [];
490
+
491
+ vq[ queryLevel ] = newQuery;
492
+
493
+ q.push( vq );
494
+
495
+ t.q = q;
496
+
497
+ o.v[ sourceLevel ].q = q;
498
+ }
499
+ }
500
+
501
+ var newValue = typeof (
502
+ o
503
+ ) && ! jQuery.isEmptyObject( o ) ? JSON.stringify( o ) : '';
504
+
505
+ console.log( 'result:', newValue );
506
+ return newValue;
507
+ }
508
+
509
+ function tvc_makeCombinedValuesStringFromArray( combinedValuesArray ) {
510
+
511
+ var combinedValuesString = '';
512
+
513
+ for ( var i = 0; i < combinedValuesArray.length; i ++ ) {
514
+
515
+ combinedValuesString += combinedValuesArray[ i ];
516
+ combinedValuesString += i < (
517
+ combinedValuesArray.length - 1
518
+ ) ? '|' : '';
519
+ }
520
+
521
+ return combinedValuesString;
522
+ }
523
+
524
+ function changeFeedFilterValue( workValue, newValues, changedFilterLevel ) {
525
+
526
+ console.log( 'workValue:', workValue );
527
+ console.log( 'newValues:', newValues );
528
+ console.log( 'changedFilterLevel:', changedFilterLevel );
529
+
530
+ var filterObject = [];
531
+
532
+ if ( workValue ) {
533
+ filterObject = JSON.parse( workValue[ 0 ][ 'meta_value' ] );
534
+ } else {
535
+ filterObject = [];
536
+
537
+ workValue = []; // build a new empty workValue
538
+ var m = {'meta_value': ''};
539
+ workValue.push( m );
540
+ }
541
+
542
+ var nrFilters = filterObject.length;
543
+
544
+ var newValueString = newValues[ 0 ] + '#' + newValues[ 1 ] + '#' + newValues[ 2 ];
545
+ newValueString += newValues[ 2 ] !== '4' && newValues[ 2 ] !== '5' ? '#' + newValues[ 3 ] : '';
546
+
547
+ if ( changedFilterLevel <= nrFilters ) {
548
+ filterObject[ changedFilterLevel - 1 ][ changedFilterLevel ] = newValueString;
549
+ } else {
550
+
551
+ var n = {};
552
+
553
+ n[ changedFilterLevel ] = newValueString;
554
+ //filterObject.push( n );
555
+ filterObject[ changedFilterLevel - 1 ] = n;
556
+ }
557
+
558
+ workValue[ 0 ][ 'meta_value' ] = JSON.stringify( filterObject );
559
+
560
+ console.log( 'result:', JSON.stringify( workValue ) );
561
+
562
+ return workValue;
563
+ }
564
+
565
+ function removeFeedFilterLevel( workValue, levelToRemove ) {
566
+
567
+ console.log( 'workValue:', workValue );
568
+ console.log( 'levelToRemove:', levelToRemove );
569
+
570
+ var filterObject = workValue ? JSON.parse( workValue[ 0 ][ 'meta_value' ] ) : {};
571
+ var returnFilterObject = [];
572
+ var i = 0;
573
+
574
+ for ( var key in filterObject ) {
575
+
576
+ if ( parseInt( key ) !== levelToRemove - 1 ) {
577
+
578
+ var v = {};
579
+ v[ i + 1 ] = filterObject[ key ][ parseInt( key ) + 1 ];
580
+
581
+ returnFilterObject[ i ] = v;
582
+
583
+ i ++;
584
+ }
585
+ }
586
+
587
+ if ( returnFilterObject.length > 0 ) {
588
+ workValue[ 0 ][ 'meta_value' ] = JSON.stringify( returnFilterObject );
589
+ console.log( 'result:', JSON.stringify( workValue ) );
590
+ } else {
591
+ workValue = '';
592
+ console.log( 'result:', workValue );
593
+ }
594
+
595
+ return workValue;
596
+ }
includes/data/js/tvc_metadatahandling.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function tvc_storeSourceValue(a,b,g,c){console.log("level:",a);console.log("currentMetaValue:",b);console.log("type:",g);console.log("valueToStore:",c);var e=b?JSON.parse(b):{};if(e&&"t" in e){return b}if(c&&g!=="clear"){var h={},i={};i[g]=c;h.s=i;if(e.hasOwnProperty("m")){if(!e.m[a]){e.m[a]=h}else{e.m[a].s=i}}else{var f=[];f.push(h);e.m=f}}else{if(g==="clear"){if(e.hasOwnProperty("m")){if(e.m.length>1){if(!e.m[a].c){e.m.splice(a,1)}else{delete e.m[a].s}}else{delete e.m}}else{e={}}}}var d=typeof(e)&&!jQuery.isEmptyObject(e)?JSON.stringify(e):"";console.log("result:",d);return d}function tvc_storeConditionValue(a,l,d,g){console.log("sourceLevel:",a);console.log("conditionLevel:",l);console.log("currentMetaValue:",d);console.log("newCondition:",g);var f=d?JSON.parse(d):{};var j=l-1;var k={};var b={};if(g){if(!f.hasOwnProperty("m")){var h=[];h.push(k);f.m=h}if(f.m[a]&&f.m[a].hasOwnProperty("c")){b[l]=g;if(f.m[a].c.hasOwnProperty(j)){f.m[a].c[j]=b}else{f.m[a].c.push(b)}}else{var i=[];b[l]=g;i.push(b);k.c=i;f.m[a].c=i}}var e=typeof(f)&&!jQuery.isEmptyObject(f)?JSON.stringify(f):"";console.log("result:",e);return e}function tvc_storeCombinedValue(f,c,b){console.log("sourceLevel:",f);console.log("currentMetaValue:",c);console.log("valueToStore:",b);var h=c?JSON.parse(c):{};if(b){var a=[],d={},e={};if(!h.hasOwnProperty("m")){a.push(d);h.m=a}if(!h.m[f].hasOwnProperty("s")){e.source="combined";h.m[f].s=e}h.m[f].s.f=b}var g=typeof(h)&&!jQuery.isEmptyObject(h)?JSON.stringify(h):"";console.log("result:",g);return g}function tvc_storeValueChange(a,g,b,f,c){console.log("sourceLevel:",a);console.log("valueEditorLevel:",g);console.log("valueToStore:",b);console.log("action:",f);console.log("currentMetaValue:",c);var e=c?JSON.parse(c):{};var i={};if(b&&f==="add"){i[a+1]=b;if(e.hasOwnProperty("v")){if(e.v[a]&&e.v[a].hasOwnProperty("q")){e.v[a][g+1]=b}else{e.v[a]=i}}else{var h=[];h.push(i);e.v=h}}else{if(f==="clear"){if("v" in e){if(e.v.length>1){if(!e.v[a].q){e.v.splice(a,1)}else{delete e.v[a].s}}else{delete e.v}}else{e={}}}}var d=typeof(e)&&!jQuery.isEmptyObject(e)?JSON.stringify(e):"";console.log("result:",d);return d}function tvc_removeCombinedValue(d,c,a){console.log("sourceLevel:",d);console.log("combinedLevel:",c);console.log("currentMetaValue:",a);var f=a?JSON.parse(a):{};if(f.hasOwnProperty("m")&&f.m[d].hasOwnProperty("s")&&f.m[d].s.hasOwnProperty("f")){if(f.m[d].s.f){var b=f.m[d].s.f.split("|");b.splice(c-1,1);f.m[d].s.f=tvc_makeCombinedValuesStringFromArray(b)}}var e=typeof(f)&&!jQuery.isEmptyObject(f)?JSON.stringify(f):"";console.log("result:",e);return e}function tvc_removeConditionValue(d,b,a){console.log("sourceLevel:",d);console.log("conditionLevel:",b);console.log("currentMetaValue:",a);var f=a?JSON.parse(a):{};var c=null;if(f&&f.hasOwnProperty("m")&&f.m[d]&&f.m[d].hasOwnProperty("c")){if(f.m[d].c[b]){if(f.m[d].c.length>1){f.m[d].c.splice(b,1);f.m[d].c=tvc_resortObject(f.m[d].c)}else{c=tvc_countObjectItems(f.m);if(c>2){f.m.splice([d],1)}else{if(c<1){if(f.hasOwnProperty("v")){delete f.m[d]}else{f={}}}else{if(f.m[d].hasOwnProperty("s")){delete f.m[d].c;f.m.splice([d+1],1)}else{if(f.hasOwnProperty("v")){delete f.m[d]}else{f={}}}}}}}}else{if(f&&f.hasOwnProperty("m")&&f.m[d]&&f.m[d].hasOwnProperty("s")){c=tvc_countObjectItems(f.m);if(c>1){f.m.splice([d],1)}else{if(f.hasOwnProperty("v")){delete f.m[d]}else{f={}}}}}var e=typeof(f)&&!jQuery.isEmptyObject(f)?JSON.stringify(f):"";console.log("result:",e);return e}function tvc_removeQueryValue(d,b,a){console.log("sourceLevel:",d);console.log("conditionLevel:",b);console.log("currentMetaValue:",a);var f=a?JSON.parse(a):{};if(f&&f.hasOwnProperty("v")&&f.v[d]&&f.v[d].hasOwnProperty("q")){if(f.v[d].q[b-1]){if(f.v[d].q.length>1){f.v[d].q.splice((b-1),1);f.v[d].q=tvc_resortObject(f.v[d].q)}else{var c=tvc_countObjectItems(f.v);if(c>2){f.v.splice([d],1)}else{if(c<1){if(f.hasOwnProperty("m")){delete f.v[d]}else{f={}}}else{if(f.v[d].hasOwnProperty("1")){delete f.v[d].q}else{if(f.hasOwnProperty("m")){delete f.v[d]}else{f={}}}}}}}}var e=typeof(f)&&!jQuery.isEmptyObject(f)?JSON.stringify(f):"";console.log("result:",e);return e}function tvc_removeEditValuesValue(b,e,a){console.log("sourceLevel:",b);console.log("valueEditorLevel:",e);console.log("currentMetaValue:",a);var d=a?JSON.parse(a):{};if("v" in d){if(d.v.length>1){d.v.splice(b,1)}else{delete d.v}}else{d={}}var c=typeof(d)&&!jQuery.isEmptyObject(d)?JSON.stringify(d):"";console.log("result:",c);return c}function tvc_storeQueryValue(c,g,d,k){console.log("sourceLevel:",c);console.log("queryLevel:",g);console.log("currentMetaValue:",d);console.log("newQuery:",k);var f=d?JSON.parse(d):{};var h=g-1;var j={};var a={};if(k){if(!f.hasOwnProperty("v")){var i=[];i.push(j);f.v=i}if(f.v[c]&&f.v[c].hasOwnProperty("q")){a[g]=k;if(f.v[c].q.hasOwnProperty(h)){f.v[c].q[h]=a}else{f.v[c].q.push(a)}}else{var b=[];a[g]=k;b.push(a);j.q=b;f.v[c].q=b}}var e=typeof(f)&&!jQuery.isEmptyObject(f)?JSON.stringify(f):"";console.log("result:",e);return e}function tvc_makeCombinedValuesStringFromArray(b){var a="";for(var c=0;c<b.length;c++){a+=b[c];a+=c<(b.length-1)?"|":""}return a}function changeFeedFilterValue(g,c,f){console.log("workValue:",g);console.log("newValues:",c);console.log("changedFilterLevel:",f);var e=[];if(g){e=JSON.parse(g[0]["meta_value"])}else{e=[];g=[];var a={meta_value:""};g.push(a)}var d=e.length;var b=c[0]+"#"+c[1]+"#"+c[2];b+=c[2]!=="4"&&c[2]!=="5"?"#"+c[3]:"";if(f<=d){e[f-1][f]=b}else{var h={};h[f]=b;e[f-1]=h}g[0]["meta_value"]=JSON.stringify(e);console.log("result:",JSON.stringify(g));return g}function removeFeedFilterLevel(f,g){console.log("workValue:",f);console.log("levelToRemove:",g);var e=f?JSON.parse(f[0]["meta_value"]):{};var d=[];var c=0;for(var b in e){if(parseInt(b)!==g-1){var a={};a[c+1]=e[b][parseInt(b)+1];d[c]=a;c++}}if(d.length>0){f[0]["meta_value"]=JSON.stringify(d);console.log("result:",JSON.stringify(f))}else{f="";console.log("result:",f)}return f};
includes/data/tvc-admin-functions.php ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package TVC Product Feed Manager/Data/Functions
5
+ * @version 2.7.0
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Converts a string containing a date-time stamp as stored in the meta data to a date time string
14
+ * that can be used in a feed file
15
+ *
16
+ * @param string $date_stamp The timestamp that needs to be converted to a string that can be stored in a feed file
17
+ *
18
+ * @return string A string containing the time or an empty string if the $date_stamp is empty
19
+ * @since 1.1.0
20
+ *
21
+ */
22
+ function tvc_convert_price_date_to_feed_format( $date_stamp ) {
23
+ if ( $date_stamp ) {
24
+ // register the date
25
+ $feed_string = date( 'Y-m-d', $date_stamp );
26
+
27
+ // if set, add the time
28
+ if ( date( 'H', $date_stamp ) !== '00' || date( 'i', $date_stamp ) !== '00' || date( 's', $date_stamp ) !== '00' ) {
29
+ $feed_string .= 'T' . date( 'H:i:s', $date_stamp );
30
+ }
31
+
32
+ return $feed_string;
33
+ } else {
34
+ return '';
35
+ }
36
+ }
37
+
38
+ /**
39
+ * After a channel has been updated this function decreases the 'tvc_channels_to_update' option with one
40
+ *
41
+ * @since 1.4.1
42
+ */
43
+ function tvc_decrease_update_ready_channels() {
44
+ $old = get_option( 'tvc_channels_to_update' );
45
+
46
+ if ( $old > 0 ) {
47
+ update_option( 'tvc_channels_to_update', $old - 1 );
48
+ } else {
49
+ update_option( 'tvc_channels_to_update', 0 );
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Checks the current database version and updates it if required
55
+ *
56
+ * @since 2.4.0
57
+ */
58
+ function tvc_check_db_version() {
59
+ $db_management = new TVC_Database_Management();
60
+ $db_management->verify_db_version();
61
+ }
62
+
63
+ /**
64
+ * Checks if a specific source key is a money related key or not
65
+ *
66
+ * @param string $key The source key to be checked
67
+ *
68
+ * @return boolean True if the source key is money related, false if not
69
+ * @since 1.1.0
70
+ *
71
+ */
72
+ function tvc_meta_key_is_money( $key ) {
73
+ // money keys
74
+ $special_price_keys = array(
75
+ '_max_variation_price',
76
+ '_max_variation_regular_price',
77
+ '_max_variation_sale_price',
78
+ '_min_variation_price',
79
+ '_min_variation_regular_price',
80
+ '_min_variation_sale_price',
81
+ '_regular_price',
82
+ '_sale_price',
83
+ );
84
+
85
+ return in_array( $key, $special_price_keys ) ? true : false;
86
+ }
87
+
88
+ /**
89
+ * Takes a value and formats it to a money value using the WooCommerce thousands separator, decimal separator and number of decimals values
90
+ *
91
+ * @param string $money_va