CTX Feed – WooCommerce Product Feed Manager Plugin - Version 3.1.45

Version Description

(2019-11-03) = * Loading ClipboardJS directly from plugin for older WordPress * Added WooCommerce minimum version checking before loading other dependencies * Fix support for WooCommerce older than 3.6.0

Download this release

Release Info

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

Code changes from version 3.1.44 to 3.1.45

README.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://webappick.com
4
  Tags:woocommerce,google product feed,facebook product feed,woocommerce product feed,woocommerce,
5
  Requires at least: 3.6
6
  Tested Up To: 5.3
7
- Stable tag: 3.1.44
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -304,6 +304,11 @@ Using pro version:
304
 
305
  == Changelog ==
306
 
 
 
 
 
 
307
  = 3.1.44 (2019-10-31) =
308
  * Remove Duplicate Css
309
  * Fix success message not showing
4
  Tags:woocommerce,google product feed,facebook product feed,woocommerce product feed,woocommerce,
5
  Requires at least: 3.6
6
  Tested Up To: 5.3
7
+ Stable tag: 3.1.45
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
304
 
305
  == Changelog ==
306
 
307
+ = 3.1.45 (2019-11-03) =
308
+ * Loading ClipboardJS directly from plugin for older WordPress
309
+ * Added WooCommerce minimum version checking before loading other dependencies
310
+ * Fix support for WooCommerce older than 3.6.0
311
+
312
  = 3.1.44 (2019-10-31) =
313
  * Remove Duplicate Css
314
  * Fix success message not showing
admin/class-woo-feed-admin.php CHANGED
@@ -96,14 +96,16 @@ class Woo_Feed_Admin
96
  * between the defined hooks and the functions defined in this
97
  * class.
98
  */
99
-
100
-
101
  wp_register_script( "jquery-selectize", plugin_dir_url(__FILE__) . 'js/selectize.min.js', array( 'jquery' ), $this->version, false );
102
  wp_register_script( "jquery-validate", plugin_dir_url(__FILE__) . 'js/jquery.validate.min.js', array( 'jquery' ), $this->version, false );
103
  wp_register_script( "jquery-validate-additional-methods", plugin_dir_url(__FILE__) . 'js/additional-methods.min.js', array( 'jquery', 'jquery-validate' ), $this->version, false );
104
  wp_register_script( "jquery-sortable", plugin_dir_url(__FILE__) . 'js/jquery-sortable.js', array( 'jquery' ), $this->version, false );
105
  wp_register_script( "jquery-slick", plugin_dir_url(__FILE__) . 'js/slick.js', array( 'jquery' ), $this->version, false );
106
-
 
 
 
107
  $mainDeps = array( 'jquery', 'clipboard', 'jquery-selectize', 'jquery-sortable', 'jquery-validate', 'jquery-validate-additional-methods' );
108
  if( $hook == 'woo-feed_page_webappick-feed-pro-vs-free' ) {
109
  $mainDeps[] = 'jquery-slick';
96
  * between the defined hooks and the functions defined in this
97
  * class.
98
  */
99
+
 
100
  wp_register_script( "jquery-selectize", plugin_dir_url(__FILE__) . 'js/selectize.min.js', array( 'jquery' ), $this->version, false );
101
  wp_register_script( "jquery-validate", plugin_dir_url(__FILE__) . 'js/jquery.validate.min.js', array( 'jquery' ), $this->version, false );
102
  wp_register_script( "jquery-validate-additional-methods", plugin_dir_url(__FILE__) . 'js/additional-methods.min.js', array( 'jquery', 'jquery-validate' ), $this->version, false );
103
  wp_register_script( "jquery-sortable", plugin_dir_url(__FILE__) . 'js/jquery-sortable.js', array( 'jquery' ), $this->version, false );
104
  wp_register_script( "jquery-slick", plugin_dir_url(__FILE__) . 'js/slick.js', array( 'jquery' ), $this->version, false );
105
+ if( ! wp_script_is( 'clipboard', 'registered' ) ) {
106
+ wp_register_script( 'clipboard', plugin_dir_url(__FILE__) . 'js/clipboard.min.js', [], '2.0.4', false);
107
+ }
108
+
109
  $mainDeps = array( 'jquery', 'clipboard', 'jquery-selectize', 'jquery-sortable', 'jquery-validate', 'jquery-validate-additional-methods' );
110
  if( $hook == 'woo-feed_page_webappick-feed-pro-vs-free' ) {
111
  $mainDeps[] = 'jquery-slick';
admin/js/clipboard.min.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ /*!
2
+ * clipboard.js v2.0.4
3
+ * https://zenorocha.github.io/clipboard.js
4
+ *
5
+ * Licensed MIT © Zeno Rocha
6
+ */
7
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),t}}(),a=o(n(1)),c=o(n(3)),u=o(n(4));function o(t){return t&&t.__esModule?t:{default:t}}var l=function(t){function o(t,e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,o);var n=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(o.__proto__||Object.getPrototypeOf(o)).call(this));return n.resolveOptions(e),n.listenClick(t),n}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(o,c.default),i(o,[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===r(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,u.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new a.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return s("action",t)}},{key:"defaultTarget",value:function(t){var e=s("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return s("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),o}();function s(t,e){var n="data-clipboard-"+t;if(e.hasAttribute(n))return e.getAttribute(n)}t.exports=l},function(t,e,n){"use strict";var o,r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),t}}(),a=n(2),c=(o=a)&&o.__esModule?o:{default:o};var u=function(){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),this.resolveOptions(t),this.initSelection()}return i(e,[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,c.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,c.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),e}();t.exports=u},function(t,e){t.exports=function(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,a=o.length;i<a;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=n},function(t,e,n){var d=n(5),h=n(6);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!d.string(e))throw new TypeError("Second argument must be a String");if(!d.fn(n))throw new TypeError("Third argument must be a Function");if(d.node(t))return s=e,f=n,(l=t).addEventListener(s,f),{destroy:function(){l.removeEventListener(s,f)}};if(d.nodeList(t))return a=t,c=e,u=n,Array.prototype.forEach.call(a,function(t){t.addEventListener(c,u)}),{destroy:function(){Array.prototype.forEach.call(a,function(t){t.removeEventListener(c,u)})}};if(d.string(t))return o=t,r=e,i=n,h(document.body,o,r,i);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,a,c,u,l,s,f}},function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e,n){var a=n(7);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=a(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},function(t,e){if("undefined"!=typeof Element&&!Element.prototype.matches){var n=Element.prototype;n.matches=n.matchesSelector||n.mozMatchesSelector||n.msMatchesSelector||n.oMatchesSelector||n.webkitMatchesSelector}t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}}])});
includes/class-woo-feed.php CHANGED
@@ -12,7 +12,7 @@
12
  * @package Woo_Feed
13
  * @subpackage Woo_Feed/includes
14
  */
15
-
16
  /**
17
  * The core plugin class.
18
  *
@@ -67,14 +67,9 @@ class Woo_Feed
67
  *
68
  * @since 1.0.0
69
  */
70
- public function __construct()
71
- {
72
  $this->woo_feed = 'woo-feed';
73
  $this->version = WOO_FEED_VERSION;
74
- $this->load_dependencies();
75
- $this->set_locale();
76
- $this->define_admin_hooks();
77
- $this->define_public_hooks();
78
  }
79
 
80
 
@@ -95,107 +90,109 @@ class Woo_Feed
95
  * @since 1.0.0
96
  * @access private
97
  */
98
- private function load_dependencies()
99
- {
100
-
 
 
101
  /**
102
  * The class responsible for orchestrating the actions and filters of the
103
  * core plugin.
104
  */
105
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-woo-feed-loader.php';
106
 
107
  /**
108
  * The class responsible for defining internationalization functionality
109
  * of the plugin.
110
  */
111
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-woo-feed-i18n.php';
112
 
113
  /**
114
  * The class responsible for getting all product information
115
  * of the plugin.
116
  */
117
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-products.php';
118
 
119
  /**
120
  * The class responsible for processing feed
121
  */
122
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-engine.php';
123
 
124
  /**
125
  * The class contain all merchants attribute dropdown
126
  */
127
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-dropdown.php';
128
 
129
  /**
130
  * The class contain merchant attributes
131
  */
132
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-default-attributes.php';
133
 
134
  /**
135
  * The class responsible for generating feed
136
  */
137
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-generate.php';
138
 
139
  /**
140
  * The class is a FTP library
141
  */
142
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-ftp.php';
143
 
144
  /**
145
  * The class
146
  */
147
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-auto-update.php';
148
 
149
 
150
  /**
151
  * The class responsible for save feed
152
  */
153
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-savefile.php';
154
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-admin-message.php';
155
  /**
156
  * Merchant classes
157
  */
158
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-google.php';
159
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-amazon.php';
160
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-facebook.php';
161
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-nextag.php';
162
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-pinterest.php';
163
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-kelkoo.php';
164
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-pricegrabber.php';
165
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-shopzilla.php';
166
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-shopmania.php';
167
- require plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-shopping.php';
168
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-bing.php';
169
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-become.php';
170
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-connexity.php';
171
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/feeds/class-woo-feed-custom.php';
172
  /**
173
  * Docs Page Class
174
  */
175
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-woo-feed-docs.php';
176
  /**
177
  * The class responsible for defining all actions that occur in the admin area.
178
  */
179
- require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-woo-feed-admin.php';
180
 
181
  /**
182
  * The class responsible for defining all actions that occur in the public area.
183
  */
184
- require_once plugin_dir_path(dirname(__FILE__)) . 'public/class-woo-feed-public.php';
185
 
186
  /**
187
  * The class responsible for making list table
188
  */
189
 
190
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-list-table.php';
191
 
192
 
193
  /**
194
  * The class responsible for making feed list
195
  */
196
- require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-woo-feed-manage-list.php';
197
 
198
- require_once plugin_dir_path(dirname(__FILE__)) . 'includes/classes/class-woo-feed-sftp.php';
199
 
200
  $this->loader = new Woo_Feed_Loader();
201
 
@@ -261,7 +258,13 @@ class Woo_Feed
261
  */
262
  public function run()
263
  {
264
- $this->loader->run();
 
 
 
 
 
 
265
  }
266
 
267
  /**
12
  * @package Woo_Feed
13
  * @subpackage Woo_Feed/includes
14
  */
15
+ /** @define "WOO_FEED_PATH" "./../" */
16
  /**
17
  * The core plugin class.
18
  *
67
  *
68
  * @since 1.0.0
69
  */
70
+ public function __construct() {
 
71
  $this->woo_feed = 'woo-feed';
72
  $this->version = WOO_FEED_VERSION;
 
 
 
 
73
  }
74
 
75
 
90
  * @since 1.0.0
91
  * @access private
92
  */
93
+ private function load_dependencies() {
94
+ /**
95
+ * Support for older version of WooCommerce
96
+ */
97
+ require_once WOO_FEED_PATH . 'includes/wc-legacy-support.php';
98
  /**
99
  * The class responsible for orchestrating the actions and filters of the
100
  * core plugin.
101
  */
102
+ require_once WOO_FEED_PATH . 'includes/class-woo-feed-loader.php';
103
 
104
  /**
105
  * The class responsible for defining internationalization functionality
106
  * of the plugin.
107
  */
108
+ require_once WOO_FEED_PATH . 'includes/class-woo-feed-i18n.php';
109
 
110
  /**
111
  * The class responsible for getting all product information
112
  * of the plugin.
113
  */
114
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-products.php';
115
 
116
  /**
117
  * The class responsible for processing feed
118
  */
119
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-engine.php';
120
 
121
  /**
122
  * The class contain all merchants attribute dropdown
123
  */
124
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-dropdown.php';
125
 
126
  /**
127
  * The class contain merchant attributes
128
  */
129
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-default-attributes.php';
130
 
131
  /**
132
  * The class responsible for generating feed
133
  */
134
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-generate.php';
135
 
136
  /**
137
  * The class is a FTP library
138
  */
139
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-ftp.php';
140
 
141
  /**
142
  * The class
143
  */
144
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-auto-update.php';
145
 
146
 
147
  /**
148
  * The class responsible for save feed
149
  */
150
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-savefile.php';
151
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-admin-message.php';
152
  /**
153
  * Merchant classes
154
  */
155
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-google.php';
156
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-amazon.php';
157
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-facebook.php';
158
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-nextag.php';
159
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-pinterest.php';
160
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-kelkoo.php';
161
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-pricegrabber.php';
162
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-shopzilla.php';
163
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-shopmania.php';
164
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-shopping.php';
165
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-bing.php';
166
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-become.php';
167
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-connexity.php';
168
+ require_once WOO_FEED_PATH . 'includes/feeds/class-woo-feed-custom.php';
169
  /**
170
  * Docs Page Class
171
  */
172
+ require_once WOO_FEED_PATH . 'includes/class-woo-feed-docs.php';
173
  /**
174
  * The class responsible for defining all actions that occur in the admin area.
175
  */
176
+ require_once WOO_FEED_PATH . 'admin/class-woo-feed-admin.php';
177
 
178
  /**
179
  * The class responsible for defining all actions that occur in the public area.
180
  */
181
+ require_once WOO_FEED_PATH . 'public/class-woo-feed-public.php';
182
 
183
  /**
184
  * The class responsible for making list table
185
  */
186
 
187
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-list-table.php';
188
 
189
 
190
  /**
191
  * The class responsible for making feed list
192
  */
193
+ require_once WOO_FEED_PATH . 'admin/class-woo-feed-manage-list.php';
194
 
195
+ require_once WOO_FEED_PATH . 'includes/classes/class-woo-feed-sftp.php';
196
 
197
  $this->loader = new Woo_Feed_Loader();
198
 
258
  */
259
  public function run()
260
  {
261
+ if( wooFeed_check_WC() && wooFeed_is_WC_supported() ) {
262
+ $this->load_dependencies();
263
+ $this->set_locale();
264
+ $this->define_admin_hooks();
265
+ $this->define_public_hooks();
266
+ $this->loader->run();
267
+ }
268
  }
269
 
270
  /**
includes/feeds/class-woo-feed-become.php CHANGED
@@ -1,668 +1,668 @@
1
- <?php
2
-
3
- /**
4
- * Class Become
5
- *
6
- * Responsible for processing and generating feed for Become.com
7
- *
8
- * @since 1.0.0
9
- * @package Become
10
- *
11
- */
12
- class Become
13
- {
14
-
15
- /**
16
- * This variable is responsible for holding all product attributes and their values
17
- *
18
- * @since 1.0.0
19
- * @var array $products Contains all the product attributes to generate feed
20
- * @access public
21
- */
22
- public $products;
23
-
24
- /**
25
- * This variable is responsible for holding feed configuration form values
26
- *
27
- * @since 1.0.0
28
- * @var Become $rules Contains feed configuration form values
29
- * @access public
30
- */
31
- public $rules;
32
-
33
- /**
34
- * This variable is responsible for mapping store attributes to merchant attribute
35
- *
36
- * @since 1.0.0
37
- * @var Become $mapping Map store attributes to merchant attribute
38
- * @access public
39
- */
40
- public $mapping;
41
-
42
- /**
43
- * This variable is responsible for generate error logs
44
- *
45
- * @since 1.0.0
46
- * @var Become $errorLog Generate error logs
47
- * @access public
48
- */
49
- public $errorLog;
50
-
51
- /**
52
- * This variable is responsible for making error number
53
- *
54
- * @since 1.0.0
55
- * @var Become $errorCounter Generate error number
56
- * @access public
57
- */
58
- public $errorCounter;
59
-
60
- /**
61
- * Feed Wrapper text for enclosing each product information
62
- *
63
- * @since 1.0.0
64
- * @var Become $feedWrapper Feed Wrapper text
65
- * @access public
66
- */
67
- private $feedWrapper;
68
-
69
- /**
70
- * Define the core functionality to generate feed.
71
- *
72
- * Set the feed rules. Map products according to the rules and Check required attributes
73
- * and their values according to merchant specification.
74
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
- * @since 1.0.0
76
- */
77
- public function __construct($feedRule)
78
- {
79
- $this->feedWrapper = 'product';
80
- $this->errorCounter = 0;
81
- $this->rules = $feedRule;
82
- $this->mapProductsByRules();
83
- $this->formatRequiredField();
84
- $this->filterProductValues();
85
- if ($this->rules['feedType'] == 'xml') {
86
- $this->mapAttributeForXML();
87
- } else {
88
- $this->mapAttributeForCSVTEXT();
89
- }
90
- }
91
-
92
- /**
93
- * Configure merchant attributes for XML feed
94
- */
95
- public function mapAttributeForXML()
96
- {
97
- //Basic product information
98
-
99
- if ( is_countable( $this->products ) && count( $this->products ) ) {
100
- foreach ($this->products as $key => $values) {
101
- foreach ($values as $attr => $value) {
102
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
103
- }
104
- }
105
- }
106
- }
107
-
108
- /**
109
- * Configure merchant attributes for CSV and TXT feed
110
- */
111
- public function mapAttributeForCSVTEXT()
112
- {
113
- //Basic product information
114
-
115
- if ( is_countable( $this->products ) && count( $this->products ) ) {
116
- foreach ($this->products as $key => $values) {
117
- foreach ($values as $attr => $value) {
118
- //Allow force strip HTML
119
- $value = strip_tags(html_entity_decode($value));
120
- if ($attr != 'Category') {
121
- $value = utf8_encode($value);
122
- $attr = utf8_encode($attr);
123
-
124
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
-
126
- if (gettype($value) == 'array')
127
- $value = json_encode($value);
128
- }
129
-
130
- $this->products[$key][$attr] = $value;
131
- }
132
- }
133
- }
134
- }
135
-
136
- /**
137
- * Check all the required attributes and make error message
138
- */
139
- public function formatRequiredField()
140
- {
141
- foreach ($this->products as $no => $product) {
142
- $upn = 0;
143
- if (array_key_exists('Unique ID', $product)) {
144
- $id = $product['Unique ID'];
145
- } else {
146
- $id = $product['Title'];
147
- }
148
-
149
- if (!array_key_exists('Unique ID', $product)) {
150
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique ID</b>] Missing for <b>$id</b>.";
151
- $this->errorCounter++;
152
- }
153
-
154
-
155
- if (!array_key_exists('Title', $product)) {
156
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
157
- $this->errorCounter++;
158
- }
159
-
160
- if (!array_key_exists('Description', $product)) {
161
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
162
- $this->errorCounter++;
163
- }
164
-
165
- if (!array_key_exists('Category', $product)) {
166
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Category</b>] Missing for <b>$id</b>.";
167
- $this->errorCounter++;
168
- }
169
-
170
- if (!array_key_exists('Product URL', $product)) {
171
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
172
- $this->errorCounter++;
173
- }
174
-
175
- if (!array_key_exists('Image URL', $product)) {
176
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
177
- $this->errorCounter++;
178
- }
179
-
180
- if (!array_key_exists('Condition', $product)) {
181
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
182
- $this->errorCounter++;
183
- }
184
-
185
- if (!array_key_exists('Availability', $product)) {
186
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Availability</b>] Missing for <b>$id</b>.";
187
- $this->errorCounter++;
188
- }
189
-
190
- if (!array_key_exists('Current price', $product)) {
191
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current price</b>] Missing for <b>$id</b>.";
192
- $this->errorCounter++;
193
- }
194
- }
195
- }
196
-
197
- /**
198
- * Return Feed
199
- *
200
- * @return array|bool|string
201
- */
202
- public function returnFinalProduct()
203
- {
204
- if ($this->rules['feedType'] == 'xml') {
205
- return $this->get_feed($this->products);
206
- } elseif ($this->rules['feedType'] == 'txt') {
207
- return $this->get_txt_feed();
208
- } elseif ($this->rules['feedType'] == 'csv') {
209
- return $this->get_csv_feed();
210
- }
211
- return false;
212
- }
213
-
214
- /**
215
- * Check product's attribute value according to merchant specifications
216
- */
217
- public function filterProductValues()
218
- {
219
- $getProduct = new Woo_Feed_Products();
220
- $products = $this->products;
221
-
222
- foreach ($products as $no => $product) {
223
- if (array_key_exists('Unique ID', $product)) {
224
- $id = $product['Unique ID'];
225
- } else {
226
- $id = $product['Title'];
227
- }
228
- // echo "<pre>";
229
- // print_r($product);
230
- foreach ($product as $key => $value) {
231
- switch ($key) {
232
- case "Unique ID":
233
- if (strlen($value) > 100) {
234
- $this->errorLog[$this->errorCounter] = "[<b>Unique ID</b>] is more that 100 character for $id.";
235
- $this->errorCounter++;
236
- }
237
- break;
238
- case "Title":
239
- if (strlen($value) > 1000) {
240
- $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 1000 character for $id.";
241
- $this->errorCounter++;
242
- }
243
- break;
244
- case "Description":
245
- if (strlen($value) > 3000) {
246
- $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 3000 character for $id.";
247
- $this->errorCounter++;
248
- }
249
- break;
250
- case "Category":
251
- if (strlen($value) > 1000) {
252
- $this->errorLog[$this->errorCounter] = "[<b>Category</b>] is more that 1000 character for $id.";
253
- $this->errorCounter++;
254
- }
255
- break;
256
- case "Product URL":
257
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
258
- $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] must start with http:// or https:// for $id.";
259
- $this->errorCounter++;
260
- }
261
-
262
- if (strlen($value) > 2000) {
263
- $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] is more that 2000 character for $id.";
264
- $this->errorCounter++;
265
- }
266
-
267
- break;
268
- case "Image URL":
269
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
270
- $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] must start with http:// or https:// for $id.";
271
- $this->errorCounter++;
272
- }
273
-
274
- if (strlen($value) > 2000) {
275
- $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] is more that 2000 character for $id.";
276
- $this->errorCounter++;
277
- }
278
-
279
- list($width, $height) = getimagesize($value);
280
- if ($width < 450 || $height < 450) {
281
- $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 450px for $id.";
282
- $this->errorCounter++;
283
- }
284
-
285
- break;
286
- case "Condition":
287
- $condition = array("New", "Used", "Refurbished", "Open Box", "OEM");
288
- if (!array_key_exists($value, $condition)) {
289
- $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] = $value is acceptable for $id.";
290
- $this->errorCounter++;
291
- }
292
- break;
293
- case "Availability":
294
- $availability = array("In Stock", "Out of Stock", "Available for Order", "PreOrder");
295
- if ($value == 'in stock') {
296
- $this->products[$no][$key] = "In Stock";
297
- } else {
298
- $this->products[$no][$key] = "Out of Stock";
299
- }
300
-
301
- if (!array_key_exists($this->products[$no][$key], $availability)) {
302
- $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] = $value is acceptable for $id.";
303
- $this->errorCounter++;
304
- }
305
- break;
306
- case "Current price":
307
- if (!is_numeric($value)) {
308
- $this->errorLog[$this->errorCounter] = "[<b>Current price</b>] should be numeric for $id.";
309
- $this->errorCounter++;
310
- }
311
- break;
312
- case "Original Price":
313
- if (!is_numeric($value)) {
314
- $this->errorLog[$this->errorCounter] = "[<b>Original price</b>] should be numeric for $id.";
315
- $this->errorCounter++;
316
- }
317
- break;
318
- default:
319
- break;
320
- }
321
- }
322
- }
323
- }
324
-
325
- /**
326
- * Return Dynamic Category Mapping Values by Parent Product Id
327
- *
328
- * @param string $mappingName Category Mapping Name
329
- * @param int $parent Parent id of the product
330
- * @return mixed
331
- */
332
- public function get_category_mapping_value($mappingName, $parent)
333
- {
334
- $getValue = unserialize(get_option($mappingName));
335
- $mapp = array_reverse($getValue['cmapping'], true);
336
- $categories = get_the_terms($parent, 'product_cat');
337
-
338
- foreach ($categories as $key => $category) {
339
- if (!empty($mapp[$category->term_id]))
340
- return $mapp[$category->term_id];
341
- }
342
- return false;
343
- }
344
-
345
- /**
346
- * Configure the feed according to the rules
347
- * @return Shopping
348
- */
349
- public function mapProductsByRules()
350
- {
351
- /**
352
- * Get WooCommerce Products
353
- * @package Woo_Feed_Products
354
- */
355
- $products = new Woo_Feed_Products();
356
-
357
- /**
358
- * This variable contain selected Woo attributes from feed making form
359
- *
360
- * @since 1.0.0
361
- * @var array $attributes contain selected Woo attributes from feed making form
362
- */
363
- $attributes = $this->rules['attributes'];
364
- /**
365
- * This variable contain selected Prefix Values from feed making form
366
- *
367
- * @since 1.0.0
368
- * @var array $prefix Prefix Values from feed making form
369
- */
370
- $prefix = $this->rules['prefix'];
371
- /**
372
- * This variable contain selected Prefix Values from feed making form
373
- *
374
- * @since 1.0.0
375
- * @var array $suffix Suffix Values from feed making form
376
- */
377
- $suffix = $this->rules['suffix'];
378
- /**
379
- * This variable contain selected Output Types from feed making form
380
- *
381
- * @since 1.0.0
382
- * @var array $outputType Output Types from feed making form
383
- */
384
- $outputType = $this->rules['output_type'];
385
-
386
- /**
387
- * This variable contain selected Output Limit from feed making form
388
- *
389
- * @since 1.0.0
390
- * @var array $limit Output Limit from feed making form
391
- */
392
- $limit = $this->rules['limit'];
393
- /**
394
- * This variable contain selected Merchant attributes from feed making form
395
- *
396
- * @since 1.0.0
397
- * @var array $merchantAttributes contain selected Woo attributes from feed making form
398
- */
399
- $merchantAttributes = $this->rules['mattributes'];
400
- /**
401
- * This variable contain attribute types from feed making form
402
- *
403
- * @since 1.0.0
404
- * @var array $type contain attribute types from feed making form
405
- */
406
- $type = $this->rules['type'];
407
- /**
408
- * This variable contain manual output of attribute from feed making form
409
- *
410
- * @since 1.0.0
411
- * @var array $default contain manual output of attribute
412
- */
413
- $default = $this->rules['default'];
414
-
415
- /**
416
- * This variable contain feed type
417
- *
418
- * @since 1.0.0
419
- * @var array $feedType contain feed type
420
- */
421
- $feedType = $this->rules['feedType'];
422
-
423
- // Map Merchant Attributes and Woo Attributes
424
- if (count($merchantAttributes)) {
425
- foreach ($merchantAttributes as $key => $attr) {
426
- if (!empty($attr) && !empty($attributes[$key])) {
427
- if ($type[$key] == 'attribute') {
428
- $this->mapping[$attr]['value'] = $attributes[$key];
429
- $this->mapping[$attr]['suffix'] = $suffix[$key];
430
- $this->mapping[$attr]['prefix'] = $prefix[$key];
431
- $this->mapping[$attr]['type'] = $outputType[$key];
432
- $this->mapping[$attr]['limit'] = $limit[$key];
433
- }
434
- } else if (empty($attributes[$key])) {
435
- if ($type[$key] == 'pattern') {
436
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
437
- $this->mapping[$attr]['suffix'] = $suffix[$key];
438
- $this->mapping[$attr]['prefix'] = $prefix[$key];
439
- $this->mapping[$attr]['type'] = $outputType[$key];
440
- $this->mapping[$attr]['limit'] = $limit[$key];
441
- }
442
- }
443
- }
444
- }
445
-
446
- // Make Product feed array according to mapping
447
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
448
- $i = 0;
449
- foreach ($this->mapping as $attr => $rules) {
450
- if (array_key_exists($rules['value'], $value)) {
451
-
452
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
453
- // Format According to output type
454
- if ($rules['type'] == 2) {
455
- $output = strip_tags($output);
456
- } elseif ($rules['type'] == 3) {
457
- $output = absint($output);
458
- }
459
- // Format According to output limit
460
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
461
- $output = substr($output, 0, $rules['limit']);
462
- }
463
- $attr = trim($attr);
464
- $this->products[$key][$attr] = trim($output);
465
- } else {
466
- if (!empty($default[$i])) {
467
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
468
- if ($rules['type'] == 2) {
469
- $output = strip_tags($output);
470
- } elseif ($rules['type'] == 3) {
471
- $output = absint($output);
472
- }
473
- // Format According to output limit
474
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
475
- $output = substr($output, 0, $rules['limit']);
476
- }
477
- $attr = trim($attr);
478
- $this->products[$key][$attr] = trim($output);
479
- }
480
- }
481
- $i++;
482
- }
483
- }
484
-
485
-
486
- return $this->products;
487
- }
488
-
489
- /**
490
- * Change the products old array key and set new
491
- *
492
- * @param string $from Attribute Before
493
- * @param string $to Attribute After
494
- * @param bool $cdata Enclose Feed value
495
- */
496
- public function mapAttribute($from, $to, $cdata = false)
497
- {
498
- $i = 0;
499
- foreach ($this->products as $no => $product) {
500
- foreach ($product as $key => $value) {
501
- if ($key == $from) {
502
- unset($this->products[$no][$from]);
503
- if ($from == 'images') {
504
- $this->products[$no][$to] = $value;
505
- } else {
506
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
507
- }
508
-
509
- }
510
- }
511
- $i++;
512
- }
513
- }
514
-
515
- /**
516
- * Format and Make the XML node for the Feed
517
- *
518
- * @param $attribute
519
- * @param $value
520
- * @param bool $cdata
521
- * @param bool $stripHTML
522
- * @param bool $utf8encode
523
- * @param string $space
524
- * @return string
525
- */
526
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
527
- {
528
- //Make single line for XML
529
- $c_leader = '';
530
- $c_footer = '';
531
- if ($cdata) {
532
- $c_leader = '<![CDATA[';
533
- $c_footer = ']]>';
534
- }
535
- //Allow force strip HTML
536
- if ($stripHTML)
537
- $value = strip_tags(html_entity_decode($value));
538
-
539
-
540
- if ($utf8encode || $utf8encode == 1) {
541
- $value = utf8_encode($value);
542
- $attribute = utf8_encode($attribute);
543
- }
544
-
545
-
546
- if (!$cdata)
547
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
548
-
549
- if (gettype($value) == 'array')
550
- $value = json_encode($value);
551
-
552
-
553
- return '
554
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
555
- }
556
-
557
- /**
558
- * Responsible to change product array key
559
- *
560
- * @param $array
561
- * @param $old_key
562
- * @param $new_key
563
- * @return array
564
- */
565
- function change_key($array, $old_key, $new_key)
566
- {
567
- foreach ($this->products as $no => $product) {
568
- if (!array_key_exists($old_key, $product))
569
- return $array;
570
-
571
- $keys = array_keys($array);
572
- $keys[array_search($old_key, $keys)] = $new_key;
573
- }
574
- return array_combine($keys, $array);
575
- }
576
-
577
- /**
578
- * Responsible to make XML feed header
579
- * @return string
580
- */
581
- public function get_feed_header()
582
- {
583
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
584
- <products>';
585
- $output .= "\n";
586
- return $output;
587
- }
588
-
589
- /**
590
- * Responsible to make XML feed body
591
- * @var array $item Product array
592
- * @return string
593
- */
594
- public function get_feed($items)
595
- {
596
- $feed = "";
597
- $feed .= $this->get_feed_header();
598
- $feed .= "\n";
599
- foreach ($items as $item => $products) {
600
- $feed .= " <" . $this->feedWrapper . ">";
601
- foreach ($products as $key => $value) {
602
- if (!empty($value))
603
- $feed .= $value;
604
- }
605
- $feed .= "\n </" . $this->feedWrapper . ">\n";
606
- }
607
- $feed .= $this->get_feed_footer();
608
-
609
- return $feed;
610
- }
611
-
612
- /**
613
- * Responsible to make XML feed footer
614
- * @return string
615
- */
616
- public function get_feed_footer()
617
- {
618
- $footer = " </products>";
619
- return $footer;
620
- }
621
-
622
- /**
623
- * Responsible to make TXT feed
624
- * @return string
625
- */
626
- public function get_txt_feed()
627
- {
628
- if ( is_countable( $this->products ) && count( $this->products ) ) {
629
- $headers = array_keys($this->products[0]);
630
- $feed[] = $headers;
631
- foreach ($this->products as $no => $product) {
632
- $row = array();
633
- foreach ($headers as $key => $header) {
634
- $row[] = $product[$header];
635
- }
636
- $feed[] = $row;
637
- }
638
- $str = "";
639
- foreach ($feed as $fields) {
640
- $str .= implode("\t", $fields) . "\n";
641
- }
642
- return $str;
643
- }
644
- return false;
645
- }
646
-
647
- /**
648
- * Responsible to make CSV feed
649
- * @return string
650
- */
651
- public function get_csv_feed()
652
- {
653
- if ( is_countable( $this->products ) && count( $this->products ) ) {
654
- $headers = array_keys($this->products[0]);
655
- $feed[] = $headers;
656
- foreach ($this->products as $no => $product) {
657
- $row = array();
658
- foreach ($headers as $key => $header) {
659
- $row[] = $product[$header];
660
- }
661
- $feed[] = $row;
662
- }
663
-
664
- return $feed;
665
- }
666
- return false;
667
- }
668
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Become
5
+ *
6
+ * Responsible for processing and generating feed for Become.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Become
10
+ *
11
+ */
12
+ class Become
13
+ {
14
+
15
+ /**
16
+ * This variable is responsible for holding all product attributes and their values
17
+ *
18
+ * @since 1.0.0
19
+ * @var array $products Contains all the product attributes to generate feed
20
+ * @access public
21
+ */
22
+ public $products;
23
+
24
+ /**
25
+ * This variable is responsible for holding feed configuration form values
26
+ *
27
+ * @since 1.0.0
28
+ * @var Become $rules Contains feed configuration form values
29
+ * @access public
30
+ */
31
+ public $rules;
32
+
33
+ /**
34
+ * This variable is responsible for mapping store attributes to merchant attribute
35
+ *
36
+ * @since 1.0.0
37
+ * @var Become $mapping Map store attributes to merchant attribute
38
+ * @access public
39
+ */
40
+ public $mapping;
41
+
42
+ /**
43
+ * This variable is responsible for generate error logs
44
+ *
45
+ * @since 1.0.0
46
+ * @var Become $errorLog Generate error logs
47
+ * @access public
48
+ */
49
+ public $errorLog;
50
+
51
+ /**
52
+ * This variable is responsible for making error number
53
+ *
54
+ * @since 1.0.0
55
+ * @var Become $errorCounter Generate error number
56
+ * @access public
57
+ */
58
+ public $errorCounter;
59
+
60
+ /**
61
+ * Feed Wrapper text for enclosing each product information
62
+ *
63
+ * @since 1.0.0
64
+ * @var Become $feedWrapper Feed Wrapper text
65
+ * @access public
66
+ */
67
+ private $feedWrapper;
68
+
69
+ /**
70
+ * Define the core functionality to generate feed.
71
+ *
72
+ * Set the feed rules. Map products according to the rules and Check required attributes
73
+ * and their values according to merchant specification.
74
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
+ * @since 1.0.0
76
+ */
77
+ public function __construct($feedRule)
78
+ {
79
+ $this->feedWrapper = 'product';
80
+ $this->errorCounter = 0;
81
+ $this->rules = $feedRule;
82
+ $this->mapProductsByRules();
83
+ $this->formatRequiredField();
84
+ $this->filterProductValues();
85
+ if ($this->rules['feedType'] == 'xml') {
86
+ $this->mapAttributeForXML();
87
+ } else {
88
+ $this->mapAttributeForCSVTEXT();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Configure merchant attributes for XML feed
94
+ */
95
+ public function mapAttributeForXML()
96
+ {
97
+ //Basic product information
98
+
99
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
100
+ foreach ($this->products as $key => $values) {
101
+ foreach ($values as $attr => $value) {
102
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Configure merchant attributes for CSV and TXT feed
110
+ */
111
+ public function mapAttributeForCSVTEXT()
112
+ {
113
+ //Basic product information
114
+
115
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
116
+ foreach ($this->products as $key => $values) {
117
+ foreach ($values as $attr => $value) {
118
+ //Allow force strip HTML
119
+ $value = strip_tags(html_entity_decode($value));
120
+ if ($attr != 'Category') {
121
+ $value = utf8_encode($value);
122
+ $attr = utf8_encode($attr);
123
+
124
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
+
126
+ if (gettype($value) == 'array')
127
+ $value = json_encode($value);
128
+ }
129
+
130
+ $this->products[$key][$attr] = $value;
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Check all the required attributes and make error message
138
+ */
139
+ public function formatRequiredField()
140
+ {
141
+ foreach ($this->products as $no => $product) {
142
+ $upn = 0;
143
+ if (array_key_exists('Unique ID', $product)) {
144
+ $id = $product['Unique ID'];
145
+ } else {
146
+ $id = $product['Title'];
147
+ }
148
+
149
+ if (!array_key_exists('Unique ID', $product)) {
150
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique ID</b>] Missing for <b>$id</b>.";
151
+ $this->errorCounter++;
152
+ }
153
+
154
+
155
+ if (!array_key_exists('Title', $product)) {
156
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
157
+ $this->errorCounter++;
158
+ }
159
+
160
+ if (!array_key_exists('Description', $product)) {
161
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
162
+ $this->errorCounter++;
163
+ }
164
+
165
+ if (!array_key_exists('Category', $product)) {
166
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Category</b>] Missing for <b>$id</b>.";
167
+ $this->errorCounter++;
168
+ }
169
+
170
+ if (!array_key_exists('Product URL', $product)) {
171
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
172
+ $this->errorCounter++;
173
+ }
174
+
175
+ if (!array_key_exists('Image URL', $product)) {
176
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
177
+ $this->errorCounter++;
178
+ }
179
+
180
+ if (!array_key_exists('Condition', $product)) {
181
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
182
+ $this->errorCounter++;
183
+ }
184
+
185
+ if (!array_key_exists('Availability', $product)) {
186
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Availability</b>] Missing for <b>$id</b>.";
187
+ $this->errorCounter++;
188
+ }
189
+
190
+ if (!array_key_exists('Current price', $product)) {
191
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current price</b>] Missing for <b>$id</b>.";
192
+ $this->errorCounter++;
193
+ }
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Return Feed
199
+ *
200
+ * @return array|bool|string
201
+ */
202
+ public function returnFinalProduct()
203
+ {
204
+ if ($this->rules['feedType'] == 'xml') {
205
+ return $this->get_feed($this->products);
206
+ } elseif ($this->rules['feedType'] == 'txt') {
207
+ return $this->get_txt_feed();
208
+ } elseif ($this->rules['feedType'] == 'csv') {
209
+ return $this->get_csv_feed();
210
+ }
211
+ return false;
212
+ }
213
+
214
+ /**
215
+ * Check product's attribute value according to merchant specifications
216
+ */
217
+ public function filterProductValues()
218
+ {
219
+ $getProduct = new Woo_Feed_Products();
220
+ $products = $this->products;
221
+
222
+ foreach ($products as $no => $product) {
223
+ if (array_key_exists('Unique ID', $product)) {
224
+ $id = $product['Unique ID'];
225
+ } else {
226
+ $id = $product['Title'];
227
+ }
228
+ // echo "<pre>";
229
+ // print_r($product);
230
+ foreach ($product as $key => $value) {
231
+ switch ($key) {
232
+ case "Unique ID":
233
+ if (strlen($value) > 100) {
234
+ $this->errorLog[$this->errorCounter] = "[<b>Unique ID</b>] is more that 100 character for $id.";
235
+ $this->errorCounter++;
236
+ }
237
+ break;
238
+ case "Title":
239
+ if (strlen($value) > 1000) {
240
+ $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 1000 character for $id.";
241
+ $this->errorCounter++;
242
+ }
243
+ break;
244
+ case "Description":
245
+ if (strlen($value) > 3000) {
246
+ $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 3000 character for $id.";
247
+ $this->errorCounter++;
248
+ }
249
+ break;
250
+ case "Category":
251
+ if (strlen($value) > 1000) {
252
+ $this->errorLog[$this->errorCounter] = "[<b>Category</b>] is more that 1000 character for $id.";
253
+ $this->errorCounter++;
254
+ }
255
+ break;
256
+ case "Product URL":
257
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
258
+ $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] must start with http:// or https:// for $id.";
259
+ $this->errorCounter++;
260
+ }
261
+
262
+ if (strlen($value) > 2000) {
263
+ $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] is more that 2000 character for $id.";
264
+ $this->errorCounter++;
265
+ }
266
+
267
+ break;
268
+ case "Image URL":
269
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
270
+ $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] must start with http:// or https:// for $id.";
271
+ $this->errorCounter++;
272
+ }
273
+
274
+ if (strlen($value) > 2000) {
275
+ $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] is more that 2000 character for $id.";
276
+ $this->errorCounter++;
277
+ }
278
+
279
+ list($width, $height) = getimagesize($value);
280
+ if ($width < 450 || $height < 450) {
281
+ $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 450px for $id.";
282
+ $this->errorCounter++;
283
+ }
284
+
285
+ break;
286
+ case "Condition":
287
+ $condition = array("New", "Used", "Refurbished", "Open Box", "OEM");
288
+ if (!array_key_exists($value, $condition)) {
289
+ $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] = $value is acceptable for $id.";
290
+ $this->errorCounter++;
291
+ }
292
+ break;
293
+ case "Availability":
294
+ $availability = array("In Stock", "Out of Stock", "Available for Order", "PreOrder");
295
+ if ($value == 'in stock') {
296
+ $this->products[$no][$key] = "In Stock";
297
+ } else {
298
+ $this->products[$no][$key] = "Out of Stock";
299
+ }
300
+
301
+ if (!array_key_exists($this->products[$no][$key], $availability)) {
302
+ $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] = $value is acceptable for $id.";
303
+ $this->errorCounter++;
304
+ }
305
+ break;
306
+ case "Current price":
307
+ if (!is_numeric($value)) {
308
+ $this->errorLog[$this->errorCounter] = "[<b>Current price</b>] should be numeric for $id.";
309
+ $this->errorCounter++;
310
+ }
311
+ break;
312
+ case "Original Price":
313
+ if (!is_numeric($value)) {
314
+ $this->errorLog[$this->errorCounter] = "[<b>Original price</b>] should be numeric for $id.";
315
+ $this->errorCounter++;
316
+ }
317
+ break;
318
+ default:
319
+ break;
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Return Dynamic Category Mapping Values by Parent Product Id
327
+ *
328
+ * @param string $mappingName Category Mapping Name
329
+ * @param int $parent Parent id of the product
330
+ * @return mixed
331
+ */
332
+ public function get_category_mapping_value($mappingName, $parent)
333
+ {
334
+ $getValue = unserialize(get_option($mappingName));
335
+ $mapp = array_reverse($getValue['cmapping'], true);
336
+ $categories = get_the_terms($parent, 'product_cat');
337
+
338
+ foreach ($categories as $key => $category) {
339
+ if (!empty($mapp[$category->term_id]))
340
+ return $mapp[$category->term_id];
341
+ }
342
+ return false;
343
+ }
344
+
345
+ /**
346
+ * Configure the feed according to the rules
347
+ * @return Shopping
348
+ */
349
+ public function mapProductsByRules()
350
+ {
351
+ /**
352
+ * Get WooCommerce Products
353
+ * @package Woo_Feed_Products
354
+ */
355
+ $products = new Woo_Feed_Products();
356
+
357
+ /**
358
+ * This variable contain selected Woo attributes from feed making form
359
+ *
360
+ * @since 1.0.0
361
+ * @var array $attributes contain selected Woo attributes from feed making form
362
+ */
363
+ $attributes = $this->rules['attributes'];
364
+ /**
365
+ * This variable contain selected Prefix Values from feed making form
366
+ *
367
+ * @since 1.0.0
368
+ * @var array $prefix Prefix Values from feed making form
369
+ */
370
+ $prefix = $this->rules['prefix'];
371
+ /**
372
+ * This variable contain selected Prefix Values from feed making form
373
+ *
374
+ * @since 1.0.0
375
+ * @var array $suffix Suffix Values from feed making form
376
+ */
377
+ $suffix = $this->rules['suffix'];
378
+ /**
379
+ * This variable contain selected Output Types from feed making form
380
+ *
381
+ * @since 1.0.0
382
+ * @var array $outputType Output Types from feed making form
383
+ */
384
+ $outputType = $this->rules['output_type'];
385
+
386
+ /**
387
+ * This variable contain selected Output Limit from feed making form
388
+ *
389
+ * @since 1.0.0
390
+ * @var array $limit Output Limit from feed making form
391
+ */
392
+ $limit = $this->rules['limit'];
393
+ /**
394
+ * This variable contain selected Merchant attributes from feed making form
395
+ *
396
+ * @since 1.0.0
397
+ * @var array $merchantAttributes contain selected Woo attributes from feed making form
398
+ */
399
+ $merchantAttributes = $this->rules['mattributes'];
400
+ /**
401
+ * This variable contain attribute types from feed making form
402
+ *
403
+ * @since 1.0.0
404
+ * @var array $type contain attribute types from feed making form
405
+ */
406
+ $type = $this->rules['type'];
407
+ /**
408
+ * This variable contain manual output of attribute from feed making form
409
+ *
410
+ * @since 1.0.0
411
+ * @var array $default contain manual output of attribute
412
+ */
413
+ $default = $this->rules['default'];
414
+
415
+ /**
416
+ * This variable contain feed type
417
+ *
418
+ * @since 1.0.0
419
+ * @var array $feedType contain feed type
420
+ */
421
+ $feedType = $this->rules['feedType'];
422
+
423
+ // Map Merchant Attributes and Woo Attributes
424
+ if (count($merchantAttributes)) {
425
+ foreach ($merchantAttributes as $key => $attr) {
426
+ if (!empty($attr) && !empty($attributes[$key])) {
427
+ if ($type[$key] == 'attribute') {
428
+ $this->mapping[$attr]['value'] = $attributes[$key];
429
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
430
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
431
+ $this->mapping[$attr]['type'] = $outputType[$key];
432
+ $this->mapping[$attr]['limit'] = $limit[$key];
433
+ }
434
+ } else if (empty($attributes[$key])) {
435
+ if ($type[$key] == 'pattern') {
436
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
437
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
438
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
439
+ $this->mapping[$attr]['type'] = $outputType[$key];
440
+ $this->mapping[$attr]['limit'] = $limit[$key];
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ // Make Product feed array according to mapping
447
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
448
+ $i = 0;
449
+ foreach ($this->mapping as $attr => $rules) {
450
+ if (array_key_exists($rules['value'], $value)) {
451
+
452
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
453
+ // Format According to output type
454
+ if ($rules['type'] == 2) {
455
+ $output = strip_tags($output);
456
+ } elseif ($rules['type'] == 3) {
457
+ $output = absint($output);
458
+ }
459
+ // Format According to output limit
460
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
461
+ $output = substr($output, 0, $rules['limit']);
462
+ }
463
+ $attr = trim($attr);
464
+ $this->products[$key][$attr] = trim($output);
465
+ } else {
466
+ if (!empty($default[$i])) {
467
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
468
+ if ($rules['type'] == 2) {
469
+ $output = strip_tags($output);
470
+ } elseif ($rules['type'] == 3) {
471
+ $output = absint($output);
472
+ }
473
+ // Format According to output limit
474
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
475
+ $output = substr($output, 0, $rules['limit']);
476
+ }
477
+ $attr = trim($attr);
478
+ $this->products[$key][$attr] = trim($output);
479
+ }
480
+ }
481
+ $i++;
482
+ }
483
+ }
484
+
485
+
486
+ return $this->products;
487
+ }
488
+
489
+ /**
490
+ * Change the products old array key and set new
491
+ *
492
+ * @param string $from Attribute Before
493
+ * @param string $to Attribute After
494
+ * @param bool $cdata Enclose Feed value
495
+ */
496
+ public function mapAttribute($from, $to, $cdata = false)
497
+ {
498
+ $i = 0;
499
+ foreach ($this->products as $no => $product) {
500
+ foreach ($product as $key => $value) {
501
+ if ($key == $from) {
502
+ unset($this->products[$no][$from]);
503
+ if ($from == 'images') {
504
+ $this->products[$no][$to] = $value;
505
+ } else {
506
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
507
+ }
508
+
509
+ }
510
+ }
511
+ $i++;
512
+ }
513
+ }
514
+
515
+ /**
516
+ * Format and Make the XML node for the Feed
517
+ *
518
+ * @param $attribute
519
+ * @param $value
520
+ * @param bool $cdata
521
+ * @param bool $stripHTML
522
+ * @param bool $utf8encode
523
+ * @param string $space
524
+ * @return string
525
+ */
526
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
527
+ {
528
+ //Make single line for XML
529
+ $c_leader = '';
530
+ $c_footer = '';
531
+ if ($cdata) {
532
+ $c_leader = '<![CDATA[';
533
+ $c_footer = ']]>';
534
+ }
535
+ //Allow force strip HTML
536
+ if ($stripHTML)
537
+ $value = strip_tags(html_entity_decode($value));
538
+
539
+
540
+ if ($utf8encode || $utf8encode == 1) {
541
+ $value = utf8_encode($value);
542
+ $attribute = utf8_encode($attribute);
543
+ }
544
+
545
+
546
+ if (!$cdata)
547
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
548
+
549
+ if (gettype($value) == 'array')
550
+ $value = json_encode($value);
551
+
552
+
553
+ return '
554
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
555
+ }
556
+
557
+ /**
558
+ * Responsible to change product array key
559
+ *
560
+ * @param $array
561
+ * @param $old_key
562
+ * @param $new_key
563
+ * @return array
564
+ */
565
+ function change_key($array, $old_key, $new_key)
566
+ {
567
+ foreach ($this->products as $no => $product) {
568
+ if (!array_key_exists($old_key, $product))
569
+ return $array;
570
+
571
+ $keys = array_keys($array);
572
+ $keys[array_search($old_key, $keys)] = $new_key;
573
+ }
574
+ return array_combine($keys, $array);
575
+ }
576
+
577
+ /**
578
+ * Responsible to make XML feed header
579
+ * @return string
580
+ */
581
+ public function get_feed_header()
582
+ {
583
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
584
+ <products>';
585
+ $output .= "\n";
586
+ return $output;
587
+ }
588
+
589
+ /**
590
+ * Responsible to make XML feed body
591
+ * @var array $item Product array
592
+ * @return string
593
+ */
594
+ public function get_feed($items)
595
+ {
596
+ $feed = "";
597
+ $feed .= $this->get_feed_header();
598
+ $feed .= "\n";
599
+ foreach ($items as $item => $products) {
600
+ $feed .= " <" . $this->feedWrapper . ">";
601
+ foreach ($products as $key => $value) {
602
+ if (!empty($value))
603
+ $feed .= $value;
604
+ }
605
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
606
+ }
607
+ $feed .= $this->get_feed_footer();
608
+
609
+ return $feed;
610
+ }
611
+
612
+ /**
613
+ * Responsible to make XML feed footer
614
+ * @return string
615
+ */
616
+ public function get_feed_footer()
617
+ {
618
+ $footer = " </products>";
619
+ return $footer;
620
+ }
621
+
622
+ /**
623
+ * Responsible to make TXT feed
624
+ * @return string
625
+ */
626
+ public function get_txt_feed()
627
+ {
628
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
629
+ $headers = array_keys($this->products[0]);
630
+ $feed[] = $headers;
631
+ foreach ($this->products as $no => $product) {
632
+ $row = array();
633
+ foreach ($headers as $key => $header) {
634
+ $row[] = $product[$header];
635
+ }
636
+ $feed[] = $row;
637
+ }
638
+ $str = "";
639
+ foreach ($feed as $fields) {
640
+ $str .= implode("\t", $fields) . "\n";
641
+ }
642
+ return $str;
643
+ }
644
+ return false;
645
+ }
646
+
647
+ /**
648
+ * Responsible to make CSV feed
649
+ * @return string
650
+ */
651
+ public function get_csv_feed()
652
+ {
653
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
654
+ $headers = array_keys($this->products[0]);
655
+ $feed[] = $headers;
656
+ foreach ($this->products as $no => $product) {
657
+ $row = array();
658
+ foreach ($headers as $key => $header) {
659
+ $row[] = $product[$header];
660
+ }
661
+ $feed[] = $row;
662
+ }
663
+
664
+ return $feed;
665
+ }
666
+ return false;
667
+ }
668
  }
includes/feeds/class-woo-feed-bing.php CHANGED
@@ -1,651 +1,651 @@
1
- <?php
2
-
3
- /**
4
- * Class Bing
5
- *
6
- * Responsible for processing and generating feed for Bing.com
7
- *
8
- * @since 1.0.0
9
- * @package Bing
10
- *
11
- */
12
- class Bing
13
- {
14
-
15
- /**
16
- * This variable is responsible for holding all product attributes and their values
17
- *
18
- * @since 1.0.0
19
- * @var array $products Contains all the product attributes to generate feed
20
- * @access public
21
- */
22
- public $products;
23
-
24
- /**
25
- * This variable is responsible for holding feed configuration form values
26
- *
27
- * @since 1.0.0
28
- * @var Bing $rules Contains feed configuration form values
29
- * @access public
30
- */
31
- public $rules;
32
-
33
- /**
34
- * This variable is responsible for mapping store attributes to merchant attribute
35
- *
36
- * @since 1.0.0
37
- * @var Bing $mapping Map store attributes to merchant attribute
38
- * @access public
39
- */
40
- public $mapping;
41
-
42
- /**
43
- * This variable is responsible for generate error logs
44
- *
45
- * @since 1.0.0
46
- * @var Bing $errorLog Generate error logs
47
- * @access public
48
- */
49
- public $errorLog;
50
-
51
- /**
52
- * This variable is responsible for making error number
53
- *
54
- * @since 1.0.0
55
- * @var Bing $errorCounter Generate error number
56
- * @access public
57
- */
58
- public $errorCounter;
59
-
60
- /**
61
- * Feed Wrapper text for enclosing each product information
62
- *
63
- * @since 1.0.0
64
- * @var Bing $feedWrapper Feed Wrapper text
65
- * @access public
66
- */
67
- private $feedWrapper = 'product';
68
-
69
- /**
70
- * Define the core functionality to generate feed.
71
- *
72
- * Set the feed rules. Map products according to the rules and Check required attributes
73
- * and their values according to merchant specification.
74
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
- * @since 1.0.0
76
- */
77
- public function __construct($feedRule)
78
- {
79
- $this->errorCounter = 0;
80
- $this->rules = $feedRule;
81
- $this->mapProductsByRules();
82
- //$this->formatRequiredField();
83
- //$this->filterProductValues();
84
- if ($this->rules['feedType'] == 'xml') {
85
- $this->mapAttributeForXML();
86
- } else {
87
- $this->mapAttributeForCSVTEXT();
88
- }
89
- }
90
-
91
- /**
92
- * Configure merchant attributes for XML feed
93
- */
94
- public function mapAttributeForXML()
95
- {
96
- //Basic product information
97
-
98
- if ( is_countable( $this->products ) && count( $this->products ) ) {
99
- foreach ($this->products as $key => $values) {
100
- foreach ($values as $attr => $value) {
101
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
102
- }
103
- }
104
- }
105
- }
106
-
107
- /**
108
- * Configure merchant attributes for CSV and TXT feed
109
- */
110
- public function mapAttributeForCSVTEXT()
111
- {
112
- //Basic product information
113
-
114
- if ( is_countable( $this->products ) && count( $this->products ) ) {
115
- foreach ($this->products as $key => $values) {
116
- foreach ($values as $attr => $value) {
117
- //Allow force strip HTML
118
-
119
- $value = strip_tags(html_entity_decode($value));
120
-
121
- $value = utf8_encode($value);
122
- $attr = utf8_encode($attr);
123
-
124
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
-
126
- if (gettype($value) == 'array')
127
- $value = json_encode($value);
128
-
129
- $this->products[$key][$attr] = $value;
130
- }
131
- }
132
- }
133
- }
134
-
135
- /**
136
- * Check all the required attributes and make error message
137
- */
138
- public function formatRequiredField()
139
- {
140
- foreach ($this->products as $no => $product) {
141
- $upn = 0;
142
- if (array_key_exists('MerchantProductID', $product)) {
143
- $id = $product['MerchantProductID'];
144
- } else {
145
- $id = $product['Title'];
146
- }
147
-
148
- if (!array_key_exists('MerchantProductID', $product)) {
149
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>MerchantProductID</b>] Missing for <b>$id</b>.";
150
- $this->errorCounter++;
151
- }
152
-
153
-
154
- if (!array_key_exists('Title', $product)) {
155
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
156
- $this->errorCounter++;
157
- }
158
-
159
- if (!array_key_exists('ProductURL', $product)) {
160
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>ProductURL</b>] Missing for <b>$id</b>.";
161
- $this->errorCounter++;
162
- }
163
-
164
- if (!array_key_exists('Price', $product)) {
165
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Price</b>] Missing for <b>$id</b>.";
166
- $this->errorCounter++;
167
- }
168
-
169
- if (!array_key_exists('Description', $product)) {
170
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
171
- $this->errorCounter++;
172
- }
173
-
174
- if (!array_key_exists('ImageURL', $product)) {
175
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>ImageURL</b>] Missing for <b>$id</b>.";
176
- $this->errorCounter++;
177
- }
178
-
179
- }
180
- }
181
-
182
- /**
183
- * Return Feed
184
- *
185
- * @return array|bool|string
186
- */
187
- public function returnFinalProduct()
188
- {
189
- if ($this->rules['feedType'] == 'xml') {
190
- return $this->get_feed($this->products);
191
- } elseif ($this->rules['feedType'] == 'txt') {
192
- return $this->get_txt_feed();
193
- } elseif ($this->rules['feedType'] == 'csv') {
194
- return $this->get_csv_feed();
195
- }
196
- return false;
197
- }
198
-
199
- /**
200
- * Check product's attribute value according to merchant specifications
201
- */
202
- public function filterProductValues()
203
- {
204
- $getProduct = new Woo_Feed_Products();
205
- $products = $this->products;
206
-
207
- foreach ($products as $no => $product) {
208
- if (array_key_exists('MerchantProductID', $product)) {
209
- $id = $product['MerchantProductID'];
210
- } else {
211
- $id = $product['Title'];
212
- }
213
- // echo "<pre>";
214
- // print_r($product);
215
- foreach ($product as $key => $value) {
216
-
217
-
218
- switch ($key) {
219
- case "MerchantProductID":
220
- if (strlen($value) > 100) {
221
- $this->errorLog[$this->errorCounter] = "[<b>MerchantProductID</b>] is more that 100 character for $id.";
222
- $this->errorCounter++;
223
- }
224
- break;
225
- case "Title":
226
- if (strlen($value) > 255) {
227
- $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 255 character for $id.";
228
- $this->errorCounter++;
229
- }
230
- break;
231
- case "Brand":
232
- if (strlen($value) > 1500) {
233
- $this->errorLog[$this->errorCounter] = "[<b>Brand</b>] is more that 1500 character for $id.";
234
- $this->errorCounter++;
235
- }
236
- break;
237
- case "MPN":
238
- if (strlen($value) > 255) {
239
- $this->errorLog[$this->errorCounter] = "[<b>MPN</b>] is more that 255 character for $id.";
240
- $this->errorCounter++;
241
- }
242
- break;
243
- case "UPC":
244
- if (strlen($value) > 12) {
245
- $this->errorLog[$this->errorCounter] = "[<b>UPC</b>] is more that 12 character for $id.";
246
- $this->errorCounter++;
247
- }
248
- break;
249
- case "ISBN":
250
- if (strlen($value) > 13) {
251
- $this->errorLog[$this->errorCounter] = "[<b>ISBN</b>] is more that 13 character for $id.";
252
- $this->errorCounter++;
253
- }
254
- break;
255
- case "ProductURL":
256
- if (strlen($value) > 2000) {
257
- $this->errorLog[$this->errorCounter] = "[<b>ProductURL</b>] is more that 2000 character for $id.";
258
- $this->errorCounter++;
259
- }
260
- break;
261
- case "Price":
262
- if (!is_numeric($value)) {
263
- $this->errorLog[$this->errorCounter] = "[<b>Price</b>] should be numeric for $id.";
264
- $this->errorCounter++;
265
- }
266
- break;
267
- case "Availability":
268
- if ($value == 'in stock') {
269
- $this->products[$no][$key] = "In Stock";
270
- } else if ($value == 'out of stock') {
271
- $this->products[$no][$key] = "Out of Stock";
272
- }
273
- if (strlen($this->products[$no][$key]) > 15) {
274
- $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] is more that 15 character for $id.";
275
- $this->errorCounter++;
276
- }
277
- break;
278
- case "Description":
279
- if (strlen($value) > 5000) {
280
- $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 5000 character for $id.";
281
- $this->errorCounter++;
282
- }
283
- break;
284
- case "ImageURL":
285
- if (strlen($value) > 1000) {
286
- $this->errorLog[$this->errorCounter] = "[<b>ImageURL</b>] is more that 1000 character for $id.";
287
- $this->errorCounter++;
288
- }
289
- break;
290
- case "Shipping":
291
- if (strlen($value) > 255) {
292
- $this->errorLog[$this->errorCounter] = "[<b>Shipping</b>] is more that 255 character for $id.";
293
- $this->errorCounter++;
294
- }
295
- break;
296
- case "MerchantCategory":
297
- if (strlen($value) > 255) {
298
- $this->errorLog[$this->errorCounter] = "[<b>Shipping</b>] is more that 255 character for $id.";
299
- $this->errorCounter++;
300
- }
301
- break;
302
- case "Condition":
303
- if (strlen($this->products[$no][$key]) > 15) {
304
- $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] is more that 15 character for $id.";
305
- $this->errorCounter++;
306
- }
307
- break;
308
- default:
309
- break;
310
- }
311
- }
312
- }
313
- }
314
-
315
- /**
316
- * Return Dynamic Category Mapping Values by Parent Product Id
317
- *
318
- * @param string $mappingName Category Mapping Name
319
- * @param int $parent Parent id of the product
320
- * @return mixed
321
- */
322
- public function get_category_mapping_value($mappingName, $parent)
323
- {
324
- $getValue = unserialize(get_option($mappingName));
325
- $mapp = array_reverse($getValue['cmapping'], true);
326
- $categories = get_the_terms($parent, 'product_cat');
327
-
328
- foreach ($categories as $key => $category) {
329
- if (!empty($mapp[$category->term_id]))
330
- return $mapp[$category->term_id];
331
- }
332
- return false;
333
- }
334
-
335
- /**
336
- * Configure the feed according to the rules
337
- * @return Shopping
338
- */
339
- public function mapProductsByRules()
340
- {
341
- /**
342
- * Get WooCommerce Products
343
- * @package Woo_Feed_Products
344
- */
345
- $products = new Woo_Feed_Products();
346
-
347
- /**
348
- * This variable contain selected Woo attributes from feed making form
349
- *
350
- * @since 1.0.0
351
- * @var array $attributes contain selected Woo attributes from feed making form
352
- */
353
- $attributes = $this->rules['attributes'];
354
- /**
355
- * This variable contain selected Prefix Values from feed making form
356
- *
357
- * @since 1.0.0
358
- * @var array $prefix Prefix Values from feed making form
359
- */
360
- $prefix = $this->rules['prefix'];
361
- /**
362
- * This variable contain selected Prefix Values from feed making form
363
- *
364
- * @since 1.0.0
365
- * @var array $suffix Suffix Values from feed making form
366
- */
367
- $suffix = $this->rules['suffix'];
368
- /**
369
- * This variable contain selected Output Types from feed making form
370
- *
371
- * @since 1.0.0
372
- * @var array $outputType Output Types from feed making form
373
- */
374
- $outputType = $this->rules['output_type'];
375
-
376
- /**
377
- * This variable contain selected Output Limit from feed making form
378
- *
379
- * @since 1.0.0
380
- * @var array $limit Output Limit from feed making form
381
- */
382
- $limit = $this->rules['limit'];
383
- /**
384
- * This variable contain selected Merchant attributes from feed making form
385
- *
386
- * @since 1.0.0
387
- * @var array $merchantAttributes contain selected Woo attributes from feed making form
388
- */
389
- $merchantAttributes = $this->rules['mattributes'];
390
- /**
391
- * This variable contain attribute types from feed making form
392
- *
393
- * @since 1.0.0
394
- * @var array $type contain attribute types from feed making form
395
- */
396
- $type = $this->rules['type'];
397
- /**
398
- * This variable contain manual output of attribute from feed making form
399
- *
400
- * @since 1.0.0
401
- * @var array $default contain manual output of attribute
402
- */
403
- $default = $this->rules['default'];
404
-
405
- /**
406
- * This variable contain feed type
407
- *
408
- * @since 1.0.0
409
- * @var array $feedType contain feed type
410
- */
411
- $feedType = $this->rules['feedType'];
412
-
413
- // Map Merchant Attributes and Woo Attributes
414
- if (count($merchantAttributes)) {
415
- foreach ($merchantAttributes as $key => $attr) {
416
- if (!empty($attr) && !empty($attributes[$key])) {
417
- if ($type[$key] == 'attribute') {
418
- $this->mapping[$attr]['value'] = $attributes[$key];
419
- $this->mapping[$attr]['suffix'] = $suffix[$key];
420
- $this->mapping[$attr]['prefix'] = $prefix[$key];
421
- $this->mapping[$attr]['type'] = $outputType[$key];
422
- $this->mapping[$attr]['limit'] = $limit[$key];
423
- }
424
- } else if (empty($attributes[$key])) {
425
- if ($type[$key] == 'pattern') {
426
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
427
- $this->mapping[$attr]['suffix'] = $suffix[$key];
428
- $this->mapping[$attr]['prefix'] = $prefix[$key];
429
- $this->mapping[$attr]['type'] = $outputType[$key];
430
- $this->mapping[$attr]['limit'] = $limit[$key];
431
- }
432
- }
433
- }
434
- }
435
-
436
- // Make Product feed array according to mapping
437
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
438
- $i = 0;
439
- foreach ($this->mapping as $attr => $rules) {
440
- if (array_key_exists($rules['value'], $value)) {
441
-
442
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
443
- // Format According to output type
444
- if ($rules['type'] == 2) {
445
- $output = strip_tags($output);
446
- } elseif ($rules['type'] == 3) {
447
- $output = absint($output);
448
- }
449
- // Format According to output limit
450
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
451
- $output = substr($output, 0, $rules['limit']);
452
- }
453
- $attr = trim($attr);
454
- $this->products[$key][$attr] = trim($output);
455
- } else {
456
- if (!empty($default[$i])) {
457
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
458
- if ($rules['type'] == 2) {
459
- $output = strip_tags($output);
460
- } elseif ($rules['type'] == 3) {
461
- $output = absint($output);
462
- }
463
- // Format According to output limit
464
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
465
- $output = substr($output, 0, $rules['limit']);
466
- }
467
- $attr = trim($attr);
468
- $this->products[$key][$attr] = trim($output);
469
- }
470
- }
471
- $i++;
472
- }
473
- }
474
-
475
- return $this->products;
476
- }
477
-
478
- /**
479
- * Change the products old array key and set new
480
- *
481
- * @param string $from Attribute Before
482
- * @param string $to Attribute After
483
- * @param bool $cdata Enclose Feed value
484
- */
485
- public function mapAttribute($from, $to, $cdata = false)
486
- {
487
- $i = 0;
488
- foreach ($this->products as $no => $product) {
489
- foreach ($product as $key => $value) {
490
- if ($key == $from) {
491
- unset($this->products[$no][$from]);
492
- if ($from == 'images') {
493
- $this->products[$no][$to] = $value;
494
- } else {
495
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
496
- }
497
-
498
- }
499
- }
500
- $i++;
501
- }
502
- }
503
-
504
- /**
505
- * Format and Make the XML node for the Feed
506
- *
507
- * @param $attribute
508
- * @param $value
509
- * @param bool $cdata
510
- * @param bool $stripHTML
511
- * @param bool $utf8encode
512
- * @param string $space
513
- * @return string
514
- */
515
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
516
- {
517
- //Make single line for XML
518
- $c_leader = '';
519
- $c_footer = '';
520
- if ($cdata) {
521
- $c_leader = '<![CDATA[';
522
- $c_footer = ']]>';
523
- }
524
- //Allow force strip HTML
525
- if ($stripHTML)
526
- $value = strip_tags(html_entity_decode($value));
527
-
528
- if ($utf8encode || $utf8encode == 1) {
529
- $value = utf8_encode($value);
530
- $attribute = utf8_encode($attribute);
531
- }
532
-
533
- if (!$cdata)
534
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
535
-
536
- if (gettype($value) == 'array')
537
- $value = json_encode($value);
538
-
539
- return '
540
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
541
- }
542
-
543
- /**
544
- * Responsible to change product array key
545
- *
546
- * @param $array
547
- * @param $old_key
548
- * @param $new_key
549
- * @return array
550
- */
551
- public function change_key($array, $old_key, $new_key)
552
- {
553
- foreach ($this->products as $no => $product) {
554
- if (!array_key_exists($old_key, $product))
555
- return $array;
556
-
557
- $keys = array_keys($array);
558
- $keys[array_search($old_key, $keys)] = $new_key;
559
- }
560
- return array_combine($keys, $array);
561
- }
562
-
563
- /**
564
- * Responsible to make XML feed header
565
- * @return string
566
- */
567
- public function get_feed_header()
568
- {
569
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
570
- <products>';
571
- $output .= "\n";
572
- return $output;
573
- }
574
-
575
- /**
576
- * Responsible to make XML feed body
577
- * @var array $items Product array
578
- * @return string
579
- */
580
- public function get_feed($items)
581
- {
582
- $feed = "";
583
- $feed .= $this->get_feed_header();
584
- $feed .= "\n";
585
- foreach ($items as $item => $products) {
586
- $feed .= " <" . $this->feedWrapper . ">";
587
- foreach ($products as $key => $value) {
588
- if (!empty($value))
589
- $feed .= $value;
590
- }
591
- $feed .= "\n </" . $this->feedWrapper . ">\n";
592
- }
593
- $feed .= $this->get_feed_footer();
594
-
595
- return $feed;
596
- }
597
-
598
-
599
- /**
600
- * Responsible to make XML feed footer
601
- * @return string
602
- */
603
- public function get_feed_footer()
604
- {
605
- $footer = " </products>";
606
- return $footer;
607
- }
608
-
609
- /**
610
- * Responsible to make TXT feed
611
- * @return string
612
- */
613
- public function get_txt_feed()
614
- {
615
- if ( is_countable( $this->products ) && count( $this->products ) ) {
616
- $headers = array_keys($this->products[0]);
617
- $feed[] = $headers;
618
- foreach ($this->products as $no => $product) {
619
- $row = array();
620
- foreach ($headers as $key => $header) {
621
- $row[] = $product[$header];
622
- }
623
- $feed[] = $row;
624
- }
625
- $str = "";
626
- foreach ($feed as $fields) {
627
- $str .= implode("\t", $fields) . "\n";
628
- }
629
- return $str;
630
- }
631
- return false;
632
- }
633
-
634
- public function get_csv_feed()
635
- {
636
- if ( is_countable( $this->products ) && count( $this->products ) ) {
637
- $headers = array_keys($this->products[0]);
638
- $feed[] = $headers;
639
- foreach ($this->products as $no => $product) {
640
- $row = array();
641
- foreach ($headers as $key => $header) {
642
- $row[] = $product[$header];
643
- }
644
- $feed[] = $row;
645
- }
646
-
647
- return $feed;
648
- }
649
- return false;
650
- }
651
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Bing
5
+ *
6
+ * Responsible for processing and generating feed for Bing.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Bing
10
+ *
11
+ */
12
+ class Bing
13
+ {
14
+
15
+ /**
16
+ * This variable is responsible for holding all product attributes and their values
17
+ *
18
+ * @since 1.0.0
19
+ * @var array $products Contains all the product attributes to generate feed
20
+ * @access public
21
+ */
22
+ public $products;
23
+
24
+ /**
25
+ * This variable is responsible for holding feed configuration form values
26
+ *
27
+ * @since 1.0.0
28
+ * @var Bing $rules Contains feed configuration form values
29
+ * @access public
30
+ */
31
+ public $rules;
32
+
33
+ /**
34
+ * This variable is responsible for mapping store attributes to merchant attribute
35
+ *
36
+ * @since 1.0.0
37
+ * @var Bing $mapping Map store attributes to merchant attribute
38
+ * @access public
39
+ */
40
+ public $mapping;
41
+
42
+ /**
43
+ * This variable is responsible for generate error logs
44
+ *
45
+ * @since 1.0.0
46
+ * @var Bing $errorLog Generate error logs
47
+ * @access public
48
+ */
49
+ public $errorLog;
50
+
51
+ /**
52
+ * This variable is responsible for making error number
53
+ *
54
+ * @since 1.0.0
55
+ * @var Bing $errorCounter Generate error number
56
+ * @access public
57
+ */
58
+ public $errorCounter;
59
+
60
+ /**
61
+ * Feed Wrapper text for enclosing each product information
62
+ *
63
+ * @since 1.0.0
64
+ * @var Bing $feedWrapper Feed Wrapper text
65
+ * @access public
66
+ */
67
+ private $feedWrapper = 'product';
68
+
69
+ /**
70
+ * Define the core functionality to generate feed.
71
+ *
72
+ * Set the feed rules. Map products according to the rules and Check required attributes
73
+ * and their values according to merchant specification.
74
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
+ * @since 1.0.0
76
+ */
77
+ public function __construct($feedRule)
78
+ {
79
+ $this->errorCounter = 0;
80
+ $this->rules = $feedRule;
81
+ $this->mapProductsByRules();
82
+ //$this->formatRequiredField();
83
+ //$this->filterProductValues();
84
+ if ($this->rules['feedType'] == 'xml') {
85
+ $this->mapAttributeForXML();
86
+ } else {
87
+ $this->mapAttributeForCSVTEXT();
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Configure merchant attributes for XML feed
93
+ */
94
+ public function mapAttributeForXML()
95
+ {
96
+ //Basic product information
97
+
98
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
99
+ foreach ($this->products as $key => $values) {
100
+ foreach ($values as $attr => $value) {
101
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Configure merchant attributes for CSV and TXT feed
109
+ */
110
+ public function mapAttributeForCSVTEXT()
111
+ {
112
+ //Basic product information
113
+
114
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
115
+ foreach ($this->products as $key => $values) {
116
+ foreach ($values as $attr => $value) {
117
+ //Allow force strip HTML
118
+
119
+ $value = strip_tags(html_entity_decode($value));
120
+
121
+ $value = utf8_encode($value);
122
+ $attr = utf8_encode($attr);
123
+
124
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
+
126
+ if (gettype($value) == 'array')
127
+ $value = json_encode($value);
128
+
129
+ $this->products[$key][$attr] = $value;
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Check all the required attributes and make error message
137
+ */
138
+ public function formatRequiredField()
139
+ {
140
+ foreach ($this->products as $no => $product) {
141
+ $upn = 0;
142
+ if (array_key_exists('MerchantProductID', $product)) {
143
+ $id = $product['MerchantProductID'];
144
+ } else {
145
+ $id = $product['Title'];
146
+ }
147
+
148
+ if (!array_key_exists('MerchantProductID', $product)) {
149
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>MerchantProductID</b>] Missing for <b>$id</b>.";
150
+ $this->errorCounter++;
151
+ }
152
+
153
+
154
+ if (!array_key_exists('Title', $product)) {
155
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
156
+ $this->errorCounter++;
157
+ }
158
+
159
+ if (!array_key_exists('ProductURL', $product)) {
160
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>ProductURL</b>] Missing for <b>$id</b>.";
161
+ $this->errorCounter++;
162
+ }
163
+
164
+ if (!array_key_exists('Price', $product)) {
165
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Price</b>] Missing for <b>$id</b>.";
166
+ $this->errorCounter++;
167
+ }
168
+
169
+ if (!array_key_exists('Description', $product)) {
170
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
171
+ $this->errorCounter++;
172
+ }
173
+
174
+ if (!array_key_exists('ImageURL', $product)) {
175
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>ImageURL</b>] Missing for <b>$id</b>.";
176
+ $this->errorCounter++;
177
+ }
178
+
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Return Feed
184
+ *
185
+ * @return array|bool|string
186
+ */
187
+ public function returnFinalProduct()
188
+ {
189
+ if ($this->rules['feedType'] == 'xml') {
190
+ return $this->get_feed($this->products);
191
+ } elseif ($this->rules['feedType'] == 'txt') {
192
+ return $this->get_txt_feed();
193
+ } elseif ($this->rules['feedType'] == 'csv') {
194
+ return $this->get_csv_feed();
195
+ }
196
+ return false;
197
+ }
198
+
199
+ /**
200
+ * Check product's attribute value according to merchant specifications
201
+ */
202
+ public function filterProductValues()
203
+ {
204
+ $getProduct = new Woo_Feed_Products();
205
+ $products = $this->products;
206
+
207
+ foreach ($products as $no => $product) {
208
+ if (array_key_exists('MerchantProductID', $product)) {
209
+ $id = $product['MerchantProductID'];
210
+ } else {
211
+ $id = $product['Title'];
212
+ }
213
+ // echo "<pre>";
214
+ // print_r($product);
215
+ foreach ($product as $key => $value) {
216
+
217
+
218
+ switch ($key) {
219
+ case "MerchantProductID":
220
+ if (strlen($value) > 100) {
221
+ $this->errorLog[$this->errorCounter] = "[<b>MerchantProductID</b>] is more that 100 character for $id.";
222
+ $this->errorCounter++;
223
+ }
224
+ break;
225
+ case "Title":
226
+ if (strlen($value) > 255) {
227
+ $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 255 character for $id.";
228
+ $this->errorCounter++;
229
+ }
230
+ break;
231
+ case "Brand":
232
+ if (strlen($value) > 1500) {
233
+ $this->errorLog[$this->errorCounter] = "[<b>Brand</b>] is more that 1500 character for $id.";
234
+ $this->errorCounter++;
235
+ }
236
+ break;
237
+ case "MPN":
238
+ if (strlen($value) > 255) {
239
+ $this->errorLog[$this->errorCounter] = "[<b>MPN</b>] is more that 255 character for $id.";
240
+ $this->errorCounter++;
241
+ }
242
+ break;
243
+ case "UPC":
244
+ if (strlen($value) > 12) {
245
+ $this->errorLog[$this->errorCounter] = "[<b>UPC</b>] is more that 12 character for $id.";
246
+ $this->errorCounter++;
247
+ }
248
+ break;
249
+ case "ISBN":
250
+ if (strlen($value) > 13) {
251
+ $this->errorLog[$this->errorCounter] = "[<b>ISBN</b>] is more that 13 character for $id.";
252
+ $this->errorCounter++;
253
+ }
254
+ break;
255
+ case "ProductURL":
256
+ if (strlen($value) > 2000) {
257
+ $this->errorLog[$this->errorCounter] = "[<b>ProductURL</b>] is more that 2000 character for $id.";
258
+ $this->errorCounter++;
259
+ }
260
+ break;
261
+ case "Price":
262
+ if (!is_numeric($value)) {
263
+ $this->errorLog[$this->errorCounter] = "[<b>Price</b>] should be numeric for $id.";
264
+ $this->errorCounter++;
265
+ }
266
+ break;
267
+ case "Availability":
268
+ if ($value == 'in stock') {
269
+ $this->products[$no][$key] = "In Stock";
270
+ } else if ($value == 'out of stock') {
271
+ $this->products[$no][$key] = "Out of Stock";
272
+ }
273
+ if (strlen($this->products[$no][$key]) > 15) {
274
+ $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] is more that 15 character for $id.";
275
+ $this->errorCounter++;
276
+ }
277
+ break;
278
+ case "Description":
279
+ if (strlen($value) > 5000) {
280
+ $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 5000 character for $id.";
281
+ $this->errorCounter++;
282
+ }
283
+ break;
284
+ case "ImageURL":
285
+ if (strlen($value) > 1000) {
286
+ $this->errorLog[$this->errorCounter] = "[<b>ImageURL</b>] is more that 1000 character for $id.";
287
+ $this->errorCounter++;
288
+ }
289
+ break;
290
+ case "Shipping":
291
+ if (strlen($value) > 255) {
292
+ $this->errorLog[$this->errorCounter] = "[<b>Shipping</b>] is more that 255 character for $id.";
293
+ $this->errorCounter++;
294
+ }
295
+ break;
296
+ case "MerchantCategory":
297
+ if (strlen($value) > 255) {
298
+ $this->errorLog[$this->errorCounter] = "[<b>Shipping</b>] is more that 255 character for $id.";
299
+ $this->errorCounter++;
300
+ }
301
+ break;
302
+ case "Condition":
303
+ if (strlen($this->products[$no][$key]) > 15) {
304
+ $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] is more that 15 character for $id.";
305
+ $this->errorCounter++;
306
+ }
307
+ break;
308
+ default:
309
+ break;
310
+ }
311
+ }
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Return Dynamic Category Mapping Values by Parent Product Id
317
+ *
318
+ * @param string $mappingName Category Mapping Name
319
+ * @param int $parent Parent id of the product
320
+ * @return mixed
321
+ */
322
+ public function get_category_mapping_value($mappingName, $parent)
323
+ {
324
+ $getValue = unserialize(get_option($mappingName));
325
+ $mapp = array_reverse($getValue['cmapping'], true);
326
+ $categories = get_the_terms($parent, 'product_cat');
327
+
328
+ foreach ($categories as $key => $category) {
329
+ if (!empty($mapp[$category->term_id]))
330
+ return $mapp[$category->term_id];
331
+ }
332
+ return false;
333
+ }
334
+
335
+ /**
336
+ * Configure the feed according to the rules
337
+ * @return Shopping
338
+ */
339
+ public function mapProductsByRules()
340
+ {
341
+ /**
342
+ * Get WooCommerce Products
343
+ * @package Woo_Feed_Products
344
+ */
345
+ $products = new Woo_Feed_Products();
346
+
347
+ /**
348
+ * This variable contain selected Woo attributes from feed making form
349
+ *
350
+ * @since 1.0.0
351
+ * @var array $attributes contain selected Woo attributes from feed making form
352
+ */
353
+ $attributes = $this->rules['attributes'];
354
+ /**
355
+ * This variable contain selected Prefix Values from feed making form
356
+ *
357
+ * @since 1.0.0
358
+ * @var array $prefix Prefix Values from feed making form
359
+ */
360
+ $prefix = $this->rules['prefix'];
361
+ /**
362
+ * This variable contain selected Prefix Values from feed making form
363
+ *
364
+ * @since 1.0.0
365
+ * @var array $suffix Suffix Values from feed making form
366
+ */
367
+ $suffix = $this->rules['suffix'];
368
+ /**
369
+ * This variable contain selected Output Types from feed making form
370
+ *
371
+ * @since 1.0.0
372
+ * @var array $outputType Output Types from feed making form
373
+ */
374
+ $outputType = $this->rules['output_type'];
375
+
376
+ /**
377
+ * This variable contain selected Output Limit from feed making form
378
+ *
379
+ * @since 1.0.0
380
+ * @var array $limit Output Limit from feed making form
381
+ */
382
+ $limit = $this->rules['limit'];
383
+ /**
384
+ * This variable contain selected Merchant attributes from feed making form
385
+ *
386
+ * @since 1.0.0
387
+ * @var array $merchantAttributes contain selected Woo attributes from feed making form
388
+ */
389
+ $merchantAttributes = $this->rules['mattributes'];
390
+ /**
391
+ * This variable contain attribute types from feed making form
392
+ *
393
+ * @since 1.0.0
394
+ * @var array $type contain attribute types from feed making form
395
+ */
396
+ $type = $this->rules['type'];
397
+ /**
398
+ * This variable contain manual output of attribute from feed making form
399
+ *
400
+ * @since 1.0.0
401
+ * @var array $default contain manual output of attribute
402
+ */
403
+ $default = $this->rules['default'];
404
+
405
+ /**
406
+ * This variable contain feed type
407
+ *
408
+ * @since 1.0.0
409
+ * @var array $feedType contain feed type
410
+ */
411
+ $feedType = $this->rules['feedType'];
412
+
413
+ // Map Merchant Attributes and Woo Attributes
414
+ if (count($merchantAttributes)) {
415
+ foreach ($merchantAttributes as $key => $attr) {
416
+ if (!empty($attr) && !empty($attributes[$key])) {
417
+ if ($type[$key] == 'attribute') {
418
+ $this->mapping[$attr]['value'] = $attributes[$key];
419
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
420
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
421
+ $this->mapping[$attr]['type'] = $outputType[$key];
422
+ $this->mapping[$attr]['limit'] = $limit[$key];
423
+ }
424
+ } else if (empty($attributes[$key])) {
425
+ if ($type[$key] == 'pattern') {
426
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
427
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
428
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
429
+ $this->mapping[$attr]['type'] = $outputType[$key];
430
+ $this->mapping[$attr]['limit'] = $limit[$key];
431
+ }
432
+ }
433
+ }
434
+ }
435
+
436
+ // Make Product feed array according to mapping
437
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
438
+ $i = 0;
439
+ foreach ($this->mapping as $attr => $rules) {
440
+ if (array_key_exists($rules['value'], $value)) {
441
+
442
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
443
+ // Format According to output type
444
+ if ($rules['type'] == 2) {
445
+ $output = strip_tags($output);
446
+ } elseif ($rules['type'] == 3) {
447
+ $output = absint($output);
448
+ }
449
+ // Format According to output limit
450
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
451
+ $output = substr($output, 0, $rules['limit']);
452
+ }
453
+ $attr = trim($attr);
454
+ $this->products[$key][$attr] = trim($output);
455
+ } else {
456
+ if (!empty($default[$i])) {
457
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
458
+ if ($rules['type'] == 2) {
459
+ $output = strip_tags($output);
460
+ } elseif ($rules['type'] == 3) {
461
+ $output = absint($output);
462
+ }
463
+ // Format According to output limit
464
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
465
+ $output = substr($output, 0, $rules['limit']);
466
+ }
467
+ $attr = trim($attr);
468
+ $this->products[$key][$attr] = trim($output);
469
+ }
470
+ }
471
+ $i++;
472
+ }
473
+ }
474
+
475
+ return $this->products;
476
+ }
477
+
478
+ /**
479
+ * Change the products old array key and set new
480
+ *
481
+ * @param string $from Attribute Before
482
+ * @param string $to Attribute After
483
+ * @param bool $cdata Enclose Feed value
484
+ */
485
+ public function mapAttribute($from, $to, $cdata = false)
486
+ {
487
+ $i = 0;
488
+ foreach ($this->products as $no => $product) {
489
+ foreach ($product as $key => $value) {
490
+ if ($key == $from) {
491
+ unset($this->products[$no][$from]);
492
+ if ($from == 'images') {
493
+ $this->products[$no][$to] = $value;
494
+ } else {
495
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
496
+ }
497
+
498
+ }
499
+ }
500
+ $i++;
501
+ }
502
+ }
503
+
504
+ /**
505
+ * Format and Make the XML node for the Feed
506
+ *
507
+ * @param $attribute
508
+ * @param $value
509
+ * @param bool $cdata
510
+ * @param bool $stripHTML
511
+ * @param bool $utf8encode
512
+ * @param string $space
513
+ * @return string
514
+ */
515
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
516
+ {
517
+ //Make single line for XML
518
+ $c_leader = '';
519
+ $c_footer = '';
520
+ if ($cdata) {
521
+ $c_leader = '<![CDATA[';
522
+ $c_footer = ']]>';
523
+ }
524
+ //Allow force strip HTML
525
+ if ($stripHTML)
526
+ $value = strip_tags(html_entity_decode($value));
527
+
528
+ if ($utf8encode || $utf8encode == 1) {
529
+ $value = utf8_encode($value);
530
+ $attribute = utf8_encode($attribute);
531
+ }
532
+
533
+ if (!$cdata)
534
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
535
+
536
+ if (gettype($value) == 'array')
537
+ $value = json_encode($value);
538
+
539
+ return '
540
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
541
+ }
542
+
543
+ /**
544
+ * Responsible to change product array key
545
+ *
546
+ * @param $array
547
+ * @param $old_key
548
+ * @param $new_key
549
+ * @return array
550
+ */
551
+ public function change_key($array, $old_key, $new_key)
552
+ {
553
+ foreach ($this->products as $no => $product) {
554
+ if (!array_key_exists($old_key, $product))
555
+ return $array;
556
+
557
+ $keys = array_keys($array);
558
+ $keys[array_search($old_key, $keys)] = $new_key;
559
+ }
560
+ return array_combine($keys, $array);
561
+ }
562
+
563
+ /**
564
+ * Responsible to make XML feed header
565
+ * @return string
566
+ */
567
+ public function get_feed_header()
568
+ {
569
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
570
+ <products>';
571
+ $output .= "\n";
572
+ return $output;
573
+ }
574
+
575
+ /**
576
+ * Responsible to make XML feed body
577
+ * @var array $items Product array
578
+ * @return string
579
+ */
580
+ public function get_feed($items)
581
+ {
582
+ $feed = "";
583
+ $feed .= $this->get_feed_header();
584
+ $feed .= "\n";
585
+ foreach ($items as $item => $products) {
586
+ $feed .= " <" . $this->feedWrapper . ">";
587
+ foreach ($products as $key => $value) {
588
+ if (!empty($value))
589
+ $feed .= $value;
590
+ }
591
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
592
+ }
593
+ $feed .= $this->get_feed_footer();
594
+
595
+ return $feed;
596
+ }
597
+
598
+
599
+ /**
600
+ * Responsible to make XML feed footer
601
+ * @return string
602
+ */
603
+ public function get_feed_footer()
604
+ {
605
+ $footer = " </products>";
606
+ return $footer;
607
+ }
608
+
609
+ /**
610
+ * Responsible to make TXT feed
611
+ * @return string
612
+ */
613
+ public function get_txt_feed()
614
+ {
615
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
616
+ $headers = array_keys($this->products[0]);
617
+ $feed[] = $headers;
618
+ foreach ($this->products as $no => $product) {
619
+ $row = array();
620
+ foreach ($headers as $key => $header) {
621
+ $row[] = $product[$header];
622
+ }
623
+ $feed[] = $row;
624
+ }
625
+ $str = "";
626
+ foreach ($feed as $fields) {
627
+ $str .= implode("\t", $fields) . "\n";
628
+ }
629
+ return $str;
630
+ }
631
+ return false;
632
+ }
633
+
634
+ public function get_csv_feed()
635
+ {
636
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
637
+ $headers = array_keys($this->products[0]);
638
+ $feed[] = $headers;
639
+ foreach ($this->products as $no => $product) {
640
+ $row = array();
641
+ foreach ($headers as $key => $header) {
642
+ $row[] = $product[$header];
643
+ }
644
+ $feed[] = $row;
645
+ }
646
+
647
+ return $feed;
648
+ }
649
+ return false;
650
+ }
651
  }
includes/feeds/class-woo-feed-connexity.php CHANGED
@@ -1,668 +1,668 @@
1
- <?php
2
-
3
- /**
4
- * Class Connexity
5
- *
6
- * Responsible for processing and generating feed for Connexity.com
7
- *
8
- * @since 1.0.0
9
- * @package Connexity
10
- *
11
- */
12
- class Connexity
13
- {
14
-
15
- /**
16
- * This variable is responsible for holding all product attributes and their values
17
- *
18
- * @since 1.0.0
19
- * @var array $products Contains all the product attributes to generate feed
20
- * @access public
21
- */
22
- public $products;
23
-
24
- /**
25
- * This variable is responsible for holding feed configuration form values
26
- *
27
- * @since 1.0.0
28
- * @var Connexity $rules Contains feed configuration form values
29
- * @access public
30
- */
31
- public $rules;
32
-
33
- /**
34
- * This variable is responsible for mapping store attributes to merchant attribute
35
- *
36
- * @since 1.0.0
37
- * @var Connexity $mapping Map store attributes to merchant attribute
38
- * @access public
39
- */
40
- public $mapping;
41
-
42
- /**
43
- * This variable is responsible for generate error logs
44
- *
45
- * @since 1.0.0
46
- * @var Connexity $errorLog Generate error logs
47
- * @access public
48
- */
49
- public $errorLog;
50
-
51
- /**
52
- * This variable is responsible for making error number
53
- *
54
- * @since 1.0.0
55
- * @var Connexity $errorCounter Generate error number
56
- * @access public
57
- */
58
- public $errorCounter;
59
-
60
- /**
61
- * Feed Wrapper text for enclosing each product information
62
- *
63
- * @since 1.0.0
64
- * @var Connexity $feedWrapper Feed Wrapper text
65
- * @access public
66
- */
67
- private $feedWrapper;
68
-
69
- /**
70
- * Define the core functionality to generate feed.
71
- *
72
- * Set the feed rules. Map products according to the rules and Check required attributes
73
- * and their values according to merchant specification.
74
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
- * @since 1.0.0
76
- */
77
- public function __construct($feedRule)
78
- {
79
- $this->feedWrapper = 'product';
80
- $this->errorCounter = 0;
81
- $this->rules = $feedRule;
82
- $this->mapProductsByRules();
83
- $this->formatRequiredField();
84
- $this->filterProductValues();
85
- if ($this->rules['feedType'] == 'xml') {
86
- $this->mapAttributeForXML();
87
- } else {
88
- $this->mapAttributeForCSVTEXT();
89
- }
90
- }
91
-
92
- /**
93
- * Configure merchant attributes for XML feed
94
- */
95
- public function mapAttributeForXML()
96
- {
97
- //Basic product information
98
-
99
- if ( is_countable( $this->products ) && count( $this->products ) ) {
100
- foreach ($this->products as $key => $values) {
101
- foreach ($values as $attr => $value) {
102
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
103
- }
104
- }
105
- }
106
- }
107
-
108
- /**
109
- * Configure merchant attributes for CSV and TXT feed
110
- */
111
- public function mapAttributeForCSVTEXT()
112
- {
113
- //Basic product information
114
-
115
- if ( is_countable( $this->products ) && count( $this->products ) ) {
116
- foreach ($this->products as $key => $values) {
117
- foreach ($values as $attr => $value) {
118
- //Allow force strip HTML
119
- $value = strip_tags(html_entity_decode($value));
120
- if ($attr != 'Category') {
121
- $value = utf8_encode($value);
122
- $attr = utf8_encode($attr);
123
-
124
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
-
126
- if (gettype($value) == 'array')
127
- $value = json_encode($value);
128
- }
129
-
130
- $this->products[$key][$attr] = $value;
131
- }
132
- }
133
- }
134
- }
135
-
136
- /**
137
- * Check all the required attributes and make error message
138
- */
139
- public function formatRequiredField()
140
- {
141
- foreach ($this->products as $no => $product) {
142
- $upn = 0;
143
- if (array_key_exists('Unique ID', $product)) {
144
- $id = $product['Unique ID'];
145
- } else {
146
- $id = $product['Title'];
147
- }
148
-
149
- if (!array_key_exists('Unique ID', $product)) {
150
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique ID</b>] Missing for <b>$id</b>.";
151
- $this->errorCounter++;
152
- }
153
-
154
-
155
- if (!array_key_exists('Title', $product)) {
156
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
157
- $this->errorCounter++;
158
- }
159
-
160
- if (!array_key_exists('Description', $product)) {
161
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
162
- $this->errorCounter++;
163
- }
164
-
165
- if (!array_key_exists('Category', $product)) {
166
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Category</b>] Missing for <b>$id</b>.";
167
- $this->errorCounter++;
168
- }
169
-
170
- if (!array_key_exists('Product URL', $product)) {
171
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
172
- $this->errorCounter++;
173
- }
174
-
175
- if (!array_key_exists('Image URL', $product)) {
176
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
177
- $this->errorCounter++;
178
- }
179
-
180
- if (!array_key_exists('Condition', $product)) {
181
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
182
- $this->errorCounter++;
183
- }
184
-
185
- if (!array_key_exists('Availability', $product)) {
186
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Availability</b>] Missing for <b>$id</b>.";
187
- $this->errorCounter++;
188
- }
189
-
190
- if (!array_key_exists('Current price', $product)) {
191
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current price</b>] Missing for <b>$id</b>.";
192
- $this->errorCounter++;
193
- }
194
- }
195
- }
196
-
197
- /**
198
- * Return Feed
199
- *
200
- * @return array|bool|string
201
- */
202
- public function returnFinalProduct()
203
- {
204
- if ($this->rules['feedType'] == 'xml') {
205
- return $this->get_feed($this->products);
206
- } elseif ($this->rules['feedType'] == 'txt') {
207
- return $this->get_txt_feed();
208
- } elseif ($this->rules['feedType'] == 'csv') {
209
- return $this->get_csv_feed();
210
- }
211
- return false;
212
- }
213
-
214
- /**
215
- * Check product's attribute value according to merchant specifications
216
- */
217
- public function filterProductValues()
218
- {
219
- $getProduct = new Woo_Feed_Products();
220
- $products = $this->products;
221
-
222
- foreach ($products as $no => $product) {
223
- if (array_key_exists('Unique ID', $product)) {
224
- $id = $product['Unique ID'];
225
- } else {
226
- $id = $product['Title'];
227
- }
228
- // echo "<pre>";
229
- // print_r($product);
230
- foreach ($product as $key => $value) {
231
- switch ($key) {
232
- case "Unique ID":
233
- if (strlen($value) > 100) {
234
- $this->errorLog[$this->errorCounter] = "[<b>Unique ID</b>] is more that 100 character for $id.";
235
- $this->errorCounter++;
236
- }
237
- break;
238
- case "Title":
239
- if (strlen($value) > 1000) {
240
- $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 1000 character for $id.";
241
- $this->errorCounter++;
242
- }
243
- break;
244
- case "Description":
245
- if (strlen($value) > 3000) {
246
- $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 3000 character for $id.";
247
- $this->errorCounter++;
248
- }
249
- break;
250
- case "Category":
251
- if (strlen($value) > 1000) {
252
- $this->errorLog[$this->errorCounter] = "[<b>Category</b>] is more that 1000 character for $id.";
253
- $this->errorCounter++;
254
- }
255
- break;
256
- case "Product URL":
257
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
258
- $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] must start with http:// or https:// for $id.";
259
- $this->errorCounter++;
260
- }
261
-
262
- if (strlen($value) > 2000) {
263
- $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] is more that 2000 character for $id.";
264
- $this->errorCounter++;
265
- }
266
-
267
- break;
268
- case "Image URL":
269
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
270
- $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] must start with http:// or https:// for $id.";
271
- $this->errorCounter++;
272
- }
273
-
274
- if (strlen($value) > 2000) {
275
- $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] is more that 2000 character for $id.";
276
- $this->errorCounter++;
277
- }
278
-
279
- list($width, $height) = getimagesize($value);
280
- if ($width < 450 || $height < 450) {
281
- $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 450px for $id.";
282
- $this->errorCounter++;
283
- }
284
-
285
- break;
286
- case "Condition":
287
- $condition = array("New", "Used", "Refurbished", "Open Box", "OEM");
288
- if (!array_key_exists($value, $condition)) {
289
- $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] = $value is acceptable for $id.";
290
- $this->errorCounter++;
291
- }
292
- break;
293
- case "Availability":
294
- $availability = array("In Stock", "Out of Stock", "Available for Order", "PreOrder");
295
- if ($value == 'in stock') {
296
- $this->products[$no][$key] = "In Stock";
297
- } else {
298
- $this->products[$no][$key] = "Out of Stock";
299
- }
300
-
301
- if (!array_key_exists($this->products[$no][$key], $availability)) {
302
- $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] = $value is acceptable for $id.";
303
- $this->errorCounter++;
304
- }
305
- break;
306
- case "Current price":
307
- if (!is_numeric($value)) {
308
- $this->errorLog[$this->errorCounter] = "[<b>Current price</b>] should be numeric for $id.";
309
- $this->errorCounter++;
310
- }
311
- break;
312
- case "Original Price":
313
- if (!is_numeric($value)) {
314
- $this->errorLog[$this->errorCounter] = "[<b>Original price</b>] should be numeric for $id.";
315
- $this->errorCounter++;
316
- }
317
- break;
318
- default:
319
- break;
320
- }
321
- }
322
- }
323
- }
324
-
325
- /**
326
- * Return Dynamic Category Mapping Values by Parent Product Id
327
- *
328
- * @param string $mappingName Category Mapping Name
329
- * @param int $parent Parent id of the product
330
- * @return mixed
331
- */
332
- public function get_category_mapping_value($mappingName, $parent)
333
- {
334
- $getValue = unserialize(get_option($mappingName));
335
- $mapp = array_reverse($getValue['cmapping'], true);
336
- $categories = get_the_terms($parent, 'product_cat');
337
-
338
- foreach ($categories as $key => $category) {
339
- if (!empty($mapp[$category->term_id]))
340
- return $mapp[$category->term_id];
341
- }
342
- return false;
343
- }
344
-
345
- /**
346
- * Configure the feed according to the rules
347
- * @return Shopping
348
- */
349
- public function mapProductsByRules()
350
- {
351
- /**
352
- * Get WooCommerce Products
353
- * @package Woo_Feed_Products
354
- */
355
- $products = new Woo_Feed_Products();
356
-
357
- /**
358
- * This variable contain selected Woo attributes from feed making form
359
- *
360
- * @since 1.0.0
361
- * @var array $attributes contain selected Woo attributes from feed making form
362
- */
363
- $attributes = $this->rules['attributes'];
364
- /**
365
- * This variable contain selected Prefix Values from feed making form
366
- *
367
- * @since 1.0.0
368
- * @var array $prefix Prefix Values from feed making form
369
- */
370
- $prefix = $this->rules['prefix'];
371
- /**
372
- * This variable contain selected Prefix Values from feed making form
373
- *
374
- * @since 1.0.0
375
- * @var array $suffix Suffix Values from feed making form
376
- */
377
- $suffix = $this->rules['suffix'];
378
- /**
379
- * This variable contain selected Output Types from feed making form
380
- *
381
- * @since 1.0.0
382
- * @var array $outputType Output Types from feed making form
383
- */
384
- $outputType = $this->rules['output_type'];
385
-
386
- /**
387
- * This variable contain selected Output Limit from feed making form
388
- *
389
- * @since 1.0.0
390
- * @var array $limit Output Limit from feed making form
391
- */
392
- $limit = $this->rules['limit'];
393
- /**
394
- * This variable contain selected Merchant attributes from feed making form
395
- *
396
- * @since 1.0.0
397
- * @var array $merchantAttributes contain selected Woo attributes from feed making form
398
- */
399
- $merchantAttributes = $this->rules['mattributes'];
400
- /**
401
- * This variable contain attribute types from feed making form
402
- *
403
- * @since 1.0.0
404
- * @var array $type contain attribute types from feed making form
405
- */
406
- $type = $this->rules['type'];
407
- /**
408
- * This variable contain manual output of attribute from feed making form
409
- *
410
- * @since 1.0.0
411
- * @var array $default contain manual output of attribute
412
- */
413
- $default = $this->rules['default'];
414
-
415
- /**
416
- * This variable contain feed type
417
- *
418
- * @since 1.0.0
419
- * @var array $feedType contain feed type
420
- */
421
- $feedType = $this->rules['feedType'];
422
-
423
- // Map Merchant Attributes and Woo Attributes
424
- if (count($merchantAttributes)) {
425
- foreach ($merchantAttributes as $key => $attr) {
426
- if (!empty($attr) && !empty($attributes[$key])) {
427
- if ($type[$key] == 'attribute') {
428
- $this->mapping[$attr]['value'] = $attributes[$key];
429
- $this->mapping[$attr]['suffix'] = $suffix[$key];
430
- $this->mapping[$attr]['prefix'] = $prefix[$key];
431
- $this->mapping[$attr]['type'] = $outputType[$key];
432
- $this->mapping[$attr]['limit'] = $limit[$key];
433
- }
434
- } else if (empty($attributes[$key])) {
435
- if ($type[$key] == 'pattern') {
436
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
437
- $this->mapping[$attr]['suffix'] = $suffix[$key];
438
- $this->mapping[$attr]['prefix'] = $prefix[$key];
439
- $this->mapping[$attr]['type'] = $outputType[$key];
440
- $this->mapping[$attr]['limit'] = $limit[$key];
441
- }
442
- }
443
- }
444
- }
445
-
446
- // Make Product feed array according to mapping
447
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
448
- $i = 0;
449
- foreach ($this->mapping as $attr => $rules) {
450
- if (array_key_exists($rules['value'], $value)) {
451
-
452
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
453
- // Format According to output type
454
- if ($rules['type'] == 2) {
455
- $output = strip_tags($output);
456
- } elseif ($rules['type'] == 3) {
457
- $output = absint($output);
458
- }
459
- // Format According to output limit
460
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
461
- $output = substr($output, 0, $rules['limit']);
462
- }
463
- $attr = trim($attr);
464
- $this->products[$key][$attr] = trim($output);
465
- } else {
466
- if (!empty($default[$i])) {
467
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
468
- if ($rules['type'] == 2) {
469
- $output = strip_tags($output);
470
- } elseif ($rules['type'] == 3) {
471
- $output = absint($output);
472
- }
473
- // Format According to output limit
474
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
475
- $output = substr($output, 0, $rules['limit']);
476
- }
477
- $attr = trim($attr);
478
- $this->products[$key][$attr] = trim($output);
479
- }
480
- }
481
- $i++;
482
- }
483
- }
484
-
485
-
486
- return $this->products;
487
- }
488
-
489
- /**
490
- * Change the products old array key and set new
491
- *
492
- * @param string $from Attribute Before
493
- * @param string $to Attribute After
494
- * @param bool $cdata Enclose Feed value
495
- */
496
- public function mapAttribute($from, $to, $cdata = false)
497
- {
498
- $i = 0;
499
- foreach ($this->products as $no => $product) {
500
- foreach ($product as $key => $value) {
501
- if ($key == $from) {
502
- unset($this->products[$no][$from]);
503
- if ($from == 'images') {
504
- $this->products[$no][$to] = $value;
505
- } else {
506
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
507
- }
508
-
509
- }
510
- }
511
- $i++;
512
- }
513
- }
514
-
515
- /**
516
- * Format and Make the XML node for the Feed
517
- *
518
- * @param $attribute
519
- * @param $value
520
- * @param bool $cdata
521
- * @param bool $stripHTML
522
- * @param bool $utf8encode
523
- * @param string $space
524
- * @return string
525
- */
526
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
527
- {
528
- //Make single line for XML
529
- $c_leader = '';
530
- $c_footer = '';
531
- if ($cdata) {
532
- $c_leader = '<![CDATA[';
533
- $c_footer = ']]>';
534
- }
535
- //Allow force strip HTML
536
- if ($stripHTML)
537
- $value = strip_tags(html_entity_decode($value));
538
-
539
-
540
- if ($utf8encode || $utf8encode == 1) {
541
- $value = utf8_encode($value);
542
- $attribute = utf8_encode($attribute);
543
- }
544
-
545
-
546
- if (!$cdata)
547
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
548
-
549
- if (gettype($value) == 'array')
550
- $value = json_encode($value);
551
-
552
-
553
- return '
554
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
555
- }
556
-
557
- /**
558
- * Responsible to change product array key
559
- *
560
- * @param $array
561
- * @param $old_key
562
- * @param $new_key
563
- * @return array
564
- */
565
- function change_key($array, $old_key, $new_key)
566
- {
567
- foreach ($this->products as $no => $product) {
568
- if (!array_key_exists($old_key, $product))
569
- return $array;
570
-
571
- $keys = array_keys($array);
572
- $keys[array_search($old_key, $keys)] = $new_key;
573
- }
574
- return array_combine($keys, $array);
575
- }
576
-
577
- /**
578
- * Responsible to make XML feed header
579
- * @return string
580
- */
581
- public function get_feed_header()
582
- {
583
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
584
- <products>';
585
- $output .= "\n";
586
- return $output;
587
- }
588
-
589
- /**
590
- * Responsible to make XML feed body
591
- * @var array $item Product array
592
- * @return string
593
- */
594
- public function get_feed($items)
595
- {
596
- $feed = "";
597
- $feed .= $this->get_feed_header();
598
- $feed .= "\n";
599
- foreach ($items as $item => $products) {
600
- $feed .= " <" . $this->feedWrapper . ">";
601
- foreach ($products as $key => $value) {
602
- if (!empty($value))
603
- $feed .= $value;
604
- }
605
- $feed .= "\n </" . $this->feedWrapper . ">\n";
606
- }
607
- $feed .= $this->get_feed_footer();
608
-
609
- return $feed;
610
- }
611
-
612
- /**
613
- * Responsible to make XML feed footer
614
- * @return string
615
- */
616
- public function get_feed_footer()
617
- {
618
- $footer = " </products>";
619
- return $footer;
620
- }
621
-
622
- /**
623
- * Responsible to make TXT feed
624
- * @return string
625
- */
626
- public function get_txt_feed()
627
- {
628
- if ( is_countable( $this->products ) && count( $this->products ) ) {
629
- $headers = array_keys($this->products[0]);
630
- $feed[] = $headers;
631
- foreach ($this->products as $no => $product) {
632
- $row = array();
633
- foreach ($headers as $key => $header) {
634
- $row[] = $product[$header];
635
- }
636
- $feed[] = $row;
637
- }
638
- $str = "";
639
- foreach ($feed as $fields) {
640
- $str .= implode("\t", $fields) . "\n";
641
- }
642
- return $str;
643
- }
644
- return false;
645
- }
646
-
647
- /**
648
- * Responsible to make CSV feed
649
- * @return string
650
- */
651
- public function get_csv_feed()
652
- {
653
- if ( is_countable( $this->products ) && count( $this->products ) ) {
654
- $headers = array_keys($this->products[0]);
655
- $feed[] = $headers;
656
- foreach ($this->products as $no => $product) {
657
- $row = array();
658
- foreach ($headers as $key => $header) {
659
- $row[] = $product[$header];
660
- }
661
- $feed[] = $row;
662
- }
663
-
664
- return $feed;
665
- }
666
- return false;
667
- }
668
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Connexity
5
+ *
6
+ * Responsible for processing and generating feed for Connexity.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Connexity
10
+ *
11
+ */
12
+ class Connexity
13
+ {
14
+
15
+ /**
16
+ * This variable is responsible for holding all product attributes and their values
17
+ *
18
+ * @since 1.0.0
19
+ * @var array $products Contains all the product attributes to generate feed
20
+ * @access public
21
+ */
22
+ public $products;
23
+
24
+ /**
25
+ * This variable is responsible for holding feed configuration form values
26
+ *
27
+ * @since 1.0.0
28
+ * @var Connexity $rules Contains feed configuration form values
29
+ * @access public
30
+ */
31
+ public $rules;
32
+
33
+ /**
34
+ * This variable is responsible for mapping store attributes to merchant attribute
35
+ *
36
+ * @since 1.0.0
37
+ * @var Connexity $mapping Map store attributes to merchant attribute
38
+ * @access public
39
+ */
40
+ public $mapping;
41
+
42
+ /**
43
+ * This variable is responsible for generate error logs
44
+ *
45
+ * @since 1.0.0
46
+ * @var Connexity $errorLog Generate error logs
47
+ * @access public
48
+ */
49
+ public $errorLog;
50
+
51
+ /**
52
+ * This variable is responsible for making error number
53
+ *
54
+ * @since 1.0.0
55
+ * @var Connexity $errorCounter Generate error number
56
+ * @access public
57
+ */
58
+ public $errorCounter;
59
+
60
+ /**
61
+ * Feed Wrapper text for enclosing each product information
62
+ *
63
+ * @since 1.0.0
64
+ * @var Connexity $feedWrapper Feed Wrapper text
65
+ * @access public
66
+ */
67
+ private $feedWrapper;
68
+
69
+ /**
70
+ * Define the core functionality to generate feed.
71
+ *
72
+ * Set the feed rules. Map products according to the rules and Check required attributes
73
+ * and their values according to merchant specification.
74
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
+ * @since 1.0.0
76
+ */
77
+ public function __construct($feedRule)
78
+ {
79
+ $this->feedWrapper = 'product';
80
+ $this->errorCounter = 0;
81
+ $this->rules = $feedRule;
82
+ $this->mapProductsByRules();
83
+ $this->formatRequiredField();
84
+ $this->filterProductValues();
85
+ if ($this->rules['feedType'] == 'xml') {
86
+ $this->mapAttributeForXML();
87
+ } else {
88
+ $this->mapAttributeForCSVTEXT();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Configure merchant attributes for XML feed
94
+ */
95
+ public function mapAttributeForXML()
96
+ {
97
+ //Basic product information
98
+
99
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
100
+ foreach ($this->products as $key => $values) {
101
+ foreach ($values as $attr => $value) {
102
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Configure merchant attributes for CSV and TXT feed
110
+ */
111
+ public function mapAttributeForCSVTEXT()
112
+ {
113
+ //Basic product information
114
+
115
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
116
+ foreach ($this->products as $key => $values) {
117
+ foreach ($values as $attr => $value) {
118
+ //Allow force strip HTML
119
+ $value = strip_tags(html_entity_decode($value));
120
+ if ($attr != 'Category') {
121
+ $value = utf8_encode($value);
122
+ $attr = utf8_encode($attr);
123
+
124
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
+
126
+ if (gettype($value) == 'array')
127
+ $value = json_encode($value);
128
+ }
129
+
130
+ $this->products[$key][$attr] = $value;
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Check all the required attributes and make error message
138
+ */
139
+ public function formatRequiredField()
140
+ {
141
+ foreach ($this->products as $no => $product) {
142
+ $upn = 0;
143
+ if (array_key_exists('Unique ID', $product)) {
144
+ $id = $product['Unique ID'];
145
+ } else {
146
+ $id = $product['Title'];
147
+ }
148
+
149
+ if (!array_key_exists('Unique ID', $product)) {
150
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique ID</b>] Missing for <b>$id</b>.";
151
+ $this->errorCounter++;
152
+ }
153
+
154
+
155
+ if (!array_key_exists('Title', $product)) {
156
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
157
+ $this->errorCounter++;
158
+ }
159
+
160
+ if (!array_key_exists('Description', $product)) {
161
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
162
+ $this->errorCounter++;
163
+ }
164
+
165
+ if (!array_key_exists('Category', $product)) {
166
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Category</b>] Missing for <b>$id</b>.";
167
+ $this->errorCounter++;
168
+ }
169
+
170
+ if (!array_key_exists('Product URL', $product)) {
171
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
172
+ $this->errorCounter++;
173
+ }
174
+
175
+ if (!array_key_exists('Image URL', $product)) {
176
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
177
+ $this->errorCounter++;
178
+ }
179
+
180
+ if (!array_key_exists('Condition', $product)) {
181
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
182
+ $this->errorCounter++;
183
+ }
184
+
185
+ if (!array_key_exists('Availability', $product)) {
186
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Availability</b>] Missing for <b>$id</b>.";
187
+ $this->errorCounter++;
188
+ }
189
+
190
+ if (!array_key_exists('Current price', $product)) {
191
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current price</b>] Missing for <b>$id</b>.";
192
+ $this->errorCounter++;
193
+ }
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Return Feed
199
+ *
200
+ * @return array|bool|string
201
+ */
202
+ public function returnFinalProduct()
203
+ {
204
+ if ($this->rules['feedType'] == 'xml') {
205
+ return $this->get_feed($this->products);
206
+ } elseif ($this->rules['feedType'] == 'txt') {
207
+ return $this->get_txt_feed();
208
+ } elseif ($this->rules['feedType'] == 'csv') {
209
+ return $this->get_csv_feed();
210
+ }
211
+ return false;
212
+ }
213
+
214
+ /**
215
+ * Check product's attribute value according to merchant specifications
216
+ */
217
+ public function filterProductValues()
218
+ {
219
+ $getProduct = new Woo_Feed_Products();
220
+ $products = $this->products;
221
+
222
+ foreach ($products as $no => $product) {
223
+ if (array_key_exists('Unique ID', $product)) {
224
+ $id = $product['Unique ID'];
225
+ } else {
226
+ $id = $product['Title'];
227
+ }
228
+ // echo "<pre>";
229
+ // print_r($product);
230
+ foreach ($product as $key => $value) {
231
+ switch ($key) {
232
+ case "Unique ID":
233
+ if (strlen($value) > 100) {
234
+ $this->errorLog[$this->errorCounter] = "[<b>Unique ID</b>] is more that 100 character for $id.";
235
+ $this->errorCounter++;
236
+ }
237
+ break;
238
+ case "Title":
239
+ if (strlen($value) > 1000) {
240
+ $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 1000 character for $id.";
241
+ $this->errorCounter++;
242
+ }
243
+ break;
244
+ case "Description":
245
+ if (strlen($value) > 3000) {
246
+ $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 3000 character for $id.";
247
+ $this->errorCounter++;
248
+ }
249
+ break;
250
+ case "Category":
251
+ if (strlen($value) > 1000) {
252
+ $this->errorLog[$this->errorCounter] = "[<b>Category</b>] is more that 1000 character for $id.";
253
+ $this->errorCounter++;
254
+ }
255
+ break;
256
+ case "Product URL":
257
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
258
+ $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] must start with http:// or https:// for $id.";
259
+ $this->errorCounter++;
260
+ }
261
+
262
+ if (strlen($value) > 2000) {
263
+ $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] is more that 2000 character for $id.";
264
+ $this->errorCounter++;
265
+ }
266
+
267
+ break;
268
+ case "Image URL":
269
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
270
+ $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] must start with http:// or https:// for $id.";
271
+ $this->errorCounter++;
272
+ }
273
+
274
+ if (strlen($value) > 2000) {
275
+ $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] is more that 2000 character for $id.";
276
+ $this->errorCounter++;
277
+ }
278
+
279
+ list($width, $height) = getimagesize($value);
280
+ if ($width < 450 || $height < 450) {
281
+ $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 450px for $id.";
282
+ $this->errorCounter++;
283
+ }
284
+
285
+ break;
286
+ case "Condition":
287
+ $condition = array("New", "Used", "Refurbished", "Open Box", "OEM");
288
+ if (!array_key_exists($value, $condition)) {
289
+ $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] = $value is acceptable for $id.";
290
+ $this->errorCounter++;
291
+ }
292
+ break;
293
+ case "Availability":
294
+ $availability = array("In Stock", "Out of Stock", "Available for Order", "PreOrder");
295
+ if ($value == 'in stock') {
296
+ $this->products[$no][$key] = "In Stock";
297
+ } else {
298
+ $this->products[$no][$key] = "Out of Stock";
299
+ }
300
+
301
+ if (!array_key_exists($this->products[$no][$key], $availability)) {
302
+ $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] = $value is acceptable for $id.";
303
+ $this->errorCounter++;
304
+ }
305
+ break;
306
+ case "Current price":
307
+ if (!is_numeric($value)) {
308
+ $this->errorLog[$this->errorCounter] = "[<b>Current price</b>] should be numeric for $id.";
309
+ $this->errorCounter++;
310
+ }
311
+ break;
312
+ case "Original Price":
313
+ if (!is_numeric($value)) {
314
+ $this->errorLog[$this->errorCounter] = "[<b>Original price</b>] should be numeric for $id.";
315
+ $this->errorCounter++;
316
+ }
317
+ break;
318
+ default:
319
+ break;
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Return Dynamic Category Mapping Values by Parent Product Id
327
+ *
328
+ * @param string $mappingName Category Mapping Name
329
+ * @param int $parent Parent id of the product
330
+ * @return mixed
331
+ */
332
+ public function get_category_mapping_value($mappingName, $parent)
333
+ {
334
+ $getValue = unserialize(get_option($mappingName));
335
+ $mapp = array_reverse($getValue['cmapping'], true);
336
+ $categories = get_the_terms($parent, 'product_cat');
337
+
338
+ foreach ($categories as $key => $category) {
339
+ if (!empty($mapp[$category->term_id]))
340
+ return $mapp[$category->term_id];
341
+ }
342
+ return false;
343
+ }
344
+
345
+ /**
346
+ * Configure the feed according to the rules
347
+ * @return Shopping
348
+ */
349
+ public function mapProductsByRules()
350
+ {
351
+ /**
352
+ * Get WooCommerce Products
353
+ * @package Woo_Feed_Products
354
+ */
355
+ $products = new Woo_Feed_Products();
356
+
357
+ /**
358
+ * This variable contain selected Woo attributes from feed making form
359
+ *
360
+ * @since 1.0.0
361
+ * @var array $attributes contain selected Woo attributes from feed making form
362
+ */
363
+ $attributes = $this->rules['attributes'];
364
+ /**
365
+ * This variable contain selected Prefix Values from feed making form
366
+ *
367
+ * @since 1.0.0
368
+ * @var array $prefix Prefix Values from feed making form
369
+ */
370
+ $prefix = $this->rules['prefix'];
371
+ /**
372
+ * This variable contain selected Prefix Values from feed making form
373
+ *
374
+ * @since 1.0.0
375
+ * @var array $suffix Suffix Values from feed making form
376
+ */
377
+ $suffix = $this->rules['suffix'];
378
+ /**
379
+ * This variable contain selected Output Types from feed making form
380
+ *
381
+ * @since 1.0.0
382
+ * @var array $outputType Output Types from feed making form
383
+ */
384
+ $outputType = $this->rules['output_type'];
385
+
386
+ /**
387
+ * This variable contain selected Output Limit from feed making form
388
+ *
389
+ * @since 1.0.0
390
+ * @var array $limit Output Limit from feed making form
391
+ */
392
+ $limit = $this->rules['limit'];
393
+ /**
394
+ * This variable contain selected Merchant attributes from feed making form
395
+ *
396
+ * @since 1.0.0
397
+ * @var array $merchantAttributes contain selected Woo attributes from feed making form
398
+ */
399
+ $merchantAttributes = $this->rules['mattributes'];
400
+ /**
401
+ * This variable contain attribute types from feed making form
402
+ *
403
+ * @since 1.0.0
404
+ * @var array $type contain attribute types from feed making form
405
+ */
406
+ $type = $this->rules['type'];
407
+ /**
408
+ * This variable contain manual output of attribute from feed making form
409
+ *
410
+ * @since 1.0.0
411
+ * @var array $default contain manual output of attribute
412
+ */
413
+ $default = $this->rules['default'];
414
+
415
+ /**
416
+ * This variable contain feed type
417
+ *
418
+ * @since 1.0.0
419
+ * @var array $feedType contain feed type
420
+ */
421
+ $feedType = $this->rules['feedType'];
422
+
423
+ // Map Merchant Attributes and Woo Attributes
424
+ if (count($merchantAttributes)) {
425
+ foreach ($merchantAttributes as $key => $attr) {
426
+ if (!empty($attr) && !empty($attributes[$key])) {
427
+ if ($type[$key] == 'attribute') {
428
+ $this->mapping[$attr]['value'] = $attributes[$key];
429
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
430
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
431
+ $this->mapping[$attr]['type'] = $outputType[$key];
432
+ $this->mapping[$attr]['limit'] = $limit[$key];
433
+ }
434
+ } else if (empty($attributes[$key])) {
435
+ if ($type[$key] == 'pattern') {
436
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
437
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
438
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
439
+ $this->mapping[$attr]['type'] = $outputType[$key];
440
+ $this->mapping[$attr]['limit'] = $limit[$key];
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ // Make Product feed array according to mapping
447
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
448
+ $i = 0;
449
+ foreach ($this->mapping as $attr => $rules) {
450
+ if (array_key_exists($rules['value'], $value)) {
451
+
452
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
453
+ // Format According to output type
454
+ if ($rules['type'] == 2) {
455
+ $output = strip_tags($output);
456
+ } elseif ($rules['type'] == 3) {
457
+ $output = absint($output);
458
+ }
459
+ // Format According to output limit
460
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
461
+ $output = substr($output, 0, $rules['limit']);
462
+ }
463
+ $attr = trim($attr);
464
+ $this->products[$key][$attr] = trim($output);
465
+ } else {
466
+ if (!empty($default[$i])) {
467
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
468
+ if ($rules['type'] == 2) {
469
+ $output = strip_tags($output);
470
+ } elseif ($rules['type'] == 3) {
471
+ $output = absint($output);
472
+ }
473
+ // Format According to output limit
474
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
475
+ $output = substr($output, 0, $rules['limit']);
476
+ }
477
+ $attr = trim($attr);
478
+ $this->products[$key][$attr] = trim($output);
479
+ }
480
+ }
481
+ $i++;
482
+ }
483
+ }
484
+
485
+
486
+ return $this->products;
487
+ }
488
+
489
+ /**
490
+ * Change the products old array key and set new
491
+ *
492
+ * @param string $from Attribute Before
493
+ * @param string $to Attribute After
494
+ * @param bool $cdata Enclose Feed value
495
+ */
496
+ public function mapAttribute($from, $to, $cdata = false)
497
+ {
498
+ $i = 0;
499
+ foreach ($this->products as $no => $product) {
500
+ foreach ($product as $key => $value) {
501
+ if ($key == $from) {
502
+ unset($this->products[$no][$from]);
503
+ if ($from == 'images') {
504
+ $this->products[$no][$to] = $value;
505
+ } else {
506
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
507
+ }
508
+
509
+ }
510
+ }
511
+ $i++;
512
+ }
513
+ }
514
+
515
+ /**
516
+ * Format and Make the XML node for the Feed
517
+ *
518
+ * @param $attribute
519
+ * @param $value
520
+ * @param bool $cdata
521
+ * @param bool $stripHTML
522
+ * @param bool $utf8encode
523
+ * @param string $space
524
+ * @return string
525
+ */
526
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
527
+ {
528
+ //Make single line for XML
529
+ $c_leader = '';
530
+ $c_footer = '';
531
+ if ($cdata) {
532
+ $c_leader = '<![CDATA[';
533
+ $c_footer = ']]>';
534
+ }
535
+ //Allow force strip HTML
536
+ if ($stripHTML)
537
+ $value = strip_tags(html_entity_decode($value));
538
+
539
+
540
+ if ($utf8encode || $utf8encode == 1) {
541
+ $value = utf8_encode($value);
542
+ $attribute = utf8_encode($attribute);
543
+ }
544
+
545
+
546
+ if (!$cdata)
547
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
548
+
549
+ if (gettype($value) == 'array')
550
+ $value = json_encode($value);
551
+
552
+
553
+ return '
554
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
555
+ }
556
+
557
+ /**
558
+ * Responsible to change product array key
559
+ *
560
+ * @param $array
561
+ * @param $old_key
562
+ * @param $new_key
563
+ * @return array
564
+ */
565
+ function change_key($array, $old_key, $new_key)
566
+ {
567
+ foreach ($this->products as $no => $product) {
568
+ if (!array_key_exists($old_key, $product))
569
+ return $array;
570
+
571
+ $keys = array_keys($array);
572
+ $keys[array_search($old_key, $keys)] = $new_key;
573
+ }
574
+ return array_combine($keys, $array);
575
+ }
576
+
577
+ /**
578
+ * Responsible to make XML feed header
579
+ * @return string
580
+ */
581
+ public function get_feed_header()
582
+ {
583
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
584
+ <products>';
585
+ $output .= "\n";
586
+ return $output;
587
+ }
588
+
589
+ /**
590
+ * Responsible to make XML feed body
591
+ * @var array $item Product array
592
+ * @return string
593
+ */
594
+ public function get_feed($items)
595
+ {
596
+ $feed = "";
597
+ $feed .= $this->get_feed_header();
598
+ $feed .= "\n";
599
+ foreach ($items as $item => $products) {
600
+ $feed .= " <" . $this->feedWrapper . ">";
601
+ foreach ($products as $key => $value) {
602
+ if (!empty($value))
603
+ $feed .= $value;
604
+ }
605
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
606
+ }
607
+ $feed .= $this->get_feed_footer();
608
+
609
+ return $feed;
610
+ }
611
+
612
+ /**
613
+ * Responsible to make XML feed footer
614
+ * @return string
615
+ */
616
+ public function get_feed_footer()
617
+ {
618
+ $footer = " </products>";
619
+ return $footer;
620
+ }
621
+
622
+ /**
623
+ * Responsible to make TXT feed
624
+ * @return string
625
+ */
626
+ public function get_txt_feed()
627
+ {
628
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
629
+ $headers = array_keys($this->products[0]);
630
+ $feed[] = $headers;
631
+ foreach ($this->products as $no => $product) {
632
+ $row = array();
633
+ foreach ($headers as $key => $header) {
634
+ $row[] = $product[$header];
635
+ }
636
+ $feed[] = $row;
637
+ }
638
+ $str = "";
639
+ foreach ($feed as $fields) {
640
+ $str .= implode("\t", $fields) . "\n";
641
+ }
642
+ return $str;
643
+ }
644
+ return false;
645
+ }
646
+
647
+ /**
648
+ * Responsible to make CSV feed
649
+ * @return string
650
+ */
651
+ public function get_csv_feed()
652
+ {
653
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
654
+ $headers = array_keys($this->products[0]);
655
+ $feed[] = $headers;
656
+ foreach ($this->products as $no => $product) {
657
+ $row = array();
658
+ foreach ($headers as $key => $header) {
659
+ $row[] = $product[$header];
660
+ }
661
+ $feed[] = $row;
662
+ }
663
+
664
+ return $feed;
665
+ }
666
+ return false;
667
+ }
668
  }
includes/feeds/class-woo-feed-facebook.php CHANGED
@@ -1,524 +1,524 @@
1
- <?php
2
-
3
- /**
4
- * Class Google
5
- *
6
- * Responsible for processing and generating feed for Google.com
7
- *
8
- * @since 1.0.0
9
- * @package Google
10
- *
11
- */
12
- class Woo_Feed_Facebook
13
- {
14
-
15
- /**
16
- * This variable is responsible for holding all product attributes and their values
17
- *
18
- * @since 1.0.0
19
- * @var array $products Contains all the product attributes to generate feed
20
- * @access public
21
- */
22
- public $products;
23
-
24
- /**
25
- * This variable is responsible for holding feed configuration form values
26
- *
27
- * @since 1.0.0
28
- * @var array $rules Contains feed configuration form values
29
- * @access public
30
- */
31
- public $rules;
32
-
33
- /**
34
- * This variable is responsible for mapping store attributes to merchant attribute
35
- *
36
- * @since 1.0.0
37
- * @var array $mapping Map store attributes to merchant attribute
38
- * @access public
39
- */
40
- public $mapping;
41
-
42
- /**
43
- * This variable is responsible for generate error logs
44
- *
45
- * @since 1.0.0
46
- * @var array $errorLog Generate error logs
47
- * @access public
48
- */
49
- public $errorLog;
50
-
51
- /**
52
- * This variable is responsible for making error number
53
- *
54
- * @since 1.0.0
55
- * @var int $errorCounter Generate error number
56
- * @access public
57
- */
58
- public $errorCounter;
59
-
60
- /**
61
- * Feed Wrapper text for enclosing each product information
62
- *
63
- * @since 1.0.0
64
- * @var string $feedWrapper Feed Wrapper text
65
- * @access public
66
- */
67
- public $feedWrapper = 'item';
68
-
69
- /**
70
- * Store product information
71
- *
72
- * @since 1.0.0
73
- * @var array $storeProducts
74
- * @access public
75
- */
76
- private $storeProducts;
77
-
78
- /**
79
- * Define the core functionality to generate feed.
80
- *
81
- * Set the feed rules. Map products according to the rules and Check required attributes
82
- * and their values according to merchant specification.
83
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
84
- * @since 1.0.0
85
- */
86
- public function __construct($feedRule)
87
- {
88
- $products = new Woo_Feed_Products();
89
- $storeProducts = $products->woo_feed_get_visible_product($feedRule);
90
- $engine = new WF_Engine($storeProducts, $feedRule);
91
- $this->products = $engine->mapProductsByRules();
92
- $this->rules = $feedRule;
93
- if ($feedRule['feedType'] == 'xml') {
94
- $this->mapAttributeForXML();
95
- } else {
96
- $this->mapAttributeForCSVTXT();
97
- }
98
-
99
- }
100
-
101
-
102
- /**
103
- * Return Feed
104
- *
105
- * @return array|bool|string
106
- */
107
- public function returnFinalProduct()
108
- {
109
- if(!empty($this->products)) {
110
- $engine = new WF_Engine($this->products, $this->rules);
111
- if ($this->rules['feedType'] == 'xml') {
112
- //return $this->get_feed($this->products);
113
- $feed = array(
114
- "header" => $this->get_xml_feed_header(),
115
- "body" => $this->get_xml_feed_body($this->products),
116
- "footer" => $this->get_xml_feed_footer(),
117
- );
118
- return $feed;
119
- } elseif ($this->rules['feedType'] == 'txt') {
120
- //return $engine->get_txt_feed();
121
- $feed = array(
122
- "body" => $engine->get_txt_feed(),
123
- "header" => $engine->txtFeedHeader,
124
- "footer" => "",
125
- );
126
- return $feed;
127
- } elseif ($this->rules['feedType'] == 'csv') {
128
- $feed = array(
129
- "body" => $engine->get_csv_feed(),
130
- "header" => $engine->csvFeedHeader,
131
- "footer" => "",
132
- );
133
- return $feed;
134
- }
135
- }
136
- $feed=array(
137
- "body"=>"",
138
- "header"=>"",
139
- "footer"=>"",
140
- );
141
- return $feed;
142
- }
143
-
144
- /**
145
- * Configure merchant attributes for XML feed
146
- */
147
- public function mapAttributeForXML()
148
- {
149
-
150
- $googleXMLAttribute = array(
151
- "id" => array("g:id", false),
152
- "title" => array("g:title", true),
153
- "description" => array("g:description", true),
154
- "link" => array("g:link", true),
155
- "mobile_link" => array("g:mobile_link", true),
156
- "product_type" => array("g:product_type", true),
157
- "current_category" => array("g:google_product_category", true),
158
- "image" => array("g:image_link", true),
159
- "images" => array("g:additional_image_link", false),
160
- "images_1" => array("g:additional_image_link_1", true),
161
- "images_2" => array("g:additional_image_link_2", true),
162
- "images_3" => array("g:additional_image_link_3", true),
163
- "images_4" => array("g:additional_image_link_4", true),
164
- "images_5" => array("g:additional_image_link_5", true),
165
- "images_6" => array("g:additional_image_link_6", true),
166
- "images_7" => array("g:additional_image_link_7", true),
167
- "images_8" => array("g:additional_image_link_8", true),
168
- "images_9" => array("g:additional_image_link_9", true),
169
- "images_10" => array("g:additional_image_link_10", true),
170
- "condition" => array("g:condition", false),
171
- "availability" => array("g:availability", false),
172
- "inventory" => array("g:inventory", false),
173
- "override" => array("g:override", false),
174
- "price" => array("g:price", true),
175
- "sale_price" => array("g:sale_price", true),
176
- "sale_price_effective_date" => array("g:sale_price_effective_date", true),
177
- "brand" => array("g:brand", true),
178
- "sku" => array("g:mpn", true),
179
- "upc" => array("g:gtin", true),
180
- "identifier_exists" => array("g:identifier_exists", true),
181
- "item_group_id" => array("g:item_group_id", false),
182
- "color" => array("g:color", true),
183
- "gender" => array("g:gender", true),
184
- "age_group" => array("g:age_group", true),
185
- "material" => array("g:material", true),
186
- "pattern" => array("g:pattern", true),
187
- "size" => array("g:size", true),
188
- "size_type" => array("g:size_type", true),
189
- "size_system" => array("g:size_system", true),
190
- "tax" => array("tax", true),
191
- "weight" => array("g:shipping_weight", false),
192
- "length" => array("g:shipping_length", false),
193
- "width" => array("g:shipping_width", false),
194
- "height" => array("g:shipping_height", false),
195
- "shipping_label" => array("g:shipping_label", false),
196
- "shipping_country" => array("g:shipping_country", false),
197
- "shipping_service" => array("g:shipping_service", false),
198
- "shipping_price" => array("g:shipping_price", false),
199
- "shipping_region" => array("g:shipping_region", false),
200
- "multipack" => array("g:multipack", true),
201
- "is_bundle" => array("g:is_bundle", true),
202
- "adult" => array("g:adult", true),
203
- "adwords_redirect" => array("g:adwords_redirect", true),
204
- "custom_label_0" => array("g:custom_label_0", true),
205
- "custom_label_1" => array("g:custom_label_1", true),
206
- "custom_label_2" => array("g:custom_label_2", true),
207
- "custom_label_3" => array("g:custom_label_3", true),
208
- "custom_label_4" => array("g:custom_label_4", true),
209
- "excluded_destination" => array("g:excluded_destination", true),
210
- "expiration_date" => array("g:expiration_date", true),
211
- "unit_pricing_measure" => array("g:unit_pricing_measure", true),
212
- "unit_pricing_base_measure" => array("g:unit_pricing_base_measure", true),
213
- "energy_efficiency_class" => array("g:energy_efficiency_class", true),
214
- "loyalty_points" => array("g:loyalty_points", true),
215
- "installment" => array("g:installment", true),
216
- "promotion_id" => array("g:promotion_id", true),
217
- "cost_of_goods_sold" => array("g:cost_of_goods_sold", true),
218
- "availability_date" => array("g:availability_date", true),
219
- "tax_category" => array("g:tax_category", true),
220
- "included_destination" => array("g:included_destination", true),
221
- );
222
-
223
- if ( is_countable( $this->products ) && count( $this->products ) ) {
224
- foreach ($this->products as $no => $product) {
225
- foreach ($product as $key => $value) {
226
- $this->mapAttribute($no, $key, $googleXMLAttribute[$key][0], $value, $googleXMLAttribute[$key][0]);
227
- }
228
- $this->process_google_shipping_attribute_for_xml($no);
229
- }
230
- }
231
- }
232
-
233
- /**
234
- * Configure merchant attributes for XML feed
235
- */
236
- public function mapAttributeForCSVTXT()
237
- {
238
- //Basic product information
239
- $googleCSVTXTAttribute = array(
240
- "id" => array("id", false),
241
- "title" => array("title", true),
242
- "description" => array("description", true),
243
- "link" => array("link", true),
244
- "mobile_link" => array("mobile_link", true),
245
- "product_type" => array("product type", true),
246
- "current_category" => array("google product category", true),
247
- "image" => array("image link", true),
248
- "images" => array("additional image link", true),
249
- "images_1" => array("additional image link 1", true),
250
- "images_2" => array("additional image link 2", true),
251
- "images_3" => array("additional image link 3", true),
252
- "images_4" => array("additional image link 4", true),
253
- "images_5" => array("additional image link 5", true),
254
- "images_6" => array("additional image link 6", true),
255
- "images_7" => array("additional image link 7", true),
256
- "images_8" => array("additional image link 8", true),
257
- "images_9" => array("additional image link 9", true),
258
- "images_10" => array("additional image link 10", true),
259
- "condition" => array("condition", false),
260
- "availability" => array("availability", false),
261
- "inventory" => array("inventory", false),
262
- "override" => array("override", false),
263
- "price" => array("price", true),
264
- "sale_price" => array("sale price", true),
265
- "sale_price_effective_date" => array("sale price effective date", true),
266
- "brand" => array("brand", true),
267
- "sku" => array("mpn", true),
268
- "upc" => array("gtin", true),
269
- "identifier_exists" => array("identifier exists", true),
270
- "item_group_id" => array("item group id", false),
271
- "color" => array("color", true),
272
- "gender" => array("gender", true),
273
- "age_group" => array("age group", true),
274
- "material" => array("material", true),
275
- "pattern" => array("pattern", true),
276
- "size" => array("size", true),
277
- "size_type" => array("size type", true),
278
- "size_system" => array("size system", true),
279
- "tax" => array("tax", true),
280
- "weight" => array("shipping weight", false),
281
- "length" => array("shipping length", false),
282
- "width" => array("shipping width", false),
283
- "height" => array("shipping height", false),
284
- "shipping_label" => array("shipping label", false),
285
- "shipping_country" => array("shipping country", false),
286
- "shipping_service" => array("shipping service", false),
287
- "shipping_price" => array("shipping price", false),
288
- "shipping_region" => array("shipping region", false),
289
- "multipack" => array("multipack", true),
290
- "is_bundle" => array("is bundle", true),
291
- "adult" => array("adult", true),
292
- "adwords_redirect" => array("adwords redirect", true),
293
- "custom_label_0" => array("custom label 0", true),
294
- "custom_label_1" => array("custom label 1", true),
295
- "custom_label_2" => array("custom label 2", true),
296
- "custom_label_3" => array("custom label 3", true),
297
- "custom_label_4" => array("custom label 4", true),
298
- "excluded_destination" => array("excluded destination", true),
299
- "expiration_date" => array("expiration date", true),
300
- "unit_pricing_measure" => array("unit pricing measure", true),
301
- "unit_pricing_base_measure" => array("unit pricing base measure", true),
302
- "energy_efficiency_class" => array("energy efficiency class", true),
303
- "loyalty_points" => array("loyalty points", true),
304
- "installment" => array("installment", true),
305
- "promotion_id" => array("promotion id", true),
306
- "cost_of_goods_sold" => array("cost of goods sold", true),
307
- "availability_date" => array("availability date", true),
308
- "tax_category" => array("tax category", true),
309
- "included_destination" => array("included destination", true),
310
- );
311
-
312
- if ( is_countable( $this->products ) && count( $this->products ) ) {
313
- foreach ($this->products as $no => $product) {
314
- foreach ($product as $key => $value) {
315
- $this->mapAttribute($no, $key, str_replace(" ", "_", $googleCSVTXTAttribute[$key][0]), $value, $googleCSVTXTAttribute[$key][0]);
316
- }
317
- $this->process_google_shipping_attribute_for_CSVTXT($no);
318
- }
319
- }
320
- }
321
-
322
- /**
323
- * Map to google attribute
324
- * @param $no
325
- * @param $from
326
- * @param $to
327
- * @param $value
328
- * @param bool $cdata
329
- * @return array
330
- */
331
- public function mapAttribute($no, $from, $to, $value, $cdata = false)
332
- {
333
- unset($this->products[$no][$from]);
334
- if ($this->rules['feedType'] == 'xml') {
335
- return $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata);
336
- } else {
337
- return $this->products[$no][$to] = $value;
338
- }
339
- }
340
-
341
-
342
- public
343
- function process_google_shipping_attribute_for_xml($no)
344
- {
345
- $shipping = array('g:shipping_country', 'g:shipping_service', 'g:shipping_price', 'g:shipping_region');
346
- $shippingAttr = array();
347
- $products = $this->products[$no];
348
- foreach ($products as $keyAttr => $valueAttr) {
349
- if (in_array($keyAttr, $shipping)) {
350
- array_push($shippingAttr, array($keyAttr => $valueAttr));
351
- unset($this->products[$no][$keyAttr]);
352
- }
353
- }
354
- if (count($shippingAttr)) {
355
- $str = "";
356
- foreach ($shippingAttr as $key => $attributes) {
357
- foreach ($attributes as $keyAttr => $valueAttr) {
358
- $str .= str_replace("shipping_", "", $valueAttr);
359
- }
360
- }
361
- return $this->products[$no]['g:shipping'] = $this->formatXMLLine("g:shipping", $str, false);
362
- }
363
- return false;
364
- }
365
-
366
- public
367
- function process_google_shipping_attribute_for_CSVTXT($no)
368
- {
369
- $shipping = array('shipping_country', 'shipping_service', 'shipping_price', 'shipping_region');
370
- $shippingAttr = array();
371
- $products = $this->products[$no];
372
- foreach ($products as $keyAttr => $valueAttr) {
373
- if (in_array($keyAttr, $shipping)) {
374
- array_push($shippingAttr, array($keyAttr => $valueAttr));
375
- unset($this->products[$no][$keyAttr]);
376
- }
377
- }
378
- if (count($shippingAttr)) {
379
- $str = "";
380
- foreach ($shippingAttr as $key => $attributes) {
381
- foreach ($attributes as $keyAttr => $valueAttr) {
382
- $country = ($keyAttr == "shipping_country") ? $str .= $valueAttr . ":" : "";
383
- $service = ($keyAttr == "shipping_service") ? $str .= $valueAttr . ":" : "";
384
- $price = ($keyAttr == "shipping_price") ? $str .= $valueAttr : "";
385
- $region = ($keyAttr == "shipping_region") ? $str .= $valueAttr . ":" : "";
386
- }
387
- }
388
- return $this->products[$no]['shipping(country:region:service:price)'] = str_replace(" : ", ":", $str);
389
- }
390
- return false;
391
- }
392
-
393
- /**
394
- * Make xml node
395
- *
396
- * @param string $attribute Attribute Name
397
- * @param string $value Attribute Value
398
- * @param bool $cdata
399
- * @param string $space
400
- * @return string
401
- */
402
- function formatXMLLine($attribute, $value, $cdata, $space = "")
403
- {
404
- //Make single XML node
405
- if (!empty($value))
406
- $value = trim($value);
407
- if (gettype($value) == 'array')
408
- $value = json_encode($value);
409
- if (strpos($value, "<![CDATA[") === false && substr(trim($value), 0, 4) == "http") {
410
- $value = "<![CDATA[$value]]>";
411
- } elseif (strpos($value, "<![CDATA[") === false && $cdata === true && !empty($value)) {
412
- $value = "<![CDATA[$value]]>";
413
- } elseif ($cdata) {
414
- if(!empty($value)){
415
- $value = "<![CDATA[$value]]>";
416
- }
417
- }
418
-
419
- if (substr($attribute, 0, 23) == 'g:additional_image_link') {
420
- $attribute = "g:additional_image_link";
421
- }
422
-
423
- return "
424
- $space<$attribute>$value</$attribute>";
425
- }
426
-
427
-
428
- /**
429
- * Make XML Feed Header
430
- * @return string
431
- */
432
- public function get_xml_feed_header()
433
- {
434
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
435
- <rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
436
- <channel>
437
- <title><![CDATA[' . html_entity_decode(get_option('blogname')) . ']]></title>
438
- <link><![CDATA[' . site_url() . ']]></link>
439
- <description><![CDATA[' . html_entity_decode( get_option('blogdescription')) . ']]></description>';
440
- return $output;
441
- }
442
-
443
- /** Make XML Feed
444
- * @param $items
445
- * @return bool|string
446
- */
447
- public function get_xml_feed_body($items)
448
- {
449
- $feed = "";
450
- //$feed .= $this->get_feed_header();
451
- $feed .= "\n";
452
- if ($items) {
453
- foreach ($items as $item => $products) {
454
- $feed .= " <".$this->feedWrapper.">";
455
- foreach ($products as $key => $value) {
456
- if (!empty($value)){
457
- $feed .= $value;
458
- }
459
- }
460
- $feed .= "\n </" . $this->feedWrapper . ">\n";
461
- }
462
- // $feed .= $this->get_feed_footer();
463
-
464
- return $feed;
465
- }
466
- return false;
467
- }
468
-
469
- /**
470
- * Make XML Feed Footer
471
- * @return string
472
- */
473
- public function get_xml_feed_footer()
474
- {
475
- $footer = " </channel>
476
- </rss>";
477
- return $footer;
478
- }
479
-
480
- /**
481
- * Short Products
482
- * @return array
483
- */
484
- public function short_products()
485
- {
486
- if ($this->products) {
487
- update_option('wpf_progress', "Shorting Products");
488
- sleep(1);
489
- $array = array();
490
- $ij = 0;
491
- foreach ($this->products as $key => $item) {
492
- $array[$ij] = $item;
493
- unset($this->products[$key]);
494
- $ij++;
495
- }
496
- return $this->products = $array;
497
- }
498
- return $this->products;
499
- }
500
-
501
- /**
502
- * Responsible to make CSV feed
503
- * @return string
504
- */
505
- public function get_csv_feed()
506
- {
507
- if ($this->products) {
508
- $headers = array_keys($this->products[0]);
509
- $feed[] = $headers;
510
- foreach ($this->products as $no => $product) {
511
- $row = array();
512
- foreach ($headers as $key => $header) {
513
- if (strpos($header, "additional image link") !== false) {
514
- $header = "additional image link";
515
- }
516
- $row[] = isset($product[$header]) ? $product[$header] : "";;
517
- }
518
- $feed[] = $row;
519
- }
520
- return $feed;
521
- }
522
- return false;
523
- }
524
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Google
5
+ *
6
+ * Responsible for processing and generating feed for Google.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Google
10
+ *
11
+ */
12
+ class Woo_Feed_Facebook
13
+ {
14
+
15
+ /**
16
+ * This variable is responsible for holding all product attributes and their values
17
+ *
18
+ * @since 1.0.0
19
+ * @var array $products Contains all the product attributes to generate feed
20
+ * @access public
21
+ */
22
+ public $products;
23
+
24
+ /**
25
+ * This variable is responsible for holding feed configuration form values
26
+ *
27
+ * @since 1.0.0
28
+ * @var array $rules Contains feed configuration form values
29
+ * @access public
30
+ */
31
+ public $rules;
32
+
33
+ /**
34
+ * This variable is responsible for mapping store attributes to merchant attribute
35
+ *
36
+ * @since 1.0.0
37
+ * @var array $mapping Map store attributes to merchant attribute
38
+ * @access public
39
+ */
40
+ public $mapping;
41
+
42
+ /**
43
+ * This variable is responsible for generate error logs
44
+ *
45
+ * @since 1.0.0
46
+ * @var array $errorLog Generate error logs
47
+ * @access public
48
+ */
49
+ public $errorLog;
50
+
51
+ /**
52
+ * This variable is responsible for making error number
53
+ *
54
+ * @since 1.0.0
55
+ * @var int $errorCounter Generate error number
56
+ * @access public
57
+ */
58
+ public $errorCounter;
59
+
60
+ /**
61
+ * Feed Wrapper text for enclosing each product information
62
+ *
63
+ * @since 1.0.0
64
+ * @var string $feedWrapper Feed Wrapper text
65
+ * @access public
66
+ */
67
+ public $feedWrapper = 'item';
68
+
69
+ /**
70
+ * Store product information
71
+ *
72
+ * @since 1.0.0
73
+ * @var array $storeProducts
74
+ * @access public
75
+ */
76
+ private $storeProducts;
77
+
78
+ /**
79
+ * Define the core functionality to generate feed.
80
+ *
81
+ * Set the feed rules. Map products according to the rules and Check required attributes
82
+ * and their values according to merchant specification.
83
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
84
+ * @since 1.0.0
85
+ */
86
+ public function __construct($feedRule)
87
+ {
88
+ $products = new Woo_Feed_Products();
89
+ $storeProducts = $products->woo_feed_get_visible_product($feedRule);
90
+ $engine = new WF_Engine($storeProducts, $feedRule);
91
+ $this->products = $engine->mapProductsByRules();
92
+ $this->rules = $feedRule;
93
+ if ($feedRule['feedType'] == 'xml') {
94
+ $this->mapAttributeForXML();
95
+ } else {
96
+ $this->mapAttributeForCSVTXT();
97
+ }
98
+
99
+ }
100
+
101
+
102
+ /**
103
+ * Return Feed
104
+ *
105
+ * @return array|bool|string
106
+ */
107
+ public function returnFinalProduct()
108
+ {
109
+ if(!empty($this->products)) {
110
+ $engine = new WF_Engine($this->products, $this->rules);
111
+ if ($this->rules['feedType'] == 'xml') {
112
+ //return $this->get_feed($this->products);
113
+ $feed = array(
114
+ "header" => $this->get_xml_feed_header(),
115
+ "body" => $this->get_xml_feed_body($this->products),
116
+ "footer" => $this->get_xml_feed_footer(),
117
+ );
118
+ return $feed;
119
+ } elseif ($this->rules['feedType'] == 'txt') {
120
+ //return $engine->get_txt_feed();
121
+ $feed = array(
122
+ "body" => $engine->get_txt_feed(),
123
+ "header" => $engine->txtFeedHeader,
124
+ "footer" => "",
125
+ );
126
+ return $feed;
127
+ } elseif ($this->rules['feedType'] == 'csv') {
128
+ $feed = array(
129
+ "body" => $engine->get_csv_feed(),
130
+ "header" => $engine->csvFeedHeader,
131
+ "footer" => "",
132
+ );
133
+ return $feed;
134
+ }
135
+ }
136
+ $feed=array(
137
+ "body"=>"",
138
+ "header"=>"",
139
+ "footer"=>"",
140
+ );
141
+ return $feed;
142
+ }
143
+
144
+ /**
145
+ * Configure merchant attributes for XML feed
146
+ */
147
+ public function mapAttributeForXML()
148
+ {
149
+
150
+ $googleXMLAttribute = array(
151
+ "id" => array("g:id", false),
152
+ "title" => array("g:title", true),
153
+ "description" => array("g:description", true),
154
+ "link" => array("g:link", true),
155
+ "mobile_link" => array("g:mobile_link", true),
156
+ "product_type" => array("g:product_type", true),
157
+ "current_category" => array("g:google_product_category", true),
158
+ "image" => array("g:image_link", true),
159
+ "images" => array("g:additional_image_link", false),
160
+ "images_1" => array("g:additional_image_link_1", true),
161
+ "images_2" => array("g:additional_image_link_2", true),
162
+ "images_3" => array("g:additional_image_link_3", true),
163
+ "images_4" => array("g:additional_image_link_4", true),
164
+ "images_5" => array("g:additional_image_link_5", true),
165
+ "images_6" => array("g:additional_image_link_6", true),
166
+ "images_7" => array("g:additional_image_link_7", true),
167
+ "images_8" => array("g:additional_image_link_8", true),
168
+ "images_9" => array("g:additional_image_link_9", true),
169
+ "images_10" => array("g:additional_image_link_10", true),
170
+ "condition" => array("g:condition", false),
171
+ "availability" => array("g:availability", false),
172
+ "inventory" => array("g:inventory", false),
173
+ "override" => array("g:override", false),
174
+ "price" => array("g:price", true),
175
+ "sale_price" => array("g:sale_price", true),
176
+ "sale_price_effective_date" => array("g:sale_price_effective_date", true),
177
+ "brand" => array("g:brand", true),
178
+ "sku" => array("g:mpn", true),
179
+ "upc" => array("g:gtin", true),
180
+ "identifier_exists" => array("g:identifier_exists", true),
181
+ "item_group_id" => array("g:item_group_id", false),
182
+ "color" => array("g:color", true),
183
+ "gender" => array("g:gender", true),
184
+ "age_group" => array("g:age_group", true),
185
+ "material" => array("g:material", true),
186
+ "pattern" => array("g:pattern", true),
187
+ "size" => array("g:size", true),
188
+ "size_type" => array("g:size_type", true),
189
+ "size_system" => array("g:size_system", true),
190
+ "tax" => array("tax", true),
191
+ "weight" => array("g:shipping_weight", false),
192
+ "length" => array("g:shipping_length", false),
193
+ "width" => array("g:shipping_width", false),
194
+ "height" => array("g:shipping_height", false),
195
+ "shipping_label" => array("g:shipping_label", false),
196
+ "shipping_country" => array("g:shipping_country", false),
197
+ "shipping_service" => array("g:shipping_service", false),
198
+ "shipping_price" => array("g:shipping_price", false),
199
+ "shipping_region" => array("g:shipping_region", false),
200
+ "multipack" => array("g:multipack", true),
201
+ "is_bundle" => array("g:is_bundle", true),
202
+ "adult" => array("g:adult", true),
203
+ "adwords_redirect" => array("g:adwords_redirect", true),
204
+ "custom_label_0" => array("g:custom_label_0", true),
205
+ "custom_label_1" => array("g:custom_label_1", true),
206
+ "custom_label_2" => array("g:custom_label_2", true),
207
+ "custom_label_3" => array("g:custom_label_3", true),
208
+ "custom_label_4" => array("g:custom_label_4", true),
209
+ "excluded_destination" => array("g:excluded_destination", true),
210
+ "expiration_date" => array("g:expiration_date", true),
211
+ "unit_pricing_measure" => array("g:unit_pricing_measure", true),
212
+ "unit_pricing_base_measure" => array("g:unit_pricing_base_measure", true),
213
+ "energy_efficiency_class" => array("g:energy_efficiency_class", true),
214
+ "loyalty_points" => array("g:loyalty_points", true),
215
+ "installment" => array("g:installment", true),
216
+ "promotion_id" => array("g:promotion_id", true),
217
+ "cost_of_goods_sold" => array("g:cost_of_goods_sold", true),
218
+ "availability_date" => array("g:availability_date", true),
219
+ "tax_category" => array("g:tax_category", true),
220
+ "included_destination" => array("g:included_destination", true),
221
+ );
222
+
223
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
224
+ foreach ($this->products as $no => $product) {
225
+ foreach ($product as $key => $value) {
226
+ $this->mapAttribute($no, $key, $googleXMLAttribute[$key][0], $value, $googleXMLAttribute[$key][0]);
227
+ }
228
+ $this->process_google_shipping_attribute_for_xml($no);
229
+ }
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Configure merchant attributes for XML feed
235
+ */
236
+ public function mapAttributeForCSVTXT()
237
+ {
238
+ //Basic product information
239
+ $googleCSVTXTAttribute = array(
240
+ "id" => array("id", false),
241
+ "title" => array("title", true),
242
+ "description" => array("description", true),
243
+ "link" => array("link", true),
244
+ "mobile_link" => array("mobile_link", true),
245
+ "product_type" => array("product type", true),
246
+ "current_category" => array("google product category", true),
247
+ "image" => array("image link", true),
248
+ "images" => array("additional image link", true),
249
+ "images_1" => array("additional image link 1", true),
250
+ "images_2" => array("additional image link 2", true),
251
+ "images_3" => array("additional image link 3", true),
252
+ "images_4" => array("additional image link 4", true),
253
+ "images_5" => array("additional image link 5", true),
254
+ "images_6" => array("additional image link 6", true),
255
+ "images_7" => array("additional image link 7", true),
256
+ "images_8" => array("additional image link 8", true),
257
+ "images_9" => array("additional image link 9", true),
258
+ "images_10" => array("additional image link 10", true),
259
+ "condition" => array("condition", false),
260
+ "availability" => array("availability", false),
261
+ "inventory" => array("inventory", false),
262
+ "override" => array("override", false),
263
+ "price" => array("price", true),
264
+ "sale_price" => array("sale price", true),
265
+ "sale_price_effective_date" => array("sale price effective date", true),
266
+ "brand" => array("brand", true),
267
+ "sku" => array("mpn", true),
268
+ "upc" => array("gtin", true),
269
+ "identifier_exists" => array("identifier exists", true),
270
+ "item_group_id" => array("item group id", false),
271
+ "color" => array("color", true),
272
+ "gender" => array("gender", true),
273
+ "age_group" => array("age group", true),
274
+ "material" => array("material", true),
275
+ "pattern" => array("pattern", true),
276
+ "size" => array("size", true),
277
+ "size_type" => array("size type", true),
278
+ "size_system" => array("size system", true),
279
+ "tax" => array("tax", true),
280
+ "weight" => array("shipping weight", false),
281
+ "length" => array("shipping length", false),
282
+ "width" => array("shipping width", false),
283
+ "height" => array("shipping height", false),
284
+ "shipping_label" => array("shipping label", false),
285
+ "shipping_country" => array("shipping country", false),
286
+ "shipping_service" => array("shipping service", false),
287
+ "shipping_price" => array("shipping price", false),
288
+ "shipping_region" => array("shipping region", false),
289
+ "multipack" => array("multipack", true),
290
+ "is_bundle" => array("is bundle", true),
291
+ "adult" => array("adult", true),
292
+ "adwords_redirect" => array("adwords redirect", true),
293
+ "custom_label_0" => array("custom label 0", true),
294
+ "custom_label_1" => array("custom label 1", true),
295
+ "custom_label_2" => array("custom label 2", true),
296
+ "custom_label_3" => array("custom label 3", true),
297
+ "custom_label_4" => array("custom label 4", true),
298
+ "excluded_destination" => array("excluded destination", true),
299
+ "expiration_date" => array("expiration date", true),
300
+ "unit_pricing_measure" => array("unit pricing measure", true),
301
+ "unit_pricing_base_measure" => array("unit pricing base measure", true),
302
+ "energy_efficiency_class" => array("energy efficiency class", true),
303
+ "loyalty_points" => array("loyalty points", true),
304
+ "installment" => array("installment", true),
305
+ "promotion_id" => array("promotion id", true),
306
+ "cost_of_goods_sold" => array("cost of goods sold", true),
307
+ "availability_date" => array("availability date", true),
308
+ "tax_category" => array("tax category", true),
309
+ "included_destination" => array("included destination", true),
310
+ );
311
+
312
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
313
+ foreach ($this->products as $no => $product) {
314
+ foreach ($product as $key => $value) {
315
+ $this->mapAttribute($no, $key, str_replace(" ", "_", $googleCSVTXTAttribute[$key][0]), $value, $googleCSVTXTAttribute[$key][0]);
316
+ }
317
+ $this->process_google_shipping_attribute_for_CSVTXT($no);
318
+ }
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Map to google attribute
324
+ * @param $no
325
+ * @param $from
326
+ * @param $to
327
+ * @param $value
328
+ * @param bool $cdata
329
+ * @return array
330
+ */
331
+ public function mapAttribute($no, $from, $to, $value, $cdata = false)
332
+ {
333
+ unset($this->products[$no][$from]);
334
+ if ($this->rules['feedType'] == 'xml') {
335
+ return $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata);
336
+ } else {
337
+ return $this->products[$no][$to] = $value;
338
+ }
339
+ }
340
+
341
+
342
+ public
343
+ function process_google_shipping_attribute_for_xml($no)
344
+ {
345
+ $shipping = array('g:shipping_country', 'g:shipping_service', 'g:shipping_price', 'g:shipping_region');
346
+ $shippingAttr = array();
347
+ $products = $this->products[$no];
348
+ foreach ($products as $keyAttr => $valueAttr) {
349
+ if (in_array($keyAttr, $shipping)) {
350
+ array_push($shippingAttr, array($keyAttr => $valueAttr));
351
+ unset($this->products[$no][$keyAttr]);
352
+ }
353
+ }
354
+ if (count($shippingAttr)) {
355
+ $str = "";
356
+ foreach ($shippingAttr as $key => $attributes) {
357
+ foreach ($attributes as $keyAttr => $valueAttr) {
358
+ $str .= str_replace("shipping_", "", $valueAttr);
359
+ }
360
+ }
361
+ return $this->products[$no]['g:shipping'] = $this->formatXMLLine("g:shipping", $str, false);
362
+ }
363
+ return false;
364
+ }
365
+
366
+ public
367
+ function process_google_shipping_attribute_for_CSVTXT($no)
368
+ {
369
+ $shipping = array('shipping_country', 'shipping_service', 'shipping_price', 'shipping_region');
370
+ $shippingAttr = array();
371
+ $products = $this->products[$no];
372
+ foreach ($products as $keyAttr => $valueAttr) {
373
+ if (in_array($keyAttr, $shipping)) {
374
+ array_push($shippingAttr, array($keyAttr => $valueAttr));
375
+ unset($this->products[$no][$keyAttr]);
376
+ }
377
+ }
378
+ if (count($shippingAttr)) {
379
+ $str = "";
380
+ foreach ($shippingAttr as $key => $attributes) {
381
+ foreach ($attributes as $keyAttr => $valueAttr) {
382
+ $country = ($keyAttr == "shipping_country") ? $str .= $valueAttr . ":" : "";
383
+ $service = ($keyAttr == "shipping_service") ? $str .= $valueAttr . ":" : "";
384
+ $price = ($keyAttr == "shipping_price") ? $str .= $valueAttr : "";
385
+ $region = ($keyAttr == "shipping_region") ? $str .= $valueAttr . ":" : "";
386
+ }
387
+ }
388
+ return $this->products[$no]['shipping(country:region:service:price)'] = str_replace(" : ", ":", $str);
389
+ }
390
+ return false;
391
+ }
392
+
393
+ /**
394
+ * Make xml node
395
+ *
396
+ * @param string $attribute Attribute Name
397
+ * @param string $value Attribute Value
398
+ * @param bool $cdata
399
+ * @param string $space
400
+ * @return string
401
+ */
402
+ function formatXMLLine($attribute, $value, $cdata, $space = "")
403
+ {
404
+ //Make single XML node
405
+ if (!empty($value))
406
+ $value = trim($value);
407
+ if (gettype($value) == 'array')
408
+ $value = json_encode($value);
409
+ if (strpos($value, "<![CDATA[") === false && substr(trim($value), 0, 4) == "http") {
410
+ $value = "<![CDATA[$value]]>";
411
+ } elseif (strpos($value, "<![CDATA[") === false && $cdata === true && !empty($value)) {
412
+ $value = "<![CDATA[$value]]>";
413
+ } elseif ($cdata) {
414
+ if(!empty($value)){
415
+ $value = "<![CDATA[$value]]>";
416
+ }
417
+ }
418
+
419
+ if (substr($attribute, 0, 23) == 'g:additional_image_link') {
420
+ $attribute = "g:additional_image_link";
421
+ }
422
+
423
+ return "
424
+ $space<$attribute>$value</$attribute>";
425
+ }
426
+
427
+
428
+ /**
429
+ * Make XML Feed Header
430
+ * @return string
431
+ */
432
+ public function get_xml_feed_header()
433
+ {
434
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
435
+ <rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
436
+ <channel>
437
+ <title><![CDATA[' . html_entity_decode(get_option('blogname')) . ']]></title>
438
+ <link><![CDATA[' . site_url() . ']]></link>
439
+ <description><![CDATA[' . html_entity_decode( get_option('blogdescription')) . ']]></description>';
440
+ return $output;
441
+ }
442
+
443
+ /** Make XML Feed
444
+ * @param $items
445
+ * @return bool|string
446
+ */
447
+ public function get_xml_feed_body($items)
448
+ {
449
+ $feed = "";
450
+ //$feed .= $this->get_feed_header();
451
+ $feed .= "\n";
452
+ if ($items) {
453
+ foreach ($items as $item => $products) {
454
+ $feed .= " <".$this->feedWrapper.">";
455
+ foreach ($products as $key => $value) {
456
+ if (!empty($value)){
457
+ $feed .= $value;
458
+ }
459
+ }
460
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
461
+ }
462
+ // $feed .= $this->get_feed_footer();
463
+
464
+ return $feed;
465
+ }
466
+ return false;
467
+ }
468
+
469
+ /**
470
+ * Make XML Feed Footer
471
+ * @return string
472
+ */
473
+ public function get_xml_feed_footer()
474
+ {
475
+ $footer = " </channel>
476
+ </rss>";
477
+ return $footer;
478
+ }
479
+
480
+ /**
481
+ * Short Products
482
+ * @return array
483
+ */
484
+ public function short_products()
485
+ {
486
+ if ($this->products) {
487
+ update_option('wpf_progress', "Shorting Products");
488
+ sleep(1);
489
+ $array = array();
490
+ $ij = 0;
491
+ foreach ($this->products as $key => $item) {
492
+ $array[$ij] = $item;
493
+ unset($this->products[$key]);
494
+ $ij++;
495
+ }
496
+ return $this->products = $array;
497
+ }
498
+ return $this->products;
499
+ }
500
+
501
+ /**
502
+ * Responsible to make CSV feed
503
+ * @return string
504
+ */
505
+ public function get_csv_feed()
506
+ {
507
+ if ($this->products) {
508
+ $headers = array_keys($this->products[0]);
509
+ $feed[] = $headers;
510
+ foreach ($this->products as $no => $product) {
511
+ $row = array();
512
+ foreach ($headers as $key => $header) {
513
+ if (strpos($header, "additional image link") !== false) {
514
+ $header = "additional image link";
515
+ }
516
+ $row[] = isset($product[$header]) ? $product[$header] : "";;
517
+ }
518
+ $feed[] = $row;
519
+ }
520
+ return $feed;
521
+ }
522
+ return false;
523
+ }
524
  }
includes/feeds/class-woo-feed-google.php CHANGED
@@ -1,630 +1,630 @@
1
- <?php
2
-
3
- /**
4
- * Class Google
5
- *
6
- * Responsible for processing and generating feed for Google.com
7
- *
8
- * @since 1.0.0
9
- * @package Google
10
- *
11
- */
12
- class Woo_Feed_Google
13
- {
14
-
15
- /**
16
- * This variable is responsible for holding all product attributes and their values
17
- *
18
- * @since 1.0.0
19
- * @var array $products Contains all the product attributes to generate feed
20
- * @access public
21
- */
22
- public $products;
23
-
24
- /**
25
- * This variable is responsible for holding feed configuration form values
26
- *
27
- * @since 1.0.0
28
- * @var array $rules Contains feed configuration form values
29
- * @access public
30
- */
31
- public $rules;
32
-
33
- /**
34
- * This variable is responsible for mapping store attributes to merchant attribute
35
- *
36
- * @since 1.0.0
37
- * @var array $mapping Map store attributes to merchant attribute
38
- * @access public
39
- */
40
- public $mapping;
41
-
42
- /**
43
- * This variable is responsible for generate error logs
44
- *
45
- * @since 1.0.0
46
- * @var array $errors hold error logs
47
- * @access public
48
- */
49
- public $errors;
50
-
51
- /**
52
- * This variable is responsible for generate error logs
53
- *
54
- * @since 1.0.0
55
- * @var array $warnings hold warnings logs
56
- * @access public
57
- */
58
- public $warnings;
59
-
60
- /**
61
- * This variable is responsible for making error number
62
- *
63
- * @since 1.0.0
64
- * @var int $errorCounter Generate error number
65
- * @access public
66
- */
67
- public $errorCounter;
68
-
69
- /**
70
- * Feed Wrapper text for enclosing each product information
71
- *
72
- * @since 1.0.0
73
- * @var string $feedWrapper Feed Wrapper text
74
- * @access public
75
- */
76
- public $feedWrapper = 'item';
77
-
78
- /**
79
- * Store product information
80
- *
81
- * @since 1.0.0
82
- * @var array $storeProducts
83
- * @access public
84
- */
85
- private $storeProducts;
86
-
87
- /**
88
- * Define the core functionality to generate feed.
89
- *
90
- * Set the feed rules. Map products according to the rules and Check required attributes
91
- * and their values according to merchant specification.
92
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
93
- * @since 1.0.0
94
- */
95
- public function __construct($feedRule)
96
- {
97
- $products = new Woo_Feed_Products();
98
- $storeProducts = $products->woo_feed_get_visible_product($feedRule);
99
- if(!empty($storeProducts)){
100
- $engine = new WF_Engine($storeProducts, $feedRule);
101
- $this->products = $engine->mapProductsByRules();
102
- $this->rules = $feedRule;
103
- if ($feedRule['feedType'] == 'xml') {
104
- $this->mapAttributeForXML();
105
- } else {
106
- $this->mapAttributeForCSVTXT();
107
- }
108
- }else{
109
- $this->products=array();
110
- }
111
-
112
- }
113
-
114
-
115
- /**
116
- * Return Feed
117
- * @return array
118
- */
119
- public function returnFinalProduct()
120
- {
121
- if(!empty($this->products)){
122
- $engine = new WF_Engine($this->products, $this->rules);
123
- if ($this->rules['feedType'] == 'xml') {
124
- //return $this->get_feed($this->products);
125
- $feed=array(
126
- "header"=>$this->get_xml_feed_header(),
127
- "body"=>$this->get_xml_feed($this->products),
128
- "footer"=>$this->get_xml_feed_footer(),
129
- );
130
- return $feed;
131
- } elseif ($this->rules['feedType'] == 'txt') {
132
- //return $engine->get_txt_feed();
133
- $feed=array(
134
- "body"=>$engine->get_txt_feed(),
135
- "header"=>$engine->txtFeedHeader,
136
- "footer"=>"",
137
- );
138
- return $feed;
139
- } elseif ($this->rules['feedType'] == 'csv') {
140
- //return $engine->get_csv_feed();
141
- $feed=array(
142
- "body"=>$engine->get_csv_feed(),
143
- "header"=>$engine->csvFeedHeader,
144
- "footer"=>"",
145
- );
146
- return $feed;
147
- }
148
- }
149
-
150
- $feed=array(
151
- "body"=>"",
152
- "header"=>"",
153
- "footer"=>"",
154
- );
155
- return $feed;
156
- }
157
-
158
- /**
159
- * Configure merchant attributes for XML feed
160
- */
161
- public function mapAttributeForXML()
162
- {
163
-
164
- $googleXMLAttribute = array(
165
- "id" => array("g:id", false),
166
- "title" => array("title", true),
167
- "description" => array("description", true),
168
- "link" => array("link", true),
169
- "mobile_link" => array("mobile_link", true),
170
- "product_type" => array("g:product_type", true),
171
- "current_category" => array("g:google_product_category", true),
172
- "image" => array("g:image_link", true),
173
- "images" => array("g:additional_image_link", false),
174
- "images_1" => array("g:additional_image_link_1", true),
175
- "images_2" => array("g:additional_image_link_2", true),
176
- "images_3" => array("g:additional_image_link_3", true),
177
- "images_4" => array("g:additional_image_link_4", true),
178
- "images_5" => array("g:additional_image_link_5", true),
179
- "images_6" => array("g:additional_image_link_6", true),
180
- "images_7" => array("g:additional_image_link_7", true),
181
- "images_8" => array("g:additional_image_link_8", true),
182
- "images_9" => array("g:additional_image_link_9", true),
183
- "images_10" => array("g:additional_image_link_10", true),
184
- "condition" => array("g:condition", false),
185
- "availability" => array("g:availability", false),
186
- "availability_date" => array("g:availability_date", false),
187
- "inventory" => array("g:inventory", false),
188
- "price" => array("g:price", true),
189
- "sale_price" => array("g:sale_price", true),
190
- "sale_price_effective_date" => array("g:sale_price_effective_date", true),
191
- "brand" => array("g:brand", true),
192
- "sku" => array("g:mpn", true),
193
- "upc" => array("g:gtin", true),
194
- "identifier_exists" => array("g:identifier_exists", true),
195
- "item_group_id" => array("g:item_group_id", false),
196
- "color" => array("g:color", true),
197
- "gender" => array("g:gender", true),
198
- "age_group" => array("g:age_group", true),
199
- "material" => array("g:material", true),
200
- "pattern" => array("g:pattern", true),
201
- "size" => array("g:size", true),
202
- "size_type" => array("g:size_type", true),
203
- "size_system" => array("g:size_system", true),
204
- "tax" => array("tax", true),
205
- "tax_country" => array("g:tax_country", true),
206
- "tax_region" => array("g:tax_region", true),
207
- "tax_rate" => array("g:tax_rate", true),
208
- "tax_ship" => array("g:tax_ship", true),
209
- "tax_category" => array("g:tax_category", true),
210
- "weight" => array("g:shipping_weight", false),
211
- "length" => array("g:shipping_length", false),
212
- "width" => array("g:shipping_width", false),
213
- "height" => array("g:shipping_height", false),
214
- "shipping_label" => array("g:shipping_label", false),
215
- "shipping_country" => array("g:shipping_country", false),
216
- "shipping_service" => array("g:shipping_service", false),
217
- "shipping_price" => array("g:shipping_price", false),
218
- "shipping_region" => array("g:shipping_region", false),
219
- "multipack" => array("g:multipack", true),
220
- "is_bundle" => array("g:is_bundle", true),
221
- "adult" => array("g:adult", true),
222
- "adwords_redirect" => array("g:adwords_redirect", true),
223
- "custom_label_0" => array("g:custom_label_0", true),
224
- "custom_label_1" => array("g:custom_label_1", true),
225
- "custom_label_2" => array("g:custom_label_2", true),
226
- "custom_label_3" => array("g:custom_label_3", true),
227
- "custom_label_4" => array("g:custom_label_4", true),
228
- "excluded_destination" => array("g:excluded_destination", true),
229
- "included_destination" => array("g:included_destination", true),
230
- "expiration_date" => array("g:expiration_date", true),
231
- "unit_pricing_measure" => array("g:unit_pricing_measure", true),
232
- "unit_pricing_base_measure" => array("g:unit_pricing_base_measure", true),
233
- "energy_efficiency_class" => array("g:energy_efficiency_class", true),
234
- "loyalty_points" => array("g:loyalty_points", true),
235
- "installment" => array("g:installment", true),
236
- "promotion_id" => array("g:promotion_id", true),
237
- "cost_of_goods_sold" => array("g:cost_of_goods_sold", true),
238
- );
239
-
240
- if ( is_countable( $this->products ) && count( $this->products ) ) {
241
- foreach ($this->products as $no => $product) {
242
- $this->identifier_status_add($no);
243
- foreach ($product as $key => $value) {
244
- $this->mapAttribute($no, $key, $googleXMLAttribute[$key][0], $value, $googleXMLAttribute[$key][0]);
245
- }
246
-
247
- $this->process_google_shipping_attribute_for_xml($no);
248
- $this->process_google_tax_attribute_for_xml($no);
249
- }
250
- }
251
- }
252
-
253
- /**
254
- * Configure merchant attributes for XML feed
255
- */
256
- public function mapAttributeForCSVTXT()
257
- {
258
- //Basic product information
259
- $googleCSVTXTAttribute = array(
260
- "id" => array("id", false),
261
- "title" => array("title", true),
262
- "description" => array("description", true),
263
- "link" => array("link", true),
264
- "mobile_link" => array("mobile_link", true),
265
- "product_type" => array("product type", true),
266
- "current_category" => array("google product category", true),
267
- "image" => array("image link", true),
268
- "images" => array("additional image link", true),
269
- "images_1" => array("additional image link 1", true),
270
- "images_2" => array("additional image link 2", true),
271
- "images_3" => array("additional image link 3", true),
272
- "images_4" => array("additional image link 4", true),
273
- "images_5" => array("additional image link 5", true),
274
- "images_6" => array("additional image link 6", true),
275
- "images_7" => array("additional image link 7", true),
276
- "images_8" => array("additional image link 8", true),
277
- "images_9" => array("additional image link 9", true),
278
- "images_10" => array("additional image link 10", true),
279
- "condition" => array("condition", false),
280
- "availability" => array("availability", false),
281
- "availability_date" => array("availability date", false),
282
- "inventory" => array("inventory", false),
283
- "price" => array("price", true),
284
- "sale_price" => array("sale price", true),
285
- "sale_price_effective_date" => array("sale price effective date", true),
286
- "brand" => array("brand", true),
287
- "sku" => array("mpn", true),
288
- "upc" => array("gtin", true),
289
- "identifier_exists" => array("identifier exists", true),
290
- "item_group_id" => array("item group id", false),
291
- "color" => array("color", true),
292
- "gender" => array("gender", true),
293
- "age_group" => array("age group", true),
294
- "material" => array("material", true),
295
- "pattern" => array("pattern", true),
296
- "size" => array("size", true),
297
- "size_type" => array("size type", true),
298
- "size_system" => array("size system", true),
299
- "tax" => array("tax", true),
300
- "tax_country" => array("tax country", true),
301
- "tax_region" => array("tax region", true),
302
- "tax_rate" => array("tax rate", true),
303
- "tax_ship" => array("tax ship", true),
304
- "tax_category" => array("tax category", true),
305
- "weight" => array("shipping weight", false),
306
- "length" => array("shipping length", false),
307
- "width" => array("shipping width", false),
308
- "height" => array("shipping height", false),
309
- "shipping_label" => array("shipping label", false),
310
- "shipping_country" => array("shipping country", false),
311
- "shipping_service" => array("shipping service", false),
312
- "shipping_price" => array("shipping price", false),
313
- "shipping_region" => array("shipping region", false),
314
- "multipack" => array("multipack", true),
315
- "is_bundle" => array("is bundle", true),
316
- "adult" => array("adult", true),
317
- "adwords_redirect" => array("adwords redirect", true),
318
- "custom_label_0" => array("custom label 0", true),
319
- "custom_label_1" => array("custom label 1", true),
320
- "custom_label_2" => array("custom label 2", true),
321
- "custom_label_3" => array("custom label 3", true),
322
- "custom_label_4" => array("custom label 4", true),
323
- "excluded_destination" => array("excluded destination", true),
324
- "included_destination" => array("included destination", true),
325
- "expiration_date" => array("expiration date", true),
326
- "unit_pricing_measure" => array("unit pricing measure", true),
327
- "unit_pricing_base_measure" => array("unit pricing base measure", true),
328
- "energy_efficiency_class" => array("energy efficiency class", true),
329
- "loyalty_points" => array("loyalty points", true),
330
- "installment" => array("installment", true),
331
- "promotion_id" => array("promotion id", true),
332
- "cost_of_goods_sold" => array("cost of goods sold", true),
333
- );
334
-
335
- if ( is_countable( $this->products ) && count( $this->products ) ) {
336
- foreach ($this->products as $no => $product) {
337
- foreach ($product as $key => $value) {
338
- $this->mapAttribute($no, $key, $googleCSVTXTAttribute[$key][0], $value, $googleCSVTXTAttribute[$key][0]);
339
- }
340
- $this->process_google_shipping_attribute_for_CSVTXT($no);
341
- }
342
- }
343
- }
344
-
345
- /**
346
- * Map to google attribute
347
- * @param $no
348
- * @param $from
349
- * @param $to
350
- * @param $value
351
- * @param bool $cdata
352
- * @return array
353
- */
354
- public function mapAttribute($no, $from, $to, $value, $cdata = false)
355
- {
356
- unset($this->products[$no][$from]);
357
- if($to=='g:color'){
358
- $value=str_replace(",","/",$value);
359
- }
360
- if ($this->rules['feedType'] == 'xml') {
361
- return $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata);
362
- } else {
363
- return $this->products[$no][$to] = $value;
364
- }
365
- }
366
-
367
- public function identifier_status_add($no)
368
- {
369
- $identifier = array('brand', 'upc', 'sku', 'mpn', 'gtin');
370
- $product = $this->products[$no];
371
-
372
- if(!array_key_exists('g:identifier_exists',$product)) {
373
- if (count(array_intersect_key(array_flip($identifier), $product)) >= 2) {
374
- # Any 2 required keys exist!
375
- $countIdentifier=0;
376
- if(array_key_exists('brand',$product) && !empty($product['brand'])){
377
- $countIdentifier++;
378
- }
379
- if(array_key_exists('upc',$product) && !empty($product['upc'])){
380
- $countIdentifier++;
381
- }
382
- if(array_key_exists('sku',$product) && !empty($product['sku'])){
383
- $countIdentifier++;
384
- }
385
- if(array_key_exists('mpn',$product) && !empty($product['mpn'])){
386
- $countIdentifier++;
387
- }
388
- if(array_key_exists('gtin',$product) && !empty($product['gtin'])){
389
- $countIdentifier++;
390
- }
391
- if($countIdentifier>=2){
392
- $this->products[$no]["g:identifier_exists"] = $this->formatXMLLine("g:identifier_exists", "yes", $cdata = true);
393
- }else{
394
- $this->products[$no]["g:identifier_exists"] = $this->formatXMLLine("g:identifier_exists", "no", $cdata = true);
395
- }
396
- } else {
397
- $this->products[$no]["g:identifier_exists"] = $this->formatXMLLine("g:identifier_exists", "no", $cdata = true);
398
- }
399
- }
400
- }
401
-
402
-
403
- /**
404
- * @param $no
405
- * @return bool|string
406
- */
407
- public
408
- function process_google_shipping_attribute_for_xml($no)
409
- {
410
- $shipping = array('g:shipping_country', 'g:shipping_service', 'g:shipping_price', 'g:shipping_region');
411
- $shippingAttr = array();
412
- $products = $this->products[$no];
413
- foreach ($products as $keyAttr => $valueAttr) {
414
- if (in_array($keyAttr, $shipping)) {
415
- array_push($shippingAttr, array($keyAttr => $valueAttr));
416
- unset($this->products[$no][$keyAttr]);
417
- }
418
- }
419
- if (count($shippingAttr)) {
420
- $str = "";
421
- foreach ($shippingAttr as $key => $attributes) {
422
- foreach ($attributes as $keyAttr => $valueAttr) {
423
- $str .= str_replace("shipping_", "", $valueAttr);
424
- }
425
- }
426
- return $this->products[$no]['g:shipping'] = $this->formatXMLLine("g:shipping", $str, false);
427
- }
428
- return false;
429
- }
430
-
431
- public
432
- function process_google_tax_attribute_for_xml($no)
433
- {
434
- $tax = array('g:tax_country', 'g:tax_region', 'g:tax_rate', 'g:tax_ship');
435
- $taxAttr = array();
436
- $products = $this->products[$no];
437
- foreach ($products as $keyAttr => $valueAttr) {
438
- if (in_array($keyAttr, $tax)) {
439
- array_push($taxAttr, array($keyAttr => $valueAttr));
440
- unset($this->products[$no][$keyAttr]);
441
- }
442
- }
443
- if (count($taxAttr)) {
444
- $str = "";
445
- foreach ($taxAttr as $key => $attributes) {
446
- foreach ($attributes as $keyAttr => $valueAttr) {
447
- // if($keyAttr != "g:tax_ship")
448
- // {
449
- $str .= str_replace("tax_", "", $valueAttr);
450
- $str = str_replace("ship", "tax_ship", $str);
451
- // }
452
- // else
453
- // {
454
- // $str .= $valueAttr;
455
- // }
456
- }
457
- }
458
- return $this->products[$no]['g:tax'] = $this->formatXMLLine("g:tax", $str, false);
459
- }
460
- return false;
461
- }
462
-
463
- /**
464
- * @param $no
465
- * @return bool|mixed
466
- */
467
- public
468
- function process_google_shipping_attribute_for_CSVTXT($no)
469
- {
470
- $shipping = array('shipping country', 'shipping service', 'shipping price', 'shipping region');
471
- $shippingAttr = array();
472
- $products = $this->products[$no];
473
- foreach ($products as $keyAttr => $valueAttr) {
474
- if (in_array($keyAttr, $shipping)) {
475
- array_push($shippingAttr, array($keyAttr => $valueAttr));
476
- unset($this->products[$no][$keyAttr]);
477
- }
478
- }
479
- if (count($shippingAttr)) {
480
- $str = "";
481
- foreach ($shippingAttr as $key => $attributes) {
482
- foreach ($attributes as $keyAttr => $valueAttr) {
483
- $country = ($keyAttr == "shipping country") ? $str .= $valueAttr . ":" : "";
484
- $service = ($keyAttr == "shipping service") ? $str .= $valueAttr . ":" : "";
485
- $price = ($keyAttr == "shipping price") ? $str .= $valueAttr : "";
486
- $region = ($keyAttr == "shipping region") ? $str .= $valueAttr . ":" : "";
487
- }
488
- }
489
- return $this->products[$no]['shipping(country:region:service:price)'] = str_replace(" : ",":", $str);
490
- }
491
- return false;
492
- }
493
-
494
- public
495
- function process_google_tax_attribute_for_CSVTXT($no)
496
- {
497
- $tax = array('tax country', 'tax region', 'tax rate', 'tax ship');
498
- $taxAttr = array();
499
- $products = $this->products[$no];
500
- foreach ($products as $keyAttr => $valueAttr) {
501
- if (in_array($keyAttr, $tax)) {
502
- array_push($taxAttr, array($keyAttr => $valueAttr));
503
- unset($this->products[$no][$keyAttr]);
504
- }
505
- }
506
- if (count($taxAttr)) {
507
- $str = "";
508
- foreach ($taxAttr as $key => $attributes) {
509
- foreach ($attributes as $keyAttr => $valueAttr) {
510
- $country = ($keyAttr == "tax country") ? $str .= $valueAttr . ":" : "";
511
- $region = ($keyAttr == "tax region") ? $str .= $valueAttr . ":" : "";
512
- $rate = ($keyAttr == "tax rate") ? $str .= $valueAttr . ":": "";
513
- $ship = ($keyAttr == "tax ship") ? $str .= $valueAttr . ":" : "";
514
- }
515
- }
516
- return $this->products[$no]['tax(country:region:rate:tax_ship)'] = str_replace(" : ",":", $str);
517
- }
518
- return false;
519
- }
520
-
521
- function formatXMLLine($attribute, $value, $cdata, $space = "")
522
- {
523
- //Make single XML node
524
- if (!empty($value))
525
- $value = trim($value);
526
- if (gettype($value) == 'array')
527
- $value = json_encode($value);
528
- if (strpos($value, "<![CDATA[") === false && substr(trim($value), 0, 4) == "http") {
529
- $value = "<![CDATA[$value]]>";
530
- } elseif (strpos($value, "<![CDATA[") === false && $cdata === true && !empty($value)) {
531
- $value = "<![CDATA[$value]]>";
532
- } else if ($cdata) {
533
- if(!empty($value)){
534
- $value = "<![CDATA[$value]]>";
535
- }
536
- }
537
-
538
- if (substr($attribute, 0, 23) == 'g:additional_image_link') {
539
- $attribute = "g:additional_image_link";
540
- }
541
-
542
- return "
543
- $space<$attribute>$value</$attribute>";
544
- }
545
-
546
-
547
-
548
- public function get_xml_feed_header()
549
- {
550
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
551
- <rss version="2.0" xmlns:g="http://base.google.com/ns/1.0" xmlns:c="http://base.google.com/cns/1.0">
552
- <channel>
553
- <title><![CDATA[' . html_entity_decode(get_option('blogname')) . ']]></title>
554
- <link><![CDATA['.home_url().']]></link>
555
- <description><![CDATA['.html_entity_decode(get_option('blogdescription')).']]></description>';
556
- return $output;
557
- }
558
-
559
- public function get_xml_feed($items)
560
- {
561
- $feed = "";
562
- //$feed .= $this->get_feed_header();
563
- $feed .= "\n";
564
- if ($items) {
565
- foreach ($items as $item => $products) {
566
- $feed .= " <" . $this->feedWrapper . ">";
567
-
568
- foreach ($products as $key => $value) {
569
- if (!empty($value)){
570
- $feed .= $value;
571
- }
572
- }
573
- $feed .= "\n </" . $this->feedWrapper . ">\n";
574
- }
575
- //$feed .= $this->get_feed_footer();
576
-
577
- return $feed;
578
- }
579
- return false;
580
- }
581
-
582
- public function get_xml_feed_footer()
583
- {
584
- $footer = " </channel>
585
- </rss>";
586
- return $footer;
587
- }
588
-
589
- public function short_products()
590
- {
591
- if ($this->products) {
592
- update_option('wpf_progress', "Shorting Products");
593
- sleep(1);
594
- $array = array();
595
- $ij = 0;
596
- foreach ($this->products as $key => $item) {
597
- $array[$ij] = $item;
598
- unset($this->products[$key]);
599
- $ij++;
600
- }
601
- return $this->products = $array;
602
- }
603
- return $this->products;
604
- }
605
-
606
- /**
607
- * Responsible to make CSV feed
608
- * @return string
609
- */
610
- public function get_csv_feed()
611
- {
612
- if ($this->products) {
613
- $headers = array_keys($this->products[0]);
614
- $feed[] = $headers;
615
- foreach ($this->products as $no => $product) {
616
- $row = array();
617
- foreach ($headers as $key => $header) {
618
- if (strpos($header, "additional image link") !== false) {
619
- $header = "additional image link";
620
- }
621
- $row[] = isset($product[$header]) ? $product[$header] : "";;
622
- }
623
- $feed[] = $row;
624
- }
625
- return $feed;
626
- }
627
- return false;
628
- }
629
-
630
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Google
5
+ *
6
+ * Responsible for processing and generating feed for Google.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Google
10
+ *
11
+ */
12
+ class Woo_Feed_Google
13
+ {
14
+
15
+ /**
16
+ * This variable is responsible for holding all product attributes and their values
17
+ *
18
+ * @since 1.0.0
19
+ * @var array $products Contains all the product attributes to generate feed
20
+ * @access public
21
+ */
22
+ public $products;
23
+
24
+ /**
25
+ * This variable is responsible for holding feed configuration form values
26
+ *
27
+ * @since 1.0.0
28
+ * @var array $rules Contains feed configuration form values
29
+ * @access public
30
+ */
31
+ public $rules;
32
+
33
+ /**
34
+ * This variable is responsible for mapping store attributes to merchant attribute
35
+ *
36
+ * @since 1.0.0
37
+ * @var array $mapping Map store attributes to merchant attribute
38
+ * @access public
39
+ */
40
+ public $mapping;
41
+
42
+ /**
43
+ * This variable is responsible for generate error logs
44
+ *
45
+ * @since 1.0.0
46
+ * @var array $errors hold error logs
47
+ * @access public
48
+ */
49
+ public $errors;
50
+
51
+ /**
52
+ * This variable is responsible for generate error logs
53
+ *
54
+ * @since 1.0.0
55
+ * @var array $warnings hold warnings logs
56
+ * @access public
57
+ */
58
+ public $warnings;
59
+
60
+ /**
61
+ * This variable is responsible for making error number
62
+ *
63
+ * @since 1.0.0
64
+ * @var int $errorCounter Generate error number
65
+ * @access public
66
+ */
67
+ public $errorCounter;
68
+
69
+ /**
70
+ * Feed Wrapper text for enclosing each product information
71
+ *
72
+ * @since 1.0.0
73
+ * @var string $feedWrapper Feed Wrapper text
74
+ * @access public
75
+ */
76
+ public $feedWrapper = 'item';
77
+
78
+ /**
79
+ * Store product information
80
+ *
81
+ * @since 1.0.0
82
+ * @var array $storeProducts
83
+ * @access public
84
+ */
85
+ private $storeProducts;
86
+
87
+ /**
88
+ * Define the core functionality to generate feed.
89
+ *
90
+ * Set the feed rules. Map products according to the rules and Check required attributes
91
+ * and their values according to merchant specification.
92
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
93
+ * @since 1.0.0
94
+ */
95
+ public function __construct($feedRule)
96
+ {
97
+ $products = new Woo_Feed_Products();
98
+ $storeProducts = $products->woo_feed_get_visible_product($feedRule);
99
+ if(!empty($storeProducts)){
100
+ $engine = new WF_Engine($storeProducts, $feedRule);
101
+ $this->products = $engine->mapProductsByRules();
102
+ $this->rules = $feedRule;
103
+ if ($feedRule['feedType'] == 'xml') {
104
+ $this->mapAttributeForXML();
105
+ } else {
106
+ $this->mapAttributeForCSVTXT();
107
+ }
108
+ }else{
109
+ $this->products=array();
110
+ }
111
+
112
+ }
113
+
114
+
115
+ /**
116
+ * Return Feed
117
+ * @return array
118
+ */
119
+ public function returnFinalProduct()
120
+ {
121
+ if(!empty($this->products)){
122
+ $engine = new WF_Engine($this->products, $this->rules);
123
+ if ($this->rules['feedType'] == 'xml') {
124
+ //return $this->get_feed($this->products);
125
+ $feed=array(
126
+ "header"=>$this->get_xml_feed_header(),
127
+ "body"=>$this->get_xml_feed($this->products),
128
+ "footer"=>$this->get_xml_feed_footer(),
129
+ );
130
+ return $feed;
131
+ } elseif ($this->rules['feedType'] == 'txt') {
132
+ //return $engine->get_txt_feed();
133
+ $feed=array(
134
+ "body"=>$engine->get_txt_feed(),
135
+ "header"=>$engine->txtFeedHeader,
136
+ "footer"=>"",
137
+ );
138
+ return $feed;
139
+ } elseif ($this->rules['feedType'] == 'csv') {
140
+ //return $engine->get_csv_feed();
141
+ $feed=array(
142
+ "body"=>$engine->get_csv_feed(),
143
+ "header"=>$engine->csvFeedHeader,
144
+ "footer"=>"",
145
+ );
146
+ return $feed;
147
+ }
148
+ }
149
+
150
+ $feed=array(
151
+ "body"=>"",
152
+ "header"=>"",
153
+ "footer"=>"",
154
+ );
155
+ return $feed;
156
+ }
157
+
158
+ /**
159
+ * Configure merchant attributes for XML feed
160
+ */
161
+ public function mapAttributeForXML()
162
+ {
163
+
164
+ $googleXMLAttribute = array(
165
+ "id" => array("g:id", false),
166
+ "title" => array("title", true),
167
+ "description" => array("description", true),
168
+ "link" => array("link", true),
169
+ "mobile_link" => array("mobile_link", true),
170
+ "product_type" => array("g:product_type", true),
171
+ "current_category" => array("g:google_product_category", true),
172
+ "image" => array("g:image_link", true),
173
+ "images" => array("g:additional_image_link", false),
174
+ "images_1" => array("g:additional_image_link_1", true),
175
+ "images_2" => array("g:additional_image_link_2", true),
176
+ "images_3" => array("g:additional_image_link_3", true),
177
+ "images_4" => array("g:additional_image_link_4", true),
178
+ "images_5" => array("g:additional_image_link_5", true),
179
+ "images_6" => array("g:additional_image_link_6", true),
180
+ "images_7" => array("g:additional_image_link_7", true),
181
+ "images_8" => array("g:additional_image_link_8", true),
182
+ "images_9" => array("g:additional_image_link_9", true),
183
+ "images_10" => array("g:additional_image_link_10", true),
184
+ "condition" => array("g:condition", false),
185
+ "availability" => array("g:availability", false),
186
+ "availability_date" => array("g:availability_date", false),
187
+ "inventory" => array("g:inventory", false),
188
+ "price" => array("g:price", true),
189
+ "sale_price" => array("g:sale_price", true),
190
+ "sale_price_effective_date" => array("g:sale_price_effective_date", true),
191
+ "brand" => array("g:brand", true),
192
+ "sku" => array("g:mpn", true),
193
+ "upc" => array("g:gtin", true),
194
+ "identifier_exists" => array("g:identifier_exists", true),
195
+ "item_group_id" => array("g:item_group_id", false),
196
+ "color" => array("g:color", true),
197
+ "gender" => array("g:gender", true),
198
+ "age_group" => array("g:age_group", true),
199
+ "material" => array("g:material", true),
200
+ "pattern" => array("g:pattern", true),
201
+ "size" => array("g:size", true),
202
+ "size_type" => array("g:size_type", true),
203
+ "size_system" => array("g:size_system", true),
204
+ "tax" => array("tax", true),
205
+ "tax_country" => array("g:tax_country", true),
206
+ "tax_region" => array("g:tax_region", true),
207
+ "tax_rate" => array("g:tax_rate", true),
208
+ "tax_ship" => array("g:tax_ship", true),
209
+ "tax_category" => array("g:tax_category", true),
210
+ "weight" => array("g:shipping_weight", false),
211
+ "length" => array("g:shipping_length", false),
212
+ "width" => array("g:shipping_width", false),
213
+ "height" => array("g:shipping_height", false),
214
+ "shipping_label" => array("g:shipping_label", false),
215
+ "shipping_country" => array("g:shipping_country", false),
216
+ "shipping_service" => array("g:shipping_service", false),
217
+ "shipping_price" => array("g:shipping_price", false),
218
+ "shipping_region" => array("g:shipping_region", false),
219
+ "multipack" => array("g:multipack", true),
220
+ "is_bundle" => array("g:is_bundle", true),
221
+ "adult" => array("g:adult", true),
222
+ "adwords_redirect" => array("g:adwords_redirect", true),
223
+ "custom_label_0" => array("g:custom_label_0", true),
224
+ "custom_label_1" => array("g:custom_label_1", true),
225
+ "custom_label_2" => array("g:custom_label_2", true),
226
+ "custom_label_3" => array("g:custom_label_3", true),
227
+ "custom_label_4" => array("g:custom_label_4", true),
228
+ "excluded_destination" => array("g:excluded_destination", true),
229
+ "included_destination" => array("g:included_destination", true),
230
+ "expiration_date" => array("g:expiration_date", true),
231
+ "unit_pricing_measure" => array("g:unit_pricing_measure", true),
232
+ "unit_pricing_base_measure" => array("g:unit_pricing_base_measure", true),
233
+ "energy_efficiency_class" => array("g:energy_efficiency_class", true),
234
+ "loyalty_points" => array("g:loyalty_points", true),
235
+ "installment" => array("g:installment", true),
236
+ "promotion_id" => array("g:promotion_id", true),
237
+ "cost_of_goods_sold" => array("g:cost_of_goods_sold", true),
238
+ );
239
+
240
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
241
+ foreach ($this->products as $no => $product) {
242
+ $this->identifier_status_add($no);
243
+ foreach ($product as $key => $value) {
244
+ $this->mapAttribute($no, $key, $googleXMLAttribute[$key][0], $value, $googleXMLAttribute[$key][0]);
245
+ }
246
+
247
+ $this->process_google_shipping_attribute_for_xml($no);
248
+ $this->process_google_tax_attribute_for_xml($no);
249
+ }
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Configure merchant attributes for XML feed
255
+ */
256
+ public function mapAttributeForCSVTXT()
257
+ {
258
+ //Basic product information
259
+ $googleCSVTXTAttribute = array(
260
+ "id" => array("id", false),
261
+ "title" => array("title", true),
262
+ "description" => array("description", true),
263
+ "link" => array("link", true),
264
+ "mobile_link" => array("mobile_link", true),
265
+ "product_type" => array("product type", true),
266
+ "current_category" => array("google product category", true),
267
+ "image" => array("image link", true),
268
+ "images" => array("additional image link", true),
269
+ "images_1" => array("additional image link 1", true),
270
+ "images_2" => array("additional image link 2", true),
271
+ "images_3" => array("additional image link 3", true),
272
+ "images_4" => array("additional image link 4", true),
273
+ "images_5" => array("additional image link 5", true),
274
+ "images_6" => array("additional image link 6", true),
275
+ "images_7" => array("additional image link 7", true),
276
+ "images_8" => array("additional image link 8", true),
277
+ "images_9" => array("additional image link 9", true),
278
+ "images_10" => array("additional image link 10", true),
279
+ "condition" => array("condition", false),
280
+ "availability" => array("availability", false),
281
+ "availability_date" => array("availability date", false),
282
+ "inventory" => array("inventory", false),
283
+ "price" => array("price", true),
284
+ "sale_price" => array("sale price", true),
285
+ "sale_price_effective_date" => array("sale price effective date", true),
286
+ "brand" => array("brand", true),
287
+ "sku" => array("mpn", true),
288
+ "upc" => array("gtin", true),
289
+ "identifier_exists" => array("identifier exists", true),
290
+ "item_group_id" => array("item group id", false),
291
+ "color" => array("color", true),
292
+ "gender" => array("gender", true),
293
+ "age_group" => array("age group", true),
294
+ "material" => array("material", true),
295
+ "pattern" => array("pattern", true),
296
+ "size" => array("size", true),
297
+ "size_type" => array("size type", true),
298
+ "size_system" => array("size system", true),
299
+ "tax" => array("tax", true),
300
+ "tax_country" => array("tax country", true),
301
+ "tax_region" => array("tax region", true),
302
+ "tax_rate" => array("tax rate", true),
303
+ "tax_ship" => array("tax ship", true),
304
+ "tax_category" => array("tax category", true),
305
+ "weight" => array("shipping weight", false),
306
+ "length" => array("shipping length", false),
307
+ "width" => array("shipping width", false),
308
+ "height" => array("shipping height", false),
309
+ "shipping_label" => array("shipping label", false),
310
+ "shipping_country" => array("shipping country", false),
311
+ "shipping_service" => array("shipping service", false),
312
+ "shipping_price" => array("shipping price", false),
313
+ "shipping_region" => array("shipping region", false),
314
+ "multipack" => array("multipack", true),
315
+ "is_bundle" => array("is bundle", true),
316
+ "adult" => array("adult", true),
317
+ "adwords_redirect" => array("adwords redirect", true),
318
+ "custom_label_0" => array("custom label 0", true),
319
+ "custom_label_1" => array("custom label 1", true),
320
+ "custom_label_2" => array("custom label 2", true),
321
+ "custom_label_3" => array("custom label 3", true),
322
+ "custom_label_4" => array("custom label 4", true),
323
+ "excluded_destination" => array("excluded destination", true),
324
+ "included_destination" => array("included destination", true),
325
+ "expiration_date" => array("expiration date", true),
326
+ "unit_pricing_measure" => array("unit pricing measure", true),
327
+ "unit_pricing_base_measure" => array("unit pricing base measure", true),
328
+ "energy_efficiency_class" => array("energy efficiency class", true),
329
+ "loyalty_points" => array("loyalty points", true),
330
+ "installment" => array("installment", true),
331
+ "promotion_id" => array("promotion id", true),
332
+ "cost_of_goods_sold" => array("cost of goods sold", true),
333
+ );
334
+
335
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
336
+ foreach ($this->products as $no => $product) {
337
+ foreach ($product as $key => $value) {
338
+ $this->mapAttribute($no, $key, $googleCSVTXTAttribute[$key][0], $value, $googleCSVTXTAttribute[$key][0]);
339
+ }
340
+ $this->process_google_shipping_attribute_for_CSVTXT($no);
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Map to google attribute
347
+ * @param $no
348
+ * @param $from
349
+ * @param $to
350
+ * @param $value
351
+ * @param bool $cdata
352
+ * @return array
353
+ */
354
+ public function mapAttribute($no, $from, $to, $value, $cdata = false)
355
+ {
356
+ unset($this->products[$no][$from]);
357
+ if($to=='g:color'){
358
+ $value=str_replace(",","/",$value);
359
+ }
360
+ if ($this->rules['feedType'] == 'xml') {
361
+ return $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata);
362
+ } else {
363
+ return $this->products[$no][$to] = $value;
364
+ }
365
+ }
366
+
367
+ public function identifier_status_add($no)
368
+ {
369
+ $identifier = array('brand', 'upc', 'sku', 'mpn', 'gtin');
370
+ $product = $this->products[$no];
371
+
372
+ if(!array_key_exists('g:identifier_exists',$product)) {
373
+ if (count(array_intersect_key(array_flip($identifier), $product)) >= 2) {
374
+ # Any 2 required keys exist!
375
+ $countIdentifier=0;
376
+ if(array_key_exists('brand',$product) && !empty($product['brand'])){
377
+ $countIdentifier++;
378
+ }
379
+ if(array_key_exists('upc',$product) && !empty($product['upc'])){
380
+ $countIdentifier++;
381
+ }
382
+ if(array_key_exists('sku',$product) && !empty($product['sku'])){
383
+ $countIdentifier++;
384
+ }
385
+ if(array_key_exists('mpn',$product) && !empty($product['mpn'])){
386
+ $countIdentifier++;
387
+ }
388
+ if(array_key_exists('gtin',$product) && !empty($product['gtin'])){
389
+ $countIdentifier++;
390
+ }
391
+ if($countIdentifier>=2){
392
+ $this->products[$no]["g:identifier_exists"] = $this->formatXMLLine("g:identifier_exists", "yes", $cdata = true);
393
+ }else{
394
+ $this->products[$no]["g:identifier_exists"] = $this->formatXMLLine("g:identifier_exists", "no", $cdata = true);
395
+ }
396
+ } else {
397
+ $this->products[$no]["g:identifier_exists"] = $this->formatXMLLine("g:identifier_exists", "no", $cdata = true);
398
+ }
399
+ }
400
+ }
401
+
402
+
403
+ /**
404
+ * @param $no
405
+ * @return bool|string
406
+ */
407
+ public
408
+ function process_google_shipping_attribute_for_xml($no)
409
+ {
410
+ $shipping = array('g:shipping_country', 'g:shipping_service', 'g:shipping_price', 'g:shipping_region');
411
+ $shippingAttr = array();
412
+ $products = $this->products[$no];
413
+ foreach ($products as $keyAttr => $valueAttr) {
414
+ if (in_array($keyAttr, $shipping)) {
415
+ array_push($shippingAttr, array($keyAttr => $valueAttr));
416
+ unset($this->products[$no][$keyAttr]);
417
+ }
418
+ }
419
+ if (count($shippingAttr)) {
420
+ $str = "";
421
+ foreach ($shippingAttr as $key => $attributes) {
422
+ foreach ($attributes as $keyAttr => $valueAttr) {
423
+ $str .= str_replace("shipping_", "", $valueAttr);
424
+ }
425
+ }
426
+ return $this->products[$no]['g:shipping'] = $this->formatXMLLine("g:shipping", $str, false);
427
+ }
428
+ return false;
429
+ }
430
+
431
+ public
432
+ function process_google_tax_attribute_for_xml($no)
433
+ {
434
+ $tax = array('g:tax_country', 'g:tax_region', 'g:tax_rate', 'g:tax_ship');
435
+ $taxAttr = array();
436
+ $products = $this->products[$no];
437
+ foreach ($products as $keyAttr => $valueAttr) {
438
+ if (in_array($keyAttr, $tax)) {
439
+ array_push($taxAttr, array($keyAttr => $valueAttr));
440
+ unset($this->products[$no][$keyAttr]);
441
+ }
442
+ }
443
+ if (count($taxAttr)) {
444
+ $str = "";
445
+ foreach ($taxAttr as $key => $attributes) {
446
+ foreach ($attributes as $keyAttr => $valueAttr) {
447
+ // if($keyAttr != "g:tax_ship")
448
+ // {
449
+ $str .= str_replace("tax_", "", $valueAttr);
450
+ $str = str_replace("ship", "tax_ship", $str);
451
+ // }
452
+ // else
453
+ // {
454
+ // $str .= $valueAttr;
455
+ // }
456
+ }
457
+ }
458
+ return $this->products[$no]['g:tax'] = $this->formatXMLLine("g:tax", $str, false);
459
+ }
460
+ return false;
461
+ }
462
+
463
+ /**
464
+ * @param $no
465
+ * @return bool|mixed
466
+ */
467
+ public
468
+ function process_google_shipping_attribute_for_CSVTXT($no)
469
+ {
470
+ $shipping = array('shipping country', 'shipping service', 'shipping price', 'shipping region');
471
+ $shippingAttr = array();
472
+ $products = $this->products[$no];
473
+ foreach ($products as $keyAttr => $valueAttr) {
474
+ if (in_array($keyAttr, $shipping)) {
475
+ array_push($shippingAttr, array($keyAttr => $valueAttr));
476
+ unset($this->products[$no][$keyAttr]);
477
+ }
478
+ }
479
+ if (count($shippingAttr)) {
480
+ $str = "";
481
+ foreach ($shippingAttr as $key => $attributes) {
482
+ foreach ($attributes as $keyAttr => $valueAttr) {
483
+ $country = ($keyAttr == "shipping country") ? $str .= $valueAttr . ":" : "";
484
+ $service = ($keyAttr == "shipping service") ? $str .= $valueAttr . ":" : "";
485
+ $price = ($keyAttr == "shipping price") ? $str .= $valueAttr : "";
486
+ $region = ($keyAttr == "shipping region") ? $str .= $valueAttr . ":" : "";
487
+ }
488
+ }
489
+ return $this->products[$no]['shipping(country:region:service:price)'] = str_replace(" : ",":", $str);
490
+ }
491
+ return false;
492
+ }
493
+
494
+ public
495
+ function process_google_tax_attribute_for_CSVTXT($no)
496
+ {
497
+ $tax = array('tax country', 'tax region', 'tax rate', 'tax ship');
498
+ $taxAttr = array();
499
+ $products = $this->products[$no];
500
+ foreach ($products as $keyAttr => $valueAttr) {
501
+ if (in_array($keyAttr, $tax)) {
502
+ array_push($taxAttr, array($keyAttr => $valueAttr));
503
+ unset($this->products[$no][$keyAttr]);
504
+ }
505
+ }
506
+ if (count($taxAttr)) {
507
+ $str = "";
508
+ foreach ($taxAttr as $key => $attributes) {
509
+ foreach ($attributes as $keyAttr => $valueAttr) {
510
+ $country = ($keyAttr == "tax country") ? $str .= $valueAttr . ":" : "";
511
+ $region = ($keyAttr == "tax region") ? $str .= $valueAttr . ":" : "";
512
+ $rate = ($keyAttr == "tax rate") ? $str .= $valueAttr . ":": "";
513
+ $ship = ($keyAttr == "tax ship") ? $str .= $valueAttr . ":" : "";
514
+ }
515
+ }
516
+ return $this->products[$no]['tax(country:region:rate:tax_ship)'] = str_replace(" : ",":", $str);
517
+ }
518
+ return false;
519
+ }
520
+
521
+ function formatXMLLine($attribute, $value, $cdata, $space = "")
522
+ {
523
+ //Make single XML node
524
+ if (!empty($value))
525
+ $value = trim($value);
526
+ if (gettype($value) == 'array')
527
+ $value = json_encode($value);
528
+ if (strpos($value, "<![CDATA[") === false && substr(trim($value), 0, 4) == "http") {
529
+ $value = "<![CDATA[$value]]>";
530
+ } elseif (strpos($value, "<![CDATA[") === false && $cdata === true && !empty($value)) {
531
+ $value = "<![CDATA[$value]]>";
532
+ } else if ($cdata) {
533
+ if(!empty($value)){
534
+ $value = "<![CDATA[$value]]>";
535
+ }
536
+ }
537
+
538
+ if (substr($attribute, 0, 23) == 'g:additional_image_link') {
539
+ $attribute = "g:additional_image_link";
540
+ }
541
+
542
+ return "
543
+ $space<$attribute>$value</$attribute>";
544
+ }
545
+
546
+
547
+
548
+ public function get_xml_feed_header()
549
+ {
550
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
551
+ <rss version="2.0" xmlns:g="http://base.google.com/ns/1.0" xmlns:c="http://base.google.com/cns/1.0">
552
+ <channel>
553
+ <title><![CDATA[' . html_entity_decode(get_option('blogname')) . ']]></title>
554
+ <link><![CDATA['.home_url().']]></link>
555
+ <description><![CDATA['.html_entity_decode(get_option('blogdescription')).']]></description>';
556
+ return $output;
557
+ }
558
+
559
+ public function get_xml_feed($items)
560
+ {
561
+ $feed = "";
562
+ //$feed .= $this->get_feed_header();
563
+ $feed .= "\n";
564
+ if ($items) {
565
+ foreach ($items as $item => $products) {
566
+ $feed .= " <" . $this->feedWrapper . ">";
567
+
568
+ foreach ($products as $key => $value) {
569
+ if (!empty($value)){
570
+ $feed .= $value;
571
+ }
572
+ }
573
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
574
+ }
575
+ //$feed .= $this->get_feed_footer();
576
+
577
+ return $feed;
578
+ }
579
+ return false;
580
+ }
581
+
582
+ public function get_xml_feed_footer()
583
+ {
584
+ $footer = " </channel>
585
+ </rss>";
586
+ return $footer;
587
+ }
588
+
589
+ public function short_products()
590
+ {
591
+ if ($this->products) {
592
+ update_option('wpf_progress', "Shorting Products");
593
+ sleep(1);
594
+ $array = array();
595
+ $ij = 0;
596
+ foreach ($this->products as $key => $item) {
597
+ $array[$ij] = $item;
598
+ unset($this->products[$key]);
599
+ $ij++;
600
+ }
601
+ return $this->products = $array;
602
+ }
603
+ return $this->products;
604
+ }
605
+
606
+ /**
607
+ * Responsible to make CSV feed
608
+ * @return string
609
+ */
610
+ public function get_csv_feed()
611
+ {
612
+ if ($this->products) {
613
+ $headers = array_keys($this->products[0]);
614
+ $feed[] = $headers;
615
+ foreach ($this->products as $no => $product) {
616
+ $row = array();
617
+ foreach ($headers as $key => $header) {
618
+ if (strpos($header, "additional image link") !== false) {
619
+ $header = "additional image link";
620
+ }
621
+ $row[] = isset($product[$header]) ? $product[$header] : "";;
622
+ }
623
+ $feed[] = $row;
624
+ }
625
+ return $feed;
626
+ }
627
+ return false;
628
+ }
629
+
630
  }
includes/feeds/class-woo-feed-kelkoo.php CHANGED
@@ -1,438 +1,438 @@
1
- <?php
2
-
3
-
4
- class Kelkoo
5
- {
6
-
7
- public $products;
8
-
9
- public $rules;
10
-
11
- public $mapping;
12
-
13
- public $errorLog;
14
- public $errorCounter = 0;
15
-
16
- private $filteredProduct;
17
- private $feedWrapper = 'product';
18
-
19
- public function __construct($feedRule)
20
- {
21
- $this->rules = $feedRule;
22
- $this->mapProductsByRules();
23
- $this->formatRequiredField();
24
- $this->filterProductValues();
25
- if ($this->rules['feedType'] == 'xml') {
26
- $this->mapAttributeForXML();
27
- } else {
28
- $this->mapAttributeForCSVTEXT();
29
- }
30
- }
31
-
32
- public function mapAttributeForXML()
33
- {
34
- //Basic product information
35
-
36
- if ( is_countable( $this->products ) && count( $this->products ) ) {
37
- foreach ($this->products as $key => $values) {
38
- foreach ($values as $attr => $value) {
39
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
40
- }
41
- }
42
- }
43
- }
44
-
45
-
46
- public function mapAttributeForCSVTEXT()
47
- {
48
- //Basic product information
49
-
50
- if ( is_countable( $this->products ) && count( $this->products ) ) {
51
- foreach ($this->products as $key => $values) {
52
- foreach ($values as $attr => $value) {
53
- //Allow force strip HTML
54
-
55
- $value = strip_tags(html_entity_decode($value));
56
-
57
- $value = utf8_encode($value);
58
- $attr = utf8_encode($attr);
59
-
60
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
61
-
62
- if (gettype($value) == 'array')
63
- $value = json_encode($value);
64
-
65
- $this->products[$key][$attr] = $value;
66
- }
67
- }
68
- }
69
- }
70
-
71
- public function formatRequiredField()
72
- {
73
- foreach ($this->products as $no => $product) {
74
- $upn = 0;
75
- if (array_key_exists('title', $product)) {
76
- $id = $product['title'];
77
- } else {
78
- $id = "";
79
- }
80
-
81
- if (!array_key_exists('title', $product)) {
82
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>title</b>] Missing for <b>$id</b>.";
83
- $this->errorCounter++;
84
- }
85
-
86
-
87
- if (!array_key_exists('product-url', $product)) {
88
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>product-url</b>] Missing for <b>$id</b>.";
89
- $this->errorCounter++;
90
- }
91
-
92
- if (!array_key_exists('price', $product)) {
93
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>price</b>] Missing for <b>$id</b>.";
94
- $this->errorCounter++;
95
- }
96
-
97
- if (!array_key_exists('merchant-category', $product)) {
98
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>merchant-category</b>] Missing for <b>$id</b>.";
99
- $this->errorCounter++;
100
- }
101
- }
102
- }
103
-
104
- public function returnFinalProduct()
105
- {
106
- if ($this->rules['feedType'] == 'xml') {
107
- return $this->get_feed($this->products);
108
- } elseif ($this->rules['feedType'] == 'txt') {
109
- return $this->get_txt_feed();
110
- } elseif ($this->rules['feedType'] == 'csv') {
111
- return $this->get_csv_feed();
112
- }
113
- return false;
114
- }
115
-
116
- public function filterProductValues()
117
- {
118
- $getProduct = new Woo_Feed_Products();
119
- $products = $this->products;
120
-
121
- foreach ($products as $no => $product) {
122
- if (array_key_exists('title', $product)) {
123
- $id = $product['title'];
124
- } else {
125
- $id = "";
126
- }
127
-
128
- foreach ($product as $key => $value) {
129
-
130
- switch ($key) {
131
- case "title":
132
- if (strlen($value) > 80) {
133
- $this->errorLog[$this->errorCounter] = "[<b>title</b>] is more that 80 character for $id.";
134
- $this->errorCounter++;
135
- }
136
- break;
137
- case "product-url":
138
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
139
- $this->errorLog[$this->errorCounter] = "[<b>product-url</b>] must start with http:// or https:// for $id.";
140
- $this->errorCounter++;
141
- }
142
- break;
143
- case "description":
144
- if (strlen($value) > 300) {
145
- $this->errorLog[$this->errorCounter] = "[<b>description</b>] is more that 300 character for $id.";
146
- $this->errorCounter++;
147
- }
148
- break;
149
- case "image-url":
150
- if (strpos($value, 'http://') == false) {
151
- $this->errorLog[$this->errorCounter] = "[<b>image-url</b>] must start with http:// for $id.";
152
- $this->errorCounter++;
153
- }
154
-
155
- list($width, $height) = getimagesize($value);
156
- if (($width * $height) < 1920000) {
157
- $this->errorLog[$this->errorCounter] = "<b>Image Pixel</b> should be less than 1920000px for $id.";
158
- $this->errorCounter++;
159
- }
160
-
161
- break;
162
- case "condition":
163
- if ($value == 'new') {
164
- $this->products[$no][$key] = "0";
165
- } else if ($value == 'used') {
166
- $this->products[$no][$key] = "1";
167
- } else if ($value == 'refurbished') {
168
- $this->products[$no][$key] = "2";
169
- } else if ($value == 'open box') {
170
- $this->products[$no][$key] = "3";
171
- } else if ($value == 'returned') {
172
- $this->products[$no][$key] = "4";
173
- } else if ($value == 'damaged') {
174
- $this->products[$no][$key] = "5";
175
- } else if ($value == 'overstock') {
176
- $this->products[$no][$key] = "6";
177
- } else if ($value == 'liquidation') {
178
- $this->products[$no][$key] = "7";
179
- } else if ($value == 'unknown') {
180
- $this->products[$no][$key] = "8";
181
- } else if ($value == 'download') {
182
- $this->products[$no][$key] = "9";
183
- } else if ($value == 'offers for professional') {
184
- $this->products[$no][$key] = "10";
185
- }
186
- break;
187
- case "availability":
188
- $conditions = array('In Stock', 'Yes', 'Any Number', 'Out of Stock');
189
- if ($value == 'In Stock') {
190
- $this->products[$no][$key] = "1";
191
- } else if ($value == 'in stock') {
192
- $this->products[$no][$key] = "1";
193
- } else if ($value == 'Stock On Order') {
194
- $this->products[$no][$key] = "2";
195
- } else if ($value == 'Unknown, check site') {
196
- $this->products[$no][$key] = "3";
197
- } else if ($value == 'Preorder') {
198
- $this->products[$no][$key] = "4";
199
- } else if ($value == 'Available on Order') {
200
- $this->products[$no][$key] = "5";
201
- } else if ($value == 'Out of Stock') {
202
- $this->products[$no][$key] = "6";
203
- } else if ($value == 'out of stock') {
204
- $this->products[$no][$key] = "6";
205
- }
206
- break;
207
- default:
208
- break;
209
- }
210
- }
211
- }
212
- }
213
-
214
- public function get_category_mapping_value($mappingName, $parent)
215
- {
216
- $getValue = unserialize(get_option($mappingName));
217
- $mapp = array_reverse($getValue['cmapping'], true);
218
- $categories = get_the_terms($parent, 'product_cat');
219
-
220
- foreach ($categories as $key => $category) {
221
- if (!empty($mapp[$category->term_id]))
222
- return $mapp[$category->term_id];
223
- }
224
- }
225
-
226
-
227
- public function mapProductsByRules()
228
- {
229
- $products = new Woo_Feed_Products(); //$this->woo_feed_get_visible_product();
230
- $attributes = $this->rules['attributes'];
231
- $prefix = $this->rules['prefix'];
232
- $suffix = $this->rules['suffix'];
233
- $outputType = $this->rules['output_type'];
234
- $limit = $this->rules['limit'];
235
- $merchantAttributes = $this->rules['mattributes'];
236
- $type = $this->rules['type'];
237
- $default = $this->rules['default'];
238
- $feedType = $this->rules['feedType'];
239
-
240
- // Map Merchant Attributes and Woo Attributes
241
- if (count($merchantAttributes)) {
242
- foreach ($merchantAttributes as $key => $attr) {
243
- if (!empty($attr) && !empty($attributes[$key])) {
244
- if ($type[$key] == 'attribute') {
245
- $this->mapping[$attr]['value'] = $attributes[$key];
246
- $this->mapping[$attr]['suffix'] = $suffix[$key];
247
- $this->mapping[$attr]['prefix'] = $prefix[$key];
248
- $this->mapping[$attr]['type'] = $outputType[$key];
249
- $this->mapping[$attr]['limit'] = $limit[$key];
250
- }
251
- } else if (empty($attributes[$key])) {
252
- if ($type[$key] == 'pattern') {
253
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
254
- $this->mapping[$attr]['suffix'] = $suffix[$key];
255
- $this->mapping[$attr]['prefix'] = $prefix[$key];
256
- $this->mapping[$attr]['type'] = $outputType[$key];
257
- $this->mapping[$attr]['limit'] = $limit[$key];
258
- }
259
- }
260
- }
261
- }
262
-
263
- // Make Product feed array according to mapping
264
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
265
- $i = 0;
266
- foreach ($this->mapping as $attr => $rules) {
267
- if (array_key_exists($rules['value'], $value)) {
268
-
269
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
270
- // Format According to output type
271
- if ($rules['type'] == 2) {
272
- $output = strip_tags($output);
273
- } elseif ($rules['type'] == 3) {
274
- $output = absint($output);
275
- }
276
- // Format According to output limit
277
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
278
- $output = substr($output, 0, $rules['limit']);
279
- }
280
- $attr = trim($attr);
281
- $this->products[$key][$attr] = trim($output);
282
- } else {
283
- if (!empty($default[$i])) {
284
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
285
- if ($rules['type'] == 2) {
286
- $output = strip_tags($output);
287
- } elseif ($rules['type'] == 3) {
288
- $output = absint($output);
289
- }
290
- // Format According to output limit
291
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
292
- $output = substr($output, 0, $rules['limit']);
293
- }
294
- $attr = trim($attr);
295
- $this->products[$key][$attr] = trim($output);
296
- }
297
- }
298
- $i++;
299
- }
300
- }
301
-
302
-
303
- return $this->products;
304
- }
305
-
306
- public function mapAttribute($from, $to, $cdata = false)
307
- {
308
- $i = 0;
309
- foreach ($this->products as $no => $product) {
310
- foreach ($product as $key => $value) {
311
- if ($key == $from) {
312
- unset($this->products[$no][$from]);
313
- if ($from == 'images') {
314
- $this->products[$no][$to] = $value;
315
- } else {
316
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
317
- }
318
-
319
- }
320
- }
321
- $i++;
322
- }
323
- }
324
-
325
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
326
- {
327
- //Make single line for XML
328
- $c_leader = '';
329
- $c_footer = '';
330
- if ($cdata) {
331
- $c_leader = '<![CDATA[';
332
- $c_footer = ']]>';
333
- }
334
- //Allow force strip HTML
335
- if ($stripHTML)
336
- $value = strip_tags(html_entity_decode($value));
337
-
338
-
339
- if ($utf8encode || $utf8encode == 1) {
340
- $value = utf8_encode($value);
341
- $attribute = utf8_encode($attribute);
342
- }
343
-
344
-
345
- if (!$cdata)
346
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
347
-
348
- if (gettype($value) == 'array')
349
- $value = json_encode($value);
350
-
351
-
352
- return '
353
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
354
- }
355
-
356
- function change_key($array, $old_key, $new_key)
357
- {
358
- foreach ($this->products as $no => $product) {
359
- if (!array_key_exists($old_key, $product))
360
- return $array;
361
-
362
- $keys = array_keys($array);
363
- $keys[array_search($old_key, $keys)] = $new_key;
364
- }
365
- return array_combine($keys, $array);
366
- }
367
-
368
- public function get_feed_header()
369
- {
370
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
371
- <products>';
372
- $output .= "\n";
373
- return $output;
374
- }
375
-
376
- public function get_feed($items)
377
- {
378
- $feed = "";
379
- $feed .= $this->get_feed_header();
380
- $feed .= "\n";
381
- foreach ($items as $item => $products) {
382
- $feed .= " <" . $this->feedWrapper . ">";
383
- foreach ($products as $key => $value) {
384
- if (!empty($value))
385
- $feed .= $value;
386
- }
387
- $feed .= "\n </" . $this->feedWrapper . ">\n";
388
- }
389
- $feed .= $this->get_feed_footer();
390
-
391
- return $feed;
392
- }
393
-
394
- public function get_feed_footer()
395
- {
396
- $footer = " </products>";
397
- return $footer;
398
- }
399
-
400
- public function get_txt_feed()
401
- {
402
- if ( is_countable( $this->products ) && count( $this->products ) ) {
403
- $headers = array_keys($this->products[0]);
404
- $feed[] = $headers;
405
- foreach ($this->products as $no => $product) {
406
- $row = array();
407
- foreach ($headers as $key => $header) {
408
- $row[] = $product[$header];
409
- }
410
- $feed[] = $row;
411
- }
412
- $str = "";
413
- foreach ($feed as $fields) {
414
- $str .= implode("\t", $fields) . "\n";
415
- }
416
- return $str;
417
- }
418
- return false;
419
- }
420
-
421
- public function get_csv_feed()
422
- {
423
- if ( is_countable( $this->products ) && count( $this->products ) ) {
424
- $headers = array_keys($this->products[0]);
425
- $feed[] = $headers;
426
- foreach ($this->products as $no => $product) {
427
- $row = array();
428
- foreach ($headers as $key => $header) {
429
- $row[] = $product[$header];
430
- }
431
- $feed[] = $row;
432
- }
433
-
434
- return $feed;
435
- }
436
- return false;
437
- }
438
  }
1
+ <?php
2
+
3
+
4
+ class Kelkoo
5
+ {
6
+
7
+ public $products;
8
+
9
+ public $rules;
10
+
11
+ public $mapping;
12
+
13
+ public $errorLog;
14
+ public $errorCounter = 0;
15
+
16
+ private $filteredProduct;
17
+ private $feedWrapper = 'product';
18
+
19
+ public function __construct($feedRule)
20
+ {
21
+ $this->rules = $feedRule;
22
+ $this->mapProductsByRules();
23
+ $this->formatRequiredField();
24
+ $this->filterProductValues();
25
+ if ($this->rules['feedType'] == 'xml') {
26
+ $this->mapAttributeForXML();
27
+ } else {
28
+ $this->mapAttributeForCSVTEXT();
29
+ }
30
+ }
31
+
32
+ public function mapAttributeForXML()
33
+ {
34
+ //Basic product information
35
+
36
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
37
+ foreach ($this->products as $key => $values) {
38
+ foreach ($values as $attr => $value) {
39
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+
46
+ public function mapAttributeForCSVTEXT()
47
+ {
48
+ //Basic product information
49
+
50
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
51
+ foreach ($this->products as $key => $values) {
52
+ foreach ($values as $attr => $value) {
53
+ //Allow force strip HTML
54
+
55
+ $value = strip_tags(html_entity_decode($value));
56
+
57
+ $value = utf8_encode($value);
58
+ $attr = utf8_encode($attr);
59
+
60
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
61
+
62
+ if (gettype($value) == 'array')
63
+ $value = json_encode($value);
64
+
65
+ $this->products[$key][$attr] = $value;
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ public function formatRequiredField()
72
+ {
73
+ foreach ($this->products as $no => $product) {
74
+ $upn = 0;
75
+ if (array_key_exists('title', $product)) {
76
+ $id = $product['title'];
77
+ } else {
78
+ $id = "";
79
+ }
80
+
81
+ if (!array_key_exists('title', $product)) {
82
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>title</b>] Missing for <b>$id</b>.";
83
+ $this->errorCounter++;
84
+ }
85
+
86
+
87
+ if (!array_key_exists('product-url', $product)) {
88
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>product-url</b>] Missing for <b>$id</b>.";
89
+ $this->errorCounter++;
90
+ }
91
+
92
+ if (!array_key_exists('price', $product)) {
93
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>price</b>] Missing for <b>$id</b>.";
94
+ $this->errorCounter++;
95
+ }
96
+
97
+ if (!array_key_exists('merchant-category', $product)) {
98
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>merchant-category</b>] Missing for <b>$id</b>.";
99
+ $this->errorCounter++;
100
+ }
101
+ }
102
+ }
103
+
104
+ public function returnFinalProduct()
105
+ {
106
+ if ($this->rules['feedType'] == 'xml') {
107
+ return $this->get_feed($this->products);
108
+ } elseif ($this->rules['feedType'] == 'txt') {
109
+ return $this->get_txt_feed();
110
+ } elseif ($this->rules['feedType'] == 'csv') {
111
+ return $this->get_csv_feed();
112
+ }
113
+ return false;
114
+ }
115
+
116
+ public function filterProductValues()
117
+ {
118
+ $getProduct = new Woo_Feed_Products();
119
+ $products = $this->products;
120
+
121
+ foreach ($products as $no => $product) {
122
+ if (array_key_exists('title', $product)) {
123
+ $id = $product['title'];
124
+ } else {
125
+ $id = "";
126
+ }
127
+
128
+ foreach ($product as $key => $value) {
129
+
130
+ switch ($key) {
131
+ case "title":
132
+ if (strlen($value) > 80) {
133
+ $this->errorLog[$this->errorCounter] = "[<b>title</b>] is more that 80 character for $id.";
134
+ $this->errorCounter++;
135
+ }
136
+ break;
137
+ case "product-url":
138
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
139
+ $this->errorLog[$this->errorCounter] = "[<b>product-url</b>] must start with http:// or https:// for $id.";
140
+ $this->errorCounter++;
141
+ }
142
+ break;
143
+ case "description":
144
+ if (strlen($value) > 300) {
145
+ $this->errorLog[$this->errorCounter] = "[<b>description</b>] is more that 300 character for $id.";
146
+ $this->errorCounter++;
147
+ }
148
+ break;
149
+ case "image-url":
150
+ if (strpos($value, 'http://') == false) {
151
+ $this->errorLog[$this->errorCounter] = "[<b>image-url</b>] must start with http:// for $id.";
152
+ $this->errorCounter++;
153
+ }
154
+
155
+ list($width, $height) = getimagesize($value);
156
+ if (($width * $height) < 1920000) {
157
+ $this->errorLog[$this->errorCounter] = "<b>Image Pixel</b> should be less than 1920000px for $id.";
158
+ $this->errorCounter++;
159
+ }
160
+
161
+ break;
162
+ case "condition":
163
+ if ($value == 'new') {
164
+ $this->products[$no][$key] = "0";
165
+ } else if ($value == 'used') {
166
+ $this->products[$no][$key] = "1";
167
+ } else if ($value == 'refurbished') {
168
+ $this->products[$no][$key] = "2";
169
+ } else if ($value == 'open box') {
170
+ $this->products[$no][$key] = "3";
171
+ } else if ($value == 'returned') {
172
+ $this->products[$no][$key] = "4";
173
+ } else if ($value == 'damaged') {
174
+ $this->products[$no][$key] = "5";
175
+ } else if ($value == 'overstock') {
176
+ $this->products[$no][$key] = "6";
177
+ } else if ($value == 'liquidation') {
178
+ $this->products[$no][$key] = "7";
179
+ } else if ($value == 'unknown') {
180
+ $this->products[$no][$key] = "8";
181
+ } else if ($value == 'download') {
182
+ $this->products[$no][$key] = "9";
183
+ } else if ($value == 'offers for professional') {
184
+ $this->products[$no][$key] = "10";
185
+ }
186
+ break;
187
+ case "availability":
188
+ $conditions = array('In Stock', 'Yes', 'Any Number', 'Out of Stock');
189
+ if ($value == 'In Stock') {
190
+ $this->products[$no][$key] = "1";
191
+ } else if ($value == 'in stock') {
192
+ $this->products[$no][$key] = "1";
193
+ } else if ($value == 'Stock On Order') {
194
+ $this->products[$no][$key] = "2";
195
+ } else if ($value == 'Unknown, check site') {
196
+ $this->products[$no][$key] = "3";
197
+ } else if ($value == 'Preorder') {
198
+ $this->products[$no][$key] = "4";
199
+ } else if ($value == 'Available on Order') {
200
+ $this->products[$no][$key] = "5";
201
+ } else if ($value == 'Out of Stock') {
202
+ $this->products[$no][$key] = "6";
203
+ } else if ($value == 'out of stock') {
204
+ $this->products[$no][$key] = "6";
205
+ }
206
+ break;
207
+ default:
208
+ break;
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ public function get_category_mapping_value($mappingName, $parent)
215
+ {
216
+ $getValue = unserialize(get_option($mappingName));
217
+ $mapp = array_reverse($getValue['cmapping'], true);
218
+ $categories = get_the_terms($parent, 'product_cat');
219
+
220
+ foreach ($categories as $key => $category) {
221
+ if (!empty($mapp[$category->term_id]))
222
+ return $mapp[$category->term_id];
223
+ }
224
+ }
225
+
226
+
227
+ public function mapProductsByRules()
228
+ {
229
+ $products = new Woo_Feed_Products(); //$this->woo_feed_get_visible_product();
230
+ $attributes = $this->rules['attributes'];
231
+ $prefix = $this->rules['prefix'];
232
+ $suffix = $this->rules['suffix'];
233
+ $outputType = $this->rules['output_type'];
234
+ $limit = $this->rules['limit'];
235
+ $merchantAttributes = $this->rules['mattributes'];
236
+ $type = $this->rules['type'];
237
+ $default = $this->rules['default'];
238
+ $feedType = $this->rules['feedType'];
239
+
240
+ // Map Merchant Attributes and Woo Attributes
241
+ if (count($merchantAttributes)) {
242
+ foreach ($merchantAttributes as $key => $attr) {
243
+ if (!empty($attr) && !empty($attributes[$key])) {
244
+ if ($type[$key] == 'attribute') {
245
+ $this->mapping[$attr]['value'] = $attributes[$key];
246
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
247
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
248
+ $this->mapping[$attr]['type'] = $outputType[$key];
249
+ $this->mapping[$attr]['limit'] = $limit[$key];
250
+ }
251
+ } else if (empty($attributes[$key])) {
252
+ if ($type[$key] == 'pattern') {
253
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
254
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
255
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
256
+ $this->mapping[$attr]['type'] = $outputType[$key];
257
+ $this->mapping[$attr]['limit'] = $limit[$key];
258
+ }
259
+ }
260
+ }
261
+ }
262
+
263
+ // Make Product feed array according to mapping
264
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
265
+ $i = 0;
266
+ foreach ($this->mapping as $attr => $rules) {
267
+ if (array_key_exists($rules['value'], $value)) {
268
+
269
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
270
+ // Format According to output type
271
+ if ($rules['type'] == 2) {
272
+ $output = strip_tags($output);
273
+ } elseif ($rules['type'] == 3) {
274
+ $output = absint($output);
275
+ }
276
+ // Format According to output limit
277
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
278
+ $output = substr($output, 0, $rules['limit']);
279
+ }
280
+ $attr = trim($attr);
281
+ $this->products[$key][$attr] = trim($output);
282
+ } else {
283
+ if (!empty($default[$i])) {
284
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
285
+ if ($rules['type'] == 2) {
286
+ $output = strip_tags($output);
287
+ } elseif ($rules['type'] == 3) {
288
+ $output = absint($output);
289
+ }
290
+ // Format According to output limit
291
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
292
+ $output = substr($output, 0, $rules['limit']);
293
+ }
294
+ $attr = trim($attr);
295
+ $this->products[$key][$attr] = trim($output);
296
+ }
297
+ }
298
+ $i++;
299
+ }
300
+ }
301
+
302
+
303
+ return $this->products;
304
+ }
305
+
306
+ public function mapAttribute($from, $to, $cdata = false)
307
+ {
308
+ $i = 0;
309
+ foreach ($this->products as $no => $product) {
310
+ foreach ($product as $key => $value) {
311
+ if ($key == $from) {
312
+ unset($this->products[$no][$from]);
313
+ if ($from == 'images') {
314
+ $this->products[$no][$to] = $value;
315
+ } else {
316
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
317
+ }
318
+
319
+ }
320
+ }
321
+ $i++;
322
+ }
323
+ }
324
+
325
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
326
+ {
327
+ //Make single line for XML
328
+ $c_leader = '';
329
+ $c_footer = '';
330
+ if ($cdata) {
331
+ $c_leader = '<![CDATA[';
332
+ $c_footer = ']]>';
333
+ }
334
+ //Allow force strip HTML
335
+ if ($stripHTML)
336
+ $value = strip_tags(html_entity_decode($value));
337
+
338
+
339
+ if ($utf8encode || $utf8encode == 1) {
340
+ $value = utf8_encode($value);
341
+ $attribute = utf8_encode($attribute);
342
+ }
343
+
344
+
345
+ if (!$cdata)
346
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
347
+
348
+ if (gettype($value) == 'array')
349
+ $value = json_encode($value);
350
+
351
+
352
+ return '
353
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
354
+ }
355
+
356
+ function change_key($array, $old_key, $new_key)
357
+ {
358
+ foreach ($this->products as $no => $product) {
359
+ if (!array_key_exists($old_key, $product))
360
+ return $array;
361
+
362
+ $keys = array_keys($array);
363
+ $keys[array_search($old_key, $keys)] = $new_key;
364
+ }
365
+ return array_combine($keys, $array);
366
+ }
367
+
368
+ public function get_feed_header()
369
+ {
370
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
371
+ <products>';
372
+ $output .= "\n";
373
+ return $output;
374
+ }
375
+
376
+ public function get_feed($items)
377
+ {
378
+ $feed = "";
379
+ $feed .= $this->get_feed_header();
380
+ $feed .= "\n";
381
+ foreach ($items as $item => $products) {
382
+ $feed .= " <" . $this->feedWrapper . ">";
383
+ foreach ($products as $key => $value) {
384
+ if (!empty($value))
385
+ $feed .= $value;
386
+ }
387
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
388
+ }
389
+ $feed .= $this->get_feed_footer();
390
+
391
+ return $feed;
392
+ }
393
+
394
+ public function get_feed_footer()
395
+ {
396
+ $footer = " </products>";
397
+ return $footer;
398
+ }
399
+
400
+ public function get_txt_feed()
401
+ {
402
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
403
+ $headers = array_keys($this->products[0]);
404
+ $feed[] = $headers;
405
+ foreach ($this->products as $no => $product) {
406
+ $row = array();
407
+ foreach ($headers as $key => $header) {
408
+ $row[] = $product[$header];
409
+ }
410
+ $feed[] = $row;
411
+ }
412
+ $str = "";
413
+ foreach ($feed as $fields) {
414
+ $str .= implode("\t", $fields) . "\n";
415
+ }
416
+ return $str;
417
+ }
418
+ return false;
419
+ }
420
+
421
+ public function get_csv_feed()
422
+ {
423
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
424
+ $headers = array_keys($this->products[0]);
425
+ $feed[] = $headers;
426
+ foreach ($this->products as $no => $product) {
427
+ $row = array();
428
+ foreach ($headers as $key => $header) {
429
+ $row[] = $product[$header];
430
+ }
431
+ $feed[] = $row;
432
+ }
433
+
434
+ return $feed;
435
+ }
436
+ return false;
437
+ }
438
  }
includes/feeds/class-woo-feed-nextag.php CHANGED
@@ -1,114 +1,114 @@
1
- <?php
2
-
3
-
4
- class Nextag
5
- {
6
-
7
- /**
8
- * This variable is responsible for holding all product attributes and their values
9
- *
10
- * @since 1.0.0
11
- * @var array $products Contains all the product attributes to generate feed
12
- * @access public
13
- */
14
- public $products;
15
-
16
- /**
17
- * This variable is responsible for holding feed configuration form values
18
- *
19
- * @since 1.0.0
20
- * @var Custom $rules Contains feed configuration form values
21
- * @access public
22
- */
23
- public $rules;
24
-
25
-
26
- /**
27
- * Store product information
28
- *
29
- * @since 1.0.0
30
- * @var array $storeProducts
31
- * @access public
32
- */
33
- private $storeProducts;
34
-
35
- /**
36
- * Define the core functionality to generate feed.
37
- *
38
- * Set the feed rules. Map products according to the rules and Check required attributes
39
- * and their values according to merchant specification.
40
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
41
- * @since 1.0.0
42
- */
43
- public function __construct($feedRule)
44
- {
45
- $products = new Woo_Feed_Products();
46
- $storeProducts = $products->woo_feed_get_visible_product();
47
- $engine = new WF_Engine($storeProducts, $feedRule);
48
- $this->products = $engine->mapProductsByRules();
49
- $this->rules = $feedRule;
50
- if ($feedRule['feedType'] == 'xml') {
51
- $this->mapAttributeForXML();
52
- }
53
- }
54
-
55
- /**
56
- * Return Feed
57
- *
58
- * @return array|bool|string
59
- */
60
- public function returnFinalProduct()
61
- {
62
- $engine = new WF_Engine($this->products, $this->rules);
63
- if ($this->rules['feedType'] == 'xml') {
64
- return $engine->get_feed($this->products);
65
- } elseif ($this->rules['feedType'] == 'txt') {
66
- return $engine->get_txt_feed();
67
- } elseif ($this->rules['feedType'] == 'csv') {
68
- return $engine->get_csv_feed();
69
- }
70
- return false;
71
- }
72
-
73
- public function mapAttributeForXML()
74
- {
75
- //Basic product information
76
- if ( is_countable( $this->products ) && count( $this->products ) ) {
77
- foreach ($this->products as $key => $values) {
78
- foreach ($values as $attr => $value) {
79
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
80
- }
81
- }
82
- }
83
- }
84
-
85
- public function mapAttribute($from, $to, $cdata = false)
86
- {
87
- $i = 0;
88
- foreach ($this->products as $no => $product) {
89
- foreach ($product as $key => $value) {
90
- if ($key == $from) {
91
- unset($this->products[$no][$from]);
92
- if ($from == 'images') {
93
- $this->products[$no][$to] = $value;
94
- } else {
95
- $this->products[$no][$to] = $this->formatXMLLine($to, $value);
96
- }
97
- }
98
- }
99
- $i++;
100
- }
101
- }
102
-
103
- function formatXMLLine($attribute, $value, $space = ' ')
104
- {
105
-
106
- if (gettype($value) == 'array')
107
- $value = json_encode($value);
108
-
109
-
110
- return '
111
- ' . $space . '<' . $attribute . '>' . $value . '</' . $attribute . '>';
112
- }
113
-
114
  }
1
+ <?php
2
+
3
+
4
+ class Nextag
5
+ {
6
+
7
+ /**
8
+ * This variable is responsible for holding all product attributes and their values
9
+ *
10
+ * @since 1.0.0
11
+ * @var array $products Contains all the product attributes to generate feed
12
+ * @access public
13
+ */
14
+ public $products;
15
+
16
+ /**
17
+ * This variable is responsible for holding feed configuration form values
18
+ *
19
+ * @since 1.0.0
20
+ * @var Custom $rules Contains feed configuration form values
21
+ * @access public
22
+ */
23
+ public $rules;
24
+
25
+
26
+ /**
27
+ * Store product information
28
+ *
29
+ * @since 1.0.0
30
+ * @var array $storeProducts
31
+ * @access public
32
+ */
33
+ private $storeProducts;
34
+
35
+ /**
36
+ * Define the core functionality to generate feed.
37
+ *
38
+ * Set the feed rules. Map products according to the rules and Check required attributes
39
+ * and their values according to merchant specification.
40
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
41
+ * @since 1.0.0
42
+ */
43
+ public function __construct($feedRule)
44
+ {
45
+ $products = new Woo_Feed_Products();
46
+ $storeProducts = $products->woo_feed_get_visible_product();
47
+ $engine = new WF_Engine($storeProducts, $feedRule);
48
+ $this->products = $engine->mapProductsByRules();
49
+ $this->rules = $feedRule;
50
+ if ($feedRule['feedType'] == 'xml') {
51
+ $this->mapAttributeForXML();
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Return Feed
57
+ *
58
+ * @return array|bool|string
59
+ */
60
+ public function returnFinalProduct()
61
+ {
62
+ $engine = new WF_Engine($this->products, $this->rules);
63
+ if ($this->rules['feedType'] == 'xml') {
64
+ return $engine->get_feed($this->products);
65
+ } elseif ($this->rules['feedType'] == 'txt') {
66
+ return $engine->get_txt_feed();
67
+ } elseif ($this->rules['feedType'] == 'csv') {
68
+ return $engine->get_csv_feed();
69
+ }
70
+ return false;
71
+ }
72
+
73
+ public function mapAttributeForXML()
74
+ {
75
+ //Basic product information
76
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
77
+ foreach ($this->products as $key => $values) {
78
+ foreach ($values as $attr => $value) {
79
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ public function mapAttribute($from, $to, $cdata = false)
86
+ {
87
+ $i = 0;
88
+ foreach ($this->products as $no => $product) {
89
+ foreach ($product as $key => $value) {
90
+ if ($key == $from) {
91
+ unset($this->products[$no][$from]);
92
+ if ($from == 'images') {
93
+ $this->products[$no][$to] = $value;
94
+ } else {
95
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value);
96
+ }
97
+ }
98
+ }
99
+ $i++;
100
+ }
101
+ }
102
+
103
+ function formatXMLLine($attribute, $value, $space = ' ')
104
+ {
105
+
106
+ if (gettype($value) == 'array')
107
+ $value = json_encode($value);
108
+
109
+
110
+ return '
111
+ ' . $space . '<' . $attribute . '>' . $value . '</' . $attribute . '>';
112
+ }
113
+
114
  }
includes/feeds/class-woo-feed-pricegrabber.php CHANGED
@@ -1,480 +1,480 @@
1
- <?php
2
-
3
-
4
- class Pricegrabber
5
- {
6
-
7
- public $products;
8
-
9
- public $rules;
10
-
11
- public $mapping;
12
-
13
- public $errorLog;
14
- public $errorCounter = 0;
15
-
16
- private $filteredProduct;
17
- private $feedWrapper = 'item';
18
-
19
- public function __construct($feedRule)
20
- {
21
- $this->rules = $feedRule;
22
- $this->mapProductsByRules();
23
- $this->formatRequiredField();
24
- $this->filterProductValues();
25
- if ($this->rules['feedType'] == 'xml') {
26
- $this->mapAttributeForXML();
27
- } else {
28
- $this->mapAttributeForCSVTEXT();
29
- }
30
- }
31
-
32
- public function mapAttributeForXML()
33
- {
34
- //Basic product information
35
-
36
- if ( is_countable( $this->products ) && count( $this->products ) ) {
37
- foreach ($this->products as $key => $values) {
38
- foreach ($values as $attr => $value) {
39
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
40
- }
41
- }
42
- }
43
- }
44
-
45
-
46
- public function mapAttributeForCSVTEXT()
47
- {
48
- //Basic product information
49
-
50
- if ( is_countable( $this->products ) && count( $this->products ) ) {
51
- foreach ($this->products as $key => $values) {
52
- foreach ($values as $attr => $value) {
53
- //Allow force strip HTML
54
-
55
- $value = strip_tags(html_entity_decode($value));
56
-
57
- $value = utf8_encode($value);
58
- $attr = utf8_encode($attr);
59
-
60
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
61
-
62
- if (gettype($value) == 'array')
63
- $value = json_encode($value);
64
-
65
- $this->products[$key][$attr] = $value;
66
- }
67
- }
68
- }
69
- }
70
-
71
- public function formatRequiredField()
72
- {
73
- foreach ($this->products as $no => $product) {
74
- $upn = 0;
75
- if (array_key_exists('title', $product)) {
76
- $id = $product['title'];
77
- } else {
78
- $id = $product['id'];
79
- }
80
- foreach ($product as $key => $value) {
81
- if ($key == 'mpn' || $key == 'gtin') {
82
- $upn++;
83
- }
84
- }
85
-
86
- if (!array_key_exists('title', $product)) {
87
- $this->errorLog[$this->errorCounter] = "Product Title Missing for <b>$id</b>.";
88
- $this->errorCounter++;
89
- }
90
-
91
- if (!array_key_exists('id', $product)) {
92
- $this->errorLog[$this->errorCounter] = "Product Id Missing for <b>$id</b>.";
93
- $this->errorCounter++;
94
- }
95
-
96
- if (!array_key_exists('brand', $product)) {
97
- $this->errorLog[$this->errorCounter] = "Product Brand Missing for <b>$id</b>.";
98
- $this->errorCounter++;
99
- }
100
-
101
- if (!array_key_exists('description', $product)) {
102
- $this->errorLog[$this->errorCounter] = "Product Description Missing for <b>$id</b>.";
103
- $this->errorCounter++;
104
- }
105
-
106
- if (!array_key_exists('link', $product)) {
107
- $this->errorLog[$this->errorCounter] = "Product Link Missing for <b>$id</b>.";
108
- $this->errorCounter++;
109
- }
110
-
111
- if (!array_key_exists('image', $product)) {
112
- $this->errorLog[$this->errorCounter] = "Product Image Link Missing for <b>$id</b>.";
113
- $this->errorCounter++;
114
- }
115
-
116
- if (!array_key_exists('condition', $product)) {
117
- $this->errorLog[$this->errorCounter] = "Product Condition Missing for <b>$id</b>.";
118
- $this->errorCounter++;
119
- }
120
-
121
- }
122
- }
123
-
124
- public function returnFinalProduct()
125
- {
126
- if ($this->rules['feedType'] == 'xml') {
127
- return $this->get_feed($this->products);
128
- } elseif ($this->rules['feedType'] == 'txt') {
129
- return $this->get_txt_feed();
130
- } elseif ($this->rules['feedType'] == 'csv') {
131
- return $this->get_csv_feed();
132
- }
133
- return false;
134
- }
135
-
136
- public function filterProductValues()
137
- {
138
- $getProduct = new Woo_Feed_Products();
139
- $products = $this->products;
140
-
141
- foreach ($products as $no => $product) {
142
- if (array_key_exists('title', $product)) {
143
- $id = $product['title'];
144
- } else {
145
- $id = $product['id'];
146
- }
147
-
148
- foreach ($product as $key => $value) {
149
-
150
- switch ($key) {
151
- case "id":
152
- if (strlen($value) > 50) {
153
- $this->errorLog[$this->errorCounter] = "Product id is more that 50 character for $id.";
154
- $this->errorCounter++;
155
- }
156
- break;
157
- case "title":
158
- if (strlen($value) > 100) {
159
- $this->errorLog[$this->errorCounter] = "Product Title is more that 100 character for $id.";
160
- $this->errorCounter++;
161
- }
162
- $this->products[$no][$key] = ucwords($value);
163
- break;
164
- case "description":
165
- if (strlen($value) > 1500) {
166
- $this->errorLog[$this->errorCounter] = "Product Description is more that 1500 character for $id.";
167
- $this->errorCounter++;
168
- }
169
-
170
- $this->products[$no][$key] = strip_tags($value);
171
- break;
172
- case "short_description":
173
- if (strlen($value) > 1500) {
174
- $this->errorLog[$this->errorCounter] = "Product Short Description is more that 1500 character for $id.";
175
- $this->errorCounter++;
176
- }
177
- $this->products[$no][$key] = strip_tags($value);
178
- break;
179
- case "product_type":
180
- break;
181
- case "link":
182
- break;
183
- case "image":
184
- $this->products[$no][$key] = urlencode($value);
185
- break;
186
- case "images":
187
- break;
188
- case "condition":
189
- $conditions = array('New', 'Refurbished', 'Used', 'Like New', '3rd Party', 'Open Box', 'OEM', 'Downloadable', 'Import / Grey Market', 'Price w/Plan New', 'Price w/Plan Refurb');
190
- if (!in_array($value, $conditions)) {
191
- $this->errorLog[$this->errorCounter] = "Product Condition do not containing accepted value for <b>$id</b>.";
192
- $this->errorCounter++;
193
- }
194
- break;
195
- case "item_group_id":
196
- break;
197
- case "sku":
198
- break;
199
- case "availability":
200
- if ($value == 'in stock') {
201
- $this->products[$no][$key] = "In Stock";
202
- } else if ($value == 'out of stock') {
203
- $this->products[$no][$key] = "Out of Stock";
204
- }
205
- break;
206
- case "quantity":
207
- break;
208
- case "price":
209
- break;
210
- case "sale_price":
211
- break;
212
- case "weight":
213
- break;
214
- case "width":
215
- break;
216
- case "height":
217
- break;
218
- case "length":
219
- break;
220
- case "sale_price_effective_date":
221
- $from = $getProduct->sale_price_effective_date($id, '_sale_price_dates_from');
222
- $to = $getProduct->sale_price_effective_date($id, '_sale_price_dates_to');
223
- if (!empty($from) && !empty($to)) {
224
- $from = date('Y-m-d\TH:iO', $from);
225
- $to = date('Y-m-d\TH:iO', $to);
226
- $this->products[$no]['sale_price_effective_date'] = "$from" . "/" . "$to";
227
- } else {
228
- $this->errorLog[$this->errorCounter] = "Sale Price Effective Date Missing for <b>$id</b>.";
229
- $this->errorCounter++;
230
- }
231
- break;
232
- case "mpn":
233
- break;
234
- case "gtin":
235
- break;
236
- case "brand":
237
- break;
238
- case "color":
239
- break;
240
- case "size":
241
- break;
242
- case "current_category":
243
- if (substr($value, 0, 12) == "wf_cmapping_") {
244
- $parent = $product['item_group_id'];
245
- $category = $this->get_category_mapping_value($value, $parent);
246
- //unset($this->products[$no][$key]);
247
- $this->products[$no][$key] = $category;
248
- }
249
- break;
250
- default:
251
- break;
252
- }
253
- }
254
- }
255
- }
256
-
257
- public function get_category_mapping_value($mappingName, $parent)
258
- {
259
- $getValue = unserialize(get_option($mappingName));
260
- $mapp = array_reverse($getValue['cmapping'], true);
261
- $categories = get_the_terms($parent, 'product_cat');
262
-
263
- foreach ($categories as $key => $category) {
264
- if (!empty($mapp[$category->term_id]))
265
- return $mapp[$category->term_id];
266
- }
267
- }
268
-
269
-
270
- public function mapProductsByRules()
271
- {
272
- $products = new Woo_Feed_Products(); //$this->woo_feed_get_visible_product();
273
- $attributes = $this->rules['attributes'];
274
- $prefix = $this->rules['prefix'];
275
- $suffix = $this->rules['suffix'];
276
- $outputType = $this->rules['output_type'];
277
- $limit = $this->rules['limit'];
278
- $merchantAttributes = $this->rules['mattributes'];
279
- $type = $this->rules['type'];
280
- $default = $this->rules['default'];
281
- $feedType = $this->rules['feedType'];
282
-
283
- // Map Merchant Attributes and Woo Attributes
284
- if (count($merchantAttributes)) {
285
- foreach ($merchantAttributes as $key => $attr) {
286
- if (!empty($attr) && !empty($attributes[$key])) {
287
- if ($type[$key] == 'attribute') {
288
- $this->mapping[$attr]['value'] = $attributes[$key];
289
- $this->mapping[$attr]['suffix'] = $suffix[$key];
290
- $this->mapping[$attr]['prefix'] = $prefix[$key];
291
- $this->mapping[$attr]['type'] = $outputType[$key];
292
- $this->mapping[$attr]['limit'] = $limit[$key];
293
- }
294
- } else if (empty($attributes[$key])) {
295
- if ($type[$key] == 'pattern') {
296
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
297
- $this->mapping[$attr]['suffix'] = $suffix[$key];
298
- $this->mapping[$attr]['prefix'] = $prefix[$key];
299
- $this->mapping[$attr]['type'] = $outputType[$key];
300
- $this->mapping[$attr]['limit'] = $limit[$key];
301
- }
302
- }
303
- }
304
- }
305
-
306
- // Make Product feed array according to mapping
307
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
308
- $i = 0;
309
- foreach ($this->mapping as $attr => $rules) {
310
- if (array_key_exists($rules['value'], $value)) {
311
-
312
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
313
- // Format According to output type
314
- if ($rules['type'] == 2) {
315
- $output = strip_tags($output);
316
- } elseif ($rules['type'] == 3) {
317
- $output = absint($output);
318
- }
319
- // Format According to output limit
320
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
321
- $output = substr($output, 0, $rules['limit']);
322
- }
323
-
324
- $attr = trim($attr);
325
- $this->products[$key][$attr] = trim($output);
326
- } else {
327
- if (!empty($default[$i])) {
328
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
329
- if ($rules['type'] == 2) {
330
- $output = strip_tags($output);
331
- } elseif ($rules['type'] == 3) {
332
- $output = absint($output);
333
- }
334
- // Format According to output limit
335
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
336
- $output = substr($output, 0, $rules['limit']);
337
- }
338
-
339
- $attr = trim($attr);
340
- $this->products[$key][$attr] = trim($output);
341
- }
342
- }
343
- $i++;
344
- }
345
- }
346
- return $this->products;
347
- }
348
-
349
- public function mapAttribute($from, $to, $cdata = false)
350
- {
351
- $i = 0;
352
- foreach ($this->products as $no => $product) {
353
- foreach ($product as $key => $value) {
354
- if ($key == $from) {
355
- unset($this->products[$no][$from]);
356
- if ($from == 'images') {
357
- $this->products[$no][$to] = $value;
358
- } else {
359
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
360
- }
361
- }
362
- }
363
- $i++;
364
- }
365
- }
366
-
367
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
368
- {
369
- //Make single line for XML
370
- $c_leader = '';
371
- $c_footer = '';
372
- if ($cdata) {
373
- $c_leader = '<![CDATA[';
374
- $c_footer = ']]>';
375
- }
376
- //Allow force strip HTML
377
- if ($stripHTML)
378
- $value = strip_tags(html_entity_decode($value));
379
-
380
-
381
- if ($utf8encode || $utf8encode == 1) {
382
- $value = utf8_encode($value);
383
- $attribute = utf8_encode($attribute);
384
- }
385
-
386
-
387
- if (!$cdata)
388
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
389
-
390
- if (gettype($value) == 'array')
391
- $value = json_encode($value);
392
-
393
-
394
- return '
395
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
396
- }
397
-
398
- function change_key($array, $old_key, $new_key)
399
- {
400
- foreach ($this->products as $no => $product) {
401
- if (!array_key_exists($old_key, $product))
402
- return $array;
403
-
404
- $keys = array_keys($array);
405
- $keys[array_search($old_key, $keys)] = $new_key;
406
- }
407
- return array_combine($keys, $array);
408
- }
409
-
410
- public function get_feed_header()
411
- {
412
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
413
- <products>';
414
- $output .= "\n";
415
- return $output;
416
- }
417
-
418
- public function get_feed($items)
419
- {
420
- $feed = "";
421
- $feed .= $this->get_feed_header();
422
- $feed .= "\n";
423
- foreach ($items as $item => $products) {
424
- $feed .= " <" . $this->feedWrapper . ">";
425
- foreach ($products as $key => $value) {
426
- if (!empty($value))
427
- $feed .= $value;
428
- }
429
- $feed .= "\n </" . $this->feedWrapper . ">\n";
430
- }
431
- $feed .= $this->get_feed_footer();
432
-
433
- return $feed;
434
- }
435
-
436
- public function get_feed_footer()
437
- {
438
- $footer = " </products>";
439
- return $footer;
440
- }
441
-
442
- public function get_txt_feed()
443
- {
444
- if ( is_countable( $this->products ) && count( $this->products ) ) {
445
- $headers = array_keys($this->products[0]);
446
- $feed[] = $headers;
447
- foreach ($this->products as $no => $product) {
448
- $row = array();
449
- foreach ($headers as $key => $header) {
450
- $row[] = $product[$header];
451
- }
452
- $feed[] = $row;
453
- }
454
- $str = "";
455
- foreach ($feed as $fields) {
456
- $str .= implode("\t", $fields) . "\n";
457
- }
458
- return $str;
459
- }
460
- return false;
461
- }
462
-
463
- public function get_csv_feed()
464
- {
465
- if ( is_countable( $this->products ) && count( $this->products ) ) {
466
- $headers = array_keys($this->products[0]);
467
- $feed[] = $headers;
468
- foreach ($this->products as $no => $product) {
469
- $row = array();
470
- foreach ($headers as $key => $header) {
471
- $row[] = $product[$header];
472
- }
473
- $feed[] = $row;
474
- }
475
-
476
- return $feed;
477
- }
478
- return false;
479
- }
480
  }
1
+ <?php
2
+
3
+
4
+ class Pricegrabber
5
+ {
6
+
7
+ public $products;
8
+
9
+ public $rules;
10
+
11
+ public $mapping;
12
+
13
+ public $errorLog;
14
+ public $errorCounter = 0;
15
+
16
+ private $filteredProduct;
17
+ private $feedWrapper = 'item';
18
+
19
+ public function __construct($feedRule)
20
+ {
21
+ $this->rules = $feedRule;
22
+ $this->mapProductsByRules();
23
+ $this->formatRequiredField();
24
+ $this->filterProductValues();
25
+ if ($this->rules['feedType'] == 'xml') {
26
+ $this->mapAttributeForXML();
27
+ } else {
28
+ $this->mapAttributeForCSVTEXT();
29
+ }
30
+ }
31
+
32
+ public function mapAttributeForXML()
33
+ {
34
+ //Basic product information
35
+
36
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
37
+ foreach ($this->products as $key => $values) {
38
+ foreach ($values as $attr => $value) {
39
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+
46
+ public function mapAttributeForCSVTEXT()
47
+ {
48
+ //Basic product information
49
+
50
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
51
+ foreach ($this->products as $key => $values) {
52
+ foreach ($values as $attr => $value) {
53
+ //Allow force strip HTML
54
+
55
+ $value = strip_tags(html_entity_decode($value));
56
+
57
+ $value = utf8_encode($value);
58
+ $attr = utf8_encode($attr);
59
+
60
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
61
+
62
+ if (gettype($value) == 'array')
63
+ $value = json_encode($value);
64
+
65
+ $this->products[$key][$attr] = $value;
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ public function formatRequiredField()
72
+ {
73
+ foreach ($this->products as $no => $product) {
74
+ $upn = 0;
75
+ if (array_key_exists('title', $product)) {
76
+ $id = $product['title'];
77
+ } else {
78
+ $id = $product['id'];
79
+ }
80
+ foreach ($product as $key => $value) {
81
+ if ($key == 'mpn' || $key == 'gtin') {
82
+ $upn++;
83
+ }
84
+ }
85
+
86
+ if (!array_key_exists('title', $product)) {
87
+ $this->errorLog[$this->errorCounter] = "Product Title Missing for <b>$id</b>.";
88
+ $this->errorCounter++;
89
+ }
90
+
91
+ if (!array_key_exists('id', $product)) {
92
+ $this->errorLog[$this->errorCounter] = "Product Id Missing for <b>$id</b>.";
93
+ $this->errorCounter++;
94
+ }
95
+
96
+ if (!array_key_exists('brand', $product)) {
97
+ $this->errorLog[$this->errorCounter] = "Product Brand Missing for <b>$id</b>.";
98
+ $this->errorCounter++;
99
+ }
100
+
101
+ if (!array_key_exists('description', $product)) {
102
+ $this->errorLog[$this->errorCounter] = "Product Description Missing for <b>$id</b>.";
103
+ $this->errorCounter++;
104
+ }
105
+
106
+ if (!array_key_exists('link', $product)) {
107
+ $this->errorLog[$this->errorCounter] = "Product Link Missing for <b>$id</b>.";
108
+ $this->errorCounter++;
109
+ }
110
+
111
+ if (!array_key_exists('image', $product)) {
112
+ $this->errorLog[$this->errorCounter] = "Product Image Link Missing for <b>$id</b>.";
113
+ $this->errorCounter++;
114
+ }
115
+
116
+ if (!array_key_exists('condition', $product)) {
117
+ $this->errorLog[$this->errorCounter] = "Product Condition Missing for <b>$id</b>.";
118
+ $this->errorCounter++;
119
+ }
120
+
121
+ }
122
+ }
123
+
124
+ public function returnFinalProduct()
125
+ {
126
+ if ($this->rules['feedType'] == 'xml') {
127
+ return $this->get_feed($this->products);
128
+ } elseif ($this->rules['feedType'] == 'txt') {
129
+ return $this->get_txt_feed();
130
+ } elseif ($this->rules['feedType'] == 'csv') {
131
+ return $this->get_csv_feed();
132
+ }
133
+ return false;
134
+ }
135
+
136
+ public function filterProductValues()
137
+ {
138
+ $getProduct = new Woo_Feed_Products();
139
+ $products = $this->products;
140
+
141
+ foreach ($products as $no => $product) {
142
+ if (array_key_exists('title', $product)) {
143
+ $id = $product['title'];
144
+ } else {
145
+ $id = $product['id'];
146
+ }
147
+
148
+ foreach ($product as $key => $value) {
149
+
150
+ switch ($key) {
151
+ case "id":
152
+ if (strlen($value) > 50) {
153
+ $this->errorLog[$this->errorCounter] = "Product id is more that 50 character for $id.";
154
+ $this->errorCounter++;
155
+ }
156
+ break;
157
+ case "title":
158
+ if (strlen($value) > 100) {
159
+ $this->errorLog[$this->errorCounter] = "Product Title is more that 100 character for $id.";
160
+ $this->errorCounter++;
161
+ }
162
+ $this->products[$no][$key] = ucwords($value);
163
+ break;
164
+ case "description":
165
+ if (strlen($value) > 1500) {
166
+ $this->errorLog[$this->errorCounter] = "Product Description is more that 1500 character for $id.";
167
+ $this->errorCounter++;
168
+ }
169
+
170
+ $this->products[$no][$key] = strip_tags($value);
171
+ break;
172
+ case "short_description":
173
+ if (strlen($value) > 1500) {
174
+ $this->errorLog[$this->errorCounter] = "Product Short Description is more that 1500 character for $id.";
175
+ $this->errorCounter++;
176
+ }
177
+ $this->products[$no][$key] = strip_tags($value);
178
+ break;
179
+ case "product_type":
180
+ break;
181
+ case "link":
182
+ break;
183
+ case "image":
184
+ $this->products[$no][$key] = urlencode($value);
185
+ break;
186
+ case "images":
187
+ break;
188
+ case "condition":
189
+ $conditions = array('New', 'Refurbished', 'Used', 'Like New', '3rd Party', 'Open Box', 'OEM', 'Downloadable', 'Import / Grey Market', 'Price w/Plan New', 'Price w/Plan Refurb');
190
+ if (!in_array($value, $conditions)) {
191
+ $this->errorLog[$this->errorCounter] = "Product Condition do not containing accepted value for <b>$id</b>.";
192
+ $this->errorCounter++;
193
+ }
194
+ break;
195
+ case "item_group_id":
196
+ break;
197
+ case "sku":
198
+ break;
199
+ case "availability":
200
+ if ($value == 'in stock') {
201
+ $this->products[$no][$key] = "In Stock";
202
+ } else if ($value == 'out of stock') {
203
+ $this->products[$no][$key] = "Out of Stock";
204
+ }
205
+ break;
206
+ case "quantity":
207
+ break;
208
+ case "price":
209
+ break;
210
+ case "sale_price":
211
+ break;
212
+ case "weight":
213
+ break;
214
+ case "width":
215
+ break;
216
+ case "height":
217
+ break;
218
+ case "length":
219
+ break;
220
+ case "sale_price_effective_date":
221
+ $from = $getProduct->sale_price_effective_date($id, '_sale_price_dates_from');
222
+ $to = $getProduct->sale_price_effective_date($id, '_sale_price_dates_to');
223
+ if (!empty($from) && !empty($to)) {
224
+ $from = date('Y-m-d\TH:iO', $from);
225
+ $to = date('Y-m-d\TH:iO', $to);
226
+ $this->products[$no]['sale_price_effective_date'] = "$from" . "/" . "$to";
227
+ } else {
228
+ $this->errorLog[$this->errorCounter] = "Sale Price Effective Date Missing for <b>$id</b>.";
229
+ $this->errorCounter++;
230
+ }
231
+ break;
232
+ case "mpn":
233
+ break;
234
+ case "gtin":
235
+ break;
236
+ case "brand":
237
+ break;
238
+ case "color":
239
+ break;
240
+ case "size":
241
+ break;
242
+ case "current_category":
243
+ if (substr($value, 0, 12) == "wf_cmapping_") {
244
+ $parent = $product['item_group_id'];
245
+ $category = $this->get_category_mapping_value($value, $parent);
246
+ //unset($this->products[$no][$key]);
247
+ $this->products[$no][$key] = $category;
248
+ }
249
+ break;
250
+ default:
251
+ break;
252
+ }
253
+ }
254
+ }
255
+ }
256
+
257
+ public function get_category_mapping_value($mappingName, $parent)
258
+ {
259
+ $getValue = unserialize(get_option($mappingName));
260
+ $mapp = array_reverse($getValue['cmapping'], true);
261
+ $categories = get_the_terms($parent, 'product_cat');
262
+
263
+ foreach ($categories as $key => $category) {
264
+ if (!empty($mapp[$category->term_id]))
265
+ return $mapp[$category->term_id];
266
+ }
267
+ }
268
+
269
+
270
+ public function mapProductsByRules()
271
+ {
272
+ $products = new Woo_Feed_Products(); //$this->woo_feed_get_visible_product();
273
+ $attributes = $this->rules['attributes'];
274
+ $prefix = $this->rules['prefix'];
275
+ $suffix = $this->rules['suffix'];
276
+ $outputType = $this->rules['output_type'];
277
+ $limit = $this->rules['limit'];
278
+ $merchantAttributes = $this->rules['mattributes'];
279
+ $type = $this->rules['type'];
280
+ $default = $this->rules['default'];
281
+ $feedType = $this->rules['feedType'];
282
+
283
+ // Map Merchant Attributes and Woo Attributes
284
+ if (count($merchantAttributes)) {
285
+ foreach ($merchantAttributes as $key => $attr) {
286
+ if (!empty($attr) && !empty($attributes[$key])) {
287
+ if ($type[$key] == 'attribute') {
288
+ $this->mapping[$attr]['value'] = $attributes[$key];
289
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
290
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
291
+ $this->mapping[$attr]['type'] = $outputType[$key];
292
+ $this->mapping[$attr]['limit'] = $limit[$key];
293
+ }
294
+ } else if (empty($attributes[$key])) {
295
+ if ($type[$key] == 'pattern') {
296
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
297
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
298
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
299
+ $this->mapping[$attr]['type'] = $outputType[$key];
300
+ $this->mapping[$attr]['limit'] = $limit[$key];
301
+ }
302
+ }
303
+ }
304
+ }
305
+
306
+ // Make Product feed array according to mapping
307
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
308
+ $i = 0;
309
+ foreach ($this->mapping as $attr => $rules) {
310
+ if (array_key_exists($rules['value'], $value)) {
311
+
312
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
313
+ // Format According to output type
314
+ if ($rules['type'] == 2) {
315
+ $output = strip_tags($output);
316
+ } elseif ($rules['type'] == 3) {
317
+ $output = absint($output);
318
+ }
319
+ // Format According to output limit
320
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
321
+ $output = substr($output, 0, $rules['limit']);
322
+ }
323
+
324
+ $attr = trim($attr);
325
+ $this->products[$key][$attr] = trim($output);
326
+ } else {
327
+ if (!empty($default[$i])) {
328
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
329
+ if ($rules['type'] == 2) {
330
+ $output = strip_tags($output);
331
+ } elseif ($rules['type'] == 3) {
332
+ $output = absint($output);
333
+ }
334
+ // Format According to output limit
335
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
336
+ $output = substr($output, 0, $rules['limit']);
337
+ }
338
+
339
+ $attr = trim($attr);
340
+ $this->products[$key][$attr] = trim($output);
341
+ }
342
+ }
343
+ $i++;
344
+ }
345
+ }
346
+ return $this->products;
347
+ }
348
+
349
+ public function mapAttribute($from, $to, $cdata = false)
350
+ {
351
+ $i = 0;
352
+ foreach ($this->products as $no => $product) {
353
+ foreach ($product as $key => $value) {
354
+ if ($key == $from) {
355
+ unset($this->products[$no][$from]);
356
+ if ($from == 'images') {
357
+ $this->products[$no][$to] = $value;
358
+ } else {
359
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
360
+ }
361
+ }
362
+ }
363
+ $i++;
364
+ }
365
+ }
366
+
367
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
368
+ {
369
+ //Make single line for XML
370
+ $c_leader = '';
371
+ $c_footer = '';
372
+ if ($cdata) {
373
+ $c_leader = '<![CDATA[';
374
+ $c_footer = ']]>';
375
+ }
376
+ //Allow force strip HTML
377
+ if ($stripHTML)
378
+ $value = strip_tags(html_entity_decode($value));
379
+
380
+
381
+ if ($utf8encode || $utf8encode == 1) {
382
+ $value = utf8_encode($value);
383
+ $attribute = utf8_encode($attribute);
384
+ }
385
+
386
+
387
+ if (!$cdata)
388
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
389
+
390
+ if (gettype($value) == 'array')
391
+ $value = json_encode($value);
392
+
393
+
394
+ return '
395
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
396
+ }
397
+
398
+ function change_key($array, $old_key, $new_key)
399
+ {
400
+ foreach ($this->products as $no => $product) {
401
+ if (!array_key_exists($old_key, $product))
402
+ return $array;
403
+
404
+ $keys = array_keys($array);
405
+ $keys[array_search($old_key, $keys)] = $new_key;
406
+ }
407
+ return array_combine($keys, $array);
408
+ }
409
+
410
+ public function get_feed_header()
411
+ {
412
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
413
+ <products>';
414
+ $output .= "\n";
415
+ return $output;
416
+ }
417
+
418
+ public function get_feed($items)
419
+ {
420
+ $feed = "";
421
+ $feed .= $this->get_feed_header();
422
+ $feed .= "\n";
423
+ foreach ($items as $item => $products) {
424
+ $feed .= " <" . $this->feedWrapper . ">";
425
+ foreach ($products as $key => $value) {
426
+ if (!empty($value))
427
+ $feed .= $value;
428
+ }
429
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
430
+ }
431
+ $feed .= $this->get_feed_footer();
432
+
433
+ return $feed;
434
+ }
435
+
436
+ public function get_feed_footer()
437
+ {
438
+ $footer = " </products>";
439
+ return $footer;
440
+ }
441
+
442
+ public function get_txt_feed()
443
+ {
444
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
445
+ $headers = array_keys($this->products[0]);
446
+ $feed[] = $headers;
447
+ foreach ($this->products as $no => $product) {
448
+ $row = array();
449
+ foreach ($headers as $key => $header) {
450
+ $row[] = $product[$header];
451
+ }
452
+ $feed[] = $row;
453
+ }
454
+ $str = "";
455
+ foreach ($feed as $fields) {
456
+ $str .= implode("\t", $fields) . "\n";
457
+ }
458
+ return $str;
459
+ }
460
+ return false;
461
+ }
462
+
463
+ public function get_csv_feed()
464
+ {
465
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
466
+ $headers = array_keys($this->products[0]);
467
+ $feed[] = $headers;
468
+ foreach ($this->products as $no => $product) {
469
+ $row = array();
470
+ foreach ($headers as $key => $header) {
471
+ $row[] = $product[$header];
472
+ }
473
+ $feed[] = $row;
474
+ }
475
+
476
+ return $feed;
477
+ }
478
+ return false;
479
+ }
480
  }
includes/feeds/class-woo-feed-shopmania.php CHANGED
@@ -1,468 +1,468 @@
1
- <?php
2
-
3
-
4
- class Shopmania
5
- {
6
-
7
- public $products;
8
-
9
- public $rules;
10
-
11
- public $mapping;
12
-
13
- public $errorLog;
14
- public $errorCounter = 0;
15
-
16
- private $filteredProduct;
17
- private $feedWrapper = 'product';
18
-
19
- public function __construct($feedRule)
20
- {
21
- $this->rules = $feedRule;
22
- $this->mapProductsByRules();
23
- $this->formatRequiredField();
24
- $this->filterProductValues();
25
- if ($this->rules['feedType'] == 'xml') {
26
- $this->mapAttributeForXML();
27
- } else {
28
- $this->mapAttributeForCSVTEXT();
29
- }
30
- }
31
-
32
- public function mapAttributeForXML()
33
- {
34
- //Basic product information
35
-
36
- if ( is_countable( $this->products ) && count( $this->products ) ) {
37
- foreach ($this->products as $key => $values) {
38
- foreach ($values as $attr => $value) {
39
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
40
- }
41
- }
42
- }
43
- }
44
-
45
-
46
- public function mapAttributeForCSVTEXT()
47
- {
48
- //Basic product information
49
-
50
- if ( is_countable( $this->products ) && count( $this->products ) ) {
51
- foreach ($this->products as $key => $values) {
52
- foreach ($values as $attr => $value) {
53
- //Allow force strip HTML
54
-
55
- $value = strip_tags(html_entity_decode($value));
56
-
57
- $value = utf8_encode($value);
58
- $attr = utf8_encode($attr);
59
-
60
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
61
-
62
- if (gettype($value) == 'array')
63
- $value = json_encode($value);
64
-
65
- $this->products[$key][$attr] = $value;
66
- }
67
- }
68
- }
69
- }
70
-
71
- public function formatRequiredField()
72
- {
73
- foreach ($this->products as $no => $product) {
74
- $upn = 0;
75
- if (array_key_exists('title', $product)) {
76
- $id = $product['title'];
77
- } else {
78
- $id = $product['id'];
79
- }
80
-
81
- if (!array_key_exists('title', $product)) {
82
- $this->errorLog[$this->errorCounter] = "Product Title Missing for <b>$id</b>.";
83
- $this->errorCounter++;
84
- }
85
-
86
-
87
- if (!array_key_exists('brand', $product)) {
88
- $this->errorLog[$this->errorCounter] = "Product Manufacturer Missing for <b>$id</b>.";
89
- $this->errorCounter++;
90
- }
91
-
92
- if (!array_key_exists('description', $product)) {
93
- $this->errorLog[$this->errorCounter] = "Product Description Missing for <b>$id</b>.";
94
- $this->errorCounter++;
95
- }
96
-
97
- if (!array_key_exists('link', $product)) {
98
- $this->errorLog[$this->errorCounter] = "Product Link Missing for <b>$id</b>.";
99
- $this->errorCounter++;
100
- }
101
-
102
- if (!array_key_exists('image', $product)) {
103
- $this->errorLog[$this->errorCounter] = "Product Image Link Missing for <b>$id</b>.";
104
- $this->errorCounter++;
105
- }
106
-
107
- if (!array_key_exists('condition', $product)) {
108
- $this->errorLog[$this->errorCounter] = "Product Condition Missing for <b>$id</b>.";
109
- $this->errorCounter++;
110
- }
111
-
112
- }
113
- }
114
-
115
- public function returnFinalProduct()
116
- {
117
- if ($this->rules['feedType'] == 'xml') {
118
- return $this->get_feed($this->products);
119
- } elseif ($this->rules['feedType'] == 'txt') {
120
- return $this->get_txt_feed();
121
- } elseif ($this->rules['feedType'] == 'csv') {
122
- return $this->get_csv_feed();
123
- }
124
- return false;
125
- }
126
-
127
- public function filterProductValues()
128
- {
129
- $getProduct = new Woo_Feed_Products();
130
- $products = $this->products;
131
-
132
- foreach ($products as $no => $product) {
133
- if (array_key_exists('title', $product)) {
134
- $id = $product['title'];
135
- } else {
136
- $id = $product['id'];
137
- }
138
- // echo "<pre>";
139
- // print_r($product);
140
- foreach ($product as $key => $value) {
141
-
142
-
143
- switch ($key) {
144
- case "id":
145
- if (strlen($value) > 50) {
146
- $this->errorLog[$this->errorCounter] = "Product id is more that 50 character for $id.";
147
- $this->errorCounter++;
148
- }
149
- break;
150
- case "title":
151
- if (strlen($value) > 100) {
152
- $this->errorLog[$this->errorCounter] = "Product Title is more that 100 character for $id.";
153
- $this->errorCounter++;
154
- }
155
- $this->products[$no][$key] = ucwords($value);
156
- break;
157
- case "description":
158
- if (strlen($value) > 1500) {
159
- $this->errorLog[$this->errorCounter] = "Product Description is more that 1500 character for $id.";
160
- $this->errorCounter++;
161
- }
162
-
163
- $this->products[$no][$key] = strip_tags($value);
164
- break;
165
- case "short_description":
166
- if (strlen($value) > 1500) {
167
- $this->errorLog[$this->errorCounter] = "Product Short Description is more that 1500 character for $id.";
168
- $this->errorCounter++;
169
- }
170
- $this->products[$no][$key] = strip_tags($value);
171
- break;
172
- case "product_type":
173
- break;
174
- case "link":
175
- break;
176
- case "image":
177
- break;
178
- case "images":
179
- break;
180
- case "condition":
181
- break;
182
- case "item_group_id":
183
- break;
184
- case "sku":
185
- break;
186
- case "Availability":
187
- if ($value == 'in stock') {
188
- $this->products[$no][$key] = "In Stock";
189
- } else {
190
- $this->products[$no][$key] = "Out of Stock";
191
- }
192
- break;
193
- case "quantity":
194
- break;
195
- case "price":
196
- break;
197
- case "sale_price":
198
- break;
199
- case "weight":
200
- break;
201
- case "width":
202
- break;
203
- case "height":
204
- break;
205
- case "length":
206
- break;
207
- case "sale_price_effective_date":
208
- $from = $getProduct->sale_price_effective_date($id, '_sale_price_dates_from');
209
- $to = $getProduct->sale_price_effective_date($id, '_sale_price_dates_to');
210
- if (!empty($from) && !empty($to)) {
211
- $from = date('Y-m-d', $from);
212
- $to = date('Y-m-d', $to);
213
- $this->products[$no]['sale_price_effective_date'] = "$from" . "/" . "$to";
214
- } else {
215
- $this->errorLog[$this->errorCounter] = "Sale Price Effective Date Missing for <b>$id</b>.";
216
- $this->errorCounter++;
217
- }
218
- break;
219
- case "mpn":
220
- break;
221
- case "gtin":
222
- break;
223
- case "brand":
224
- break;
225
- case "color":
226
- break;
227
- case "size":
228
- break;
229
- case "current_category":
230
- if (substr($value, 0, 12) == "wf_cmapping_") {
231
- $parent = $product['item_group_id'];
232
- $category = $this->get_category_mapping_value($value, $parent);
233
- //unset($this->products[$no][$key]);
234
- $this->products[$no][$key] = $category;
235
- }
236
- break;
237
- default:
238
- break;
239
- }
240
- }
241
- }
242
- }
243
-
244
- public function get_category_mapping_value($mappingName, $parent)
245
- {
246
- $getValue = unserialize(get_option($mappingName));
247
- $mapp = array_reverse($getValue['cmapping'], true);
248
- $categories = get_the_terms($parent, 'product_cat');
249
-
250
- foreach ($categories as $key => $category) {
251
- if (!empty($mapp[$category->term_id]))
252
- return $mapp[$category->term_id];
253
- }
254
- }
255
-
256
-
257
- public function mapProductsByRules()
258
- {
259
- $products = new Woo_Feed_Products(); //$this->woo_feed_get_visible_product();
260
- $attributes = $this->rules['attributes'];
261
- $prefix = $this->rules['prefix'];
262
- $suffix = $this->rules['suffix'];
263
- $outputType = $this->rules['output_type'];
264
- $limit = $this->rules['limit'];
265
- $merchantAttributes = $this->rules['mattributes'];
266
- $type = $this->rules['type'];
267
- $default = $this->rules['default'];
268
- $feedType = $this->rules['feedType'];
269
-
270
- // Map Merchant Attributes and Woo Attributes
271
- if (count($merchantAttributes)) {
272
- foreach ($merchantAttributes as $key => $attr) {
273
- if (!empty($attr) && !empty($attributes[$key])) {
274
- if ($type[$key] == 'attribute') {
275
- $this->mapping[$attr]['value'] = $attributes[$key];
276
- $this->mapping[$attr]['suffix'] = $suffix[$key];
277
- $this->mapping[$attr]['prefix'] = $prefix[$key];
278
- $this->mapping[$attr]['type'] = $outputType[$key];
279
- $this->mapping[$attr]['limit'] = $limit[$key];
280
- }
281
- } else if (empty($attributes[$key])) {
282
- if ($type[$key] == 'pattern') {
283
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
284
- $this->mapping[$attr]['suffix'] = $suffix[$key];
285
- $this->mapping[$attr]['prefix'] = $prefix[$key];
286
- $this->mapping[$attr]['type'] = $outputType[$key];
287
- $this->mapping[$attr]['limit'] = $limit[$key];
288
- }
289
- }
290
- }
291
- }
292
-
293
- // Make Product feed array according to mapping
294
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
295
- $i = 0;
296
- foreach ($this->mapping as $attr => $rules) {
297
- if (array_key_exists($rules['value'], $value)) {
298
-
299
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
300
- // Format According to output type
301
- if ($rules['type'] == 2) {
302
- $output = strip_tags($output);
303
- } elseif ($rules['type'] == 3) {
304
- $output = absint($output);
305
- }
306
- // Format According to output limit
307
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
308
- $output = substr($output, 0, $rules['limit']);
309
- }
310
- $attr = trim($attr);
311
- $this->products[$key][$attr] = trim($output);
312
- } else {
313
- if (!empty($default[$i])) {
314
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
315
- if ($rules['type'] == 2) {
316
- $output = strip_tags($output);
317
- } elseif ($rules['type'] == 3) {
318
- $output = absint($output);
319
- }
320
- // Format According to output limit
321
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
322
- $output = substr($output, 0, $rules['limit']);
323
- }
324
- $attr = trim($attr);
325
- $this->products[$key][$attr] = trim($output);
326
- }
327
- }
328
- $i++;
329
- }
330
- }
331
-
332
-
333
- return $this->products;
334
- }
335
-
336
- public function mapAttribute($from, $to, $cdata = false)
337
- {
338
- $i = 0;
339
- foreach ($this->products as $no => $product) {
340
- foreach ($product as $key => $value) {
341
- if ($key == $from) {
342
- unset($this->products[$no][$from]);
343
- if ($from == 'images') {
344
- $this->products[$no][$to] = $value;
345
- } else {
346
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
347
- }
348
-
349
- }
350
- }
351
- $i++;
352
- }
353
- }
354
-
355
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
356
- {
357
- //Make single line for XML
358
- $c_leader = '';
359
- $c_footer = '';
360
- if ($cdata) {
361
- $c_leader = '<![CDATA[';
362
- $c_footer = ']]>';
363
- }
364
- //Allow force strip HTML
365
- if ($stripHTML)
366
- $value = strip_tags(html_entity_decode($value));
367
-
368
-
369
- if ($utf8encode || $utf8encode == 1) {
370
- $value = utf8_encode($value);
371
- $attribute = utf8_encode($attribute);
372
- }
373
-
374
-
375
- if (!$cdata)
376
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
377
-
378
- if (gettype($value) == 'array')
379
- $value = json_encode($value);
380
-
381
-
382
- return '
383
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
384
- }
385
-
386
- function change_key($array, $old_key, $new_key)
387
- {
388
- foreach ($this->products as $no => $product) {
389
- if (!array_key_exists($old_key, $product))
390
- return $array;
391
-
392
- $keys = array_keys($array);
393
- $keys[array_search($old_key, $keys)] = $new_key;
394
- }
395
- return array_combine($keys, $array);
396
- }
397
-
398
- public function get_feed_header()
399
- {
400
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
401
- <products>';
402
- $output .= "\n";
403
- return $output;
404
- }
405
-
406
- public function get_feed($items)
407
- {
408
- $feed = "";
409
- $feed .= $this->get_feed_header();
410
- $feed .= "\n";
411
- foreach ($items as $item => $products) {
412
- $feed .= " <" . $this->feedWrapper . ">";
413
- foreach ($products as $key => $value) {
414
- if (!empty($value))
415
- $feed .= $value;
416
- }
417
- $feed .= "\n </" . $this->feedWrapper . ">\n";
418
- }
419
- $feed .= $this->get_feed_footer();
420
-
421
- return $feed;
422
- }
423
-
424
- public function get_feed_footer()
425
- {
426
- $footer = " </products>";
427
- return $footer;
428
- }
429
-
430
- public function get_txt_feed()
431
- {
432
- if ( is_countable( $this->products ) && count( $this->products ) ) {
433
- $headers = array_keys($this->products[0]);
434
- $feed[] = $headers;
435
- foreach ($this->products as $no => $product) {
436
- $row = array();
437
- foreach ($headers as $key => $header) {
438
- $row[] = $product[$header];
439
- }
440
- $feed[] = $row;
441
- }
442
- $str = "";
443
- foreach ($feed as $fields) {
444
- $str .= implode("\t", $fields) . "\n";
445
- }
446
- return $str;
447
- }
448
- return false;
449
- }
450
-
451
- public function get_csv_feed()
452
- {
453
- if ( is_countable( $this->products ) && count( $this->products ) ) {
454
- $headers = array_keys($this->products[0]);
455
- $feed[] = $headers;
456
- foreach ($this->products as $no => $product) {
457
- $row = array();
458
- foreach ($headers as $key => $header) {
459
- $row[] = $product[$header];
460
- }
461
- $feed[] = $row;
462
- }
463
-
464
- return $feed;
465
- }
466
- return false;
467
- }
468
  }
1
+ <?php
2
+
3
+
4
+ class Shopmania
5
+ {
6
+
7
+ public $products;
8
+
9
+ public $rules;
10
+
11
+ public $mapping;
12
+
13
+ public $errorLog;
14
+ public $errorCounter = 0;
15
+
16
+ private $filteredProduct;
17
+ private $feedWrapper = 'product';
18
+
19
+ public function __construct($feedRule)
20
+ {
21
+ $this->rules = $feedRule;
22
+ $this->mapProductsByRules();
23
+ $this->formatRequiredField();
24
+ $this->filterProductValues();
25
+ if ($this->rules['feedType'] == 'xml') {
26
+ $this->mapAttributeForXML();
27
+ } else {
28
+ $this->mapAttributeForCSVTEXT();
29
+ }
30
+ }
31
+
32
+ public function mapAttributeForXML()
33
+ {
34
+ //Basic product information
35
+
36
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
37
+ foreach ($this->products as $key => $values) {
38
+ foreach ($values as $attr => $value) {
39
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+
46
+ public function mapAttributeForCSVTEXT()
47
+ {
48
+ //Basic product information
49
+
50
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
51
+ foreach ($this->products as $key => $values) {
52
+ foreach ($values as $attr => $value) {
53
+ //Allow force strip HTML
54
+
55
+ $value = strip_tags(html_entity_decode($value));
56
+
57
+ $value = utf8_encode($value);
58
+ $attr = utf8_encode($attr);
59
+
60
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
61
+
62
+ if (gettype($value) == 'array')
63
+ $value = json_encode($value);
64
+
65
+ $this->products[$key][$attr] = $value;
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ public function formatRequiredField()
72
+ {
73
+ foreach ($this->products as $no => $product) {
74
+ $upn = 0;
75
+ if (array_key_exists('title', $product)) {
76
+ $id = $product['title'];
77
+ } else {
78
+ $id = $product['id'];
79
+ }
80
+
81
+ if (!array_key_exists('title', $product)) {
82
+ $this->errorLog[$this->errorCounter] = "Product Title Missing for <b>$id</b>.";
83
+ $this->errorCounter++;
84
+ }
85
+
86
+
87
+ if (!array_key_exists('brand', $product)) {
88
+ $this->errorLog[$this->errorCounter] = "Product Manufacturer Missing for <b>$id</b>.";
89
+ $this->errorCounter++;
90
+ }
91
+
92
+ if (!array_key_exists('description', $product)) {
93
+ $this->errorLog[$this->errorCounter] = "Product Description Missing for <b>$id</b>.";
94
+ $this->errorCounter++;
95
+ }
96
+
97
+ if (!array_key_exists('link', $product)) {
98
+ $this->errorLog[$this->errorCounter] = "Product Link Missing for <b>$id</b>.";
99
+ $this->errorCounter++;
100
+ }
101
+
102
+ if (!array_key_exists('image', $product)) {
103
+ $this->errorLog[$this->errorCounter] = "Product Image Link Missing for <b>$id</b>.";
104
+ $this->errorCounter++;
105
+ }
106
+
107
+ if (!array_key_exists('condition', $product)) {
108
+ $this->errorLog[$this->errorCounter] = "Product Condition Missing for <b>$id</b>.";
109
+ $this->errorCounter++;
110
+ }
111
+
112
+ }
113
+ }
114
+
115
+ public function returnFinalProduct()
116
+ {
117
+ if ($this->rules['feedType'] == 'xml') {
118
+ return $this->get_feed($this->products);
119
+ } elseif ($this->rules['feedType'] == 'txt') {
120
+ return $this->get_txt_feed();
121
+ } elseif ($this->rules['feedType'] == 'csv') {
122
+ return $this->get_csv_feed();
123
+ }
124
+ return false;
125
+ }
126
+
127
+ public function filterProductValues()
128
+ {
129
+ $getProduct = new Woo_Feed_Products();
130
+ $products = $this->products;
131
+
132
+ foreach ($products as $no => $product) {
133
+ if (array_key_exists('title', $product)) {
134
+ $id = $product['title'];
135
+ } else {
136
+ $id = $product['id'];
137
+ }
138
+ // echo "<pre>";
139
+ // print_r($product);
140
+ foreach ($product as $key => $value) {
141
+
142
+
143
+ switch ($key) {
144
+ case "id":
145
+ if (strlen($value) > 50) {
146
+ $this->errorLog[$this->errorCounter] = "Product id is more that 50 character for $id.";
147
+ $this->errorCounter++;
148
+ }
149
+ break;
150
+ case "title":
151
+ if (strlen($value) > 100) {
152
+ $this->errorLog[$this->errorCounter] = "Product Title is more that 100 character for $id.";
153
+ $this->errorCounter++;
154
+ }
155
+ $this->products[$no][$key] = ucwords($value);
156
+ break;
157
+ case "description":
158
+ if (strlen($value) > 1500) {
159
+ $this->errorLog[$this->errorCounter] = "Product Description is more that 1500 character for $id.";
160
+ $this->errorCounter++;
161
+ }
162
+
163
+ $this->products[$no][$key] = strip_tags($value);
164
+ break;
165
+ case "short_description":
166
+ if (strlen($value) > 1500) {
167
+ $this->errorLog[$this->errorCounter] = "Product Short Description is more that 1500 character for $id.";
168
+ $this->errorCounter++;
169
+ }
170
+ $this->products[$no][$key] = strip_tags($value);
171
+ break;
172
+ case "product_type":
173
+ break;
174
+ case "link":
175
+ break;
176
+ case "image":
177
+ break;
178
+ case "images":
179
+ break;
180
+ case "condition":
181
+ break;
182
+ case "item_group_id":
183
+ break;
184
+ case "sku":
185
+ break;
186
+ case "Availability":
187
+ if ($value == 'in stock') {
188
+ $this->products[$no][$key] = "In Stock";
189
+ } else {
190
+ $this->products[$no][$key] = "Out of Stock";
191
+ }
192
+ break;
193
+ case "quantity":
194
+ break;
195
+ case "price":
196
+ break;
197
+ case "sale_price":
198
+ break;
199
+ case "weight":
200
+ break;
201
+ case "width":
202
+ break;
203
+ case "height":
204
+ break;
205
+ case "length":
206
+ break;
207
+ case "sale_price_effective_date":
208
+ $from = $getProduct->sale_price_effective_date($id, '_sale_price_dates_from');
209
+ $to = $getProduct->sale_price_effective_date($id, '_sale_price_dates_to');
210
+ if (!empty($from) && !empty($to)) {
211
+ $from = date('Y-m-d', $from);
212
+ $to = date('Y-m-d', $to);
213
+ $this->products[$no]['sale_price_effective_date'] = "$from" . "/" . "$to";
214
+ } else {
215
+ $this->errorLog[$this->errorCounter] = "Sale Price Effective Date Missing for <b>$id</b>.";
216
+ $this->errorCounter++;
217
+ }
218
+ break;
219
+ case "mpn":
220
+ break;
221
+ case "gtin":
222
+ break;
223
+ case "brand":
224
+ break;
225
+ case "color":
226
+ break;
227
+ case "size":
228
+ break;
229
+ case "current_category":
230
+ if (substr($value, 0, 12) == "wf_cmapping_") {
231
+ $parent = $product['item_group_id'];
232
+ $category = $this->get_category_mapping_value($value, $parent);
233
+ //unset($this->products[$no][$key]);
234
+ $this->products[$no][$key] = $category;
235
+ }
236
+ break;
237
+ default:
238
+ break;
239
+ }
240
+ }
241
+ }
242
+ }
243
+
244
+ public function get_category_mapping_value($mappingName, $parent)
245
+ {
246
+ $getValue = unserialize(get_option($mappingName));
247
+ $mapp = array_reverse($getValue['cmapping'], true);
248
+ $categories = get_the_terms($parent, 'product_cat');
249
+
250
+ foreach ($categories as $key => $category) {
251
+ if (!empty($mapp[$category->term_id]))
252
+ return $mapp[$category->term_id];
253
+ }
254
+ }
255
+
256
+
257
+ public function mapProductsByRules()
258
+ {
259
+ $products = new Woo_Feed_Products(); //$this->woo_feed_get_visible_product();
260
+ $attributes = $this->rules['attributes'];
261
+ $prefix = $this->rules['prefix'];
262
+ $suffix = $this->rules['suffix'];
263
+ $outputType = $this->rules['output_type'];
264
+ $limit = $this->rules['limit'];
265
+ $merchantAttributes = $this->rules['mattributes'];
266
+ $type = $this->rules['type'];
267
+ $default = $this->rules['default'];
268
+ $feedType = $this->rules['feedType'];
269
+
270
+ // Map Merchant Attributes and Woo Attributes
271
+ if (count($merchantAttributes)) {
272
+ foreach ($merchantAttributes as $key => $attr) {
273
+ if (!empty($attr) && !empty($attributes[$key])) {
274
+ if ($type[$key] == 'attribute') {
275
+ $this->mapping[$attr]['value'] = $attributes[$key];
276
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
277
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
278
+ $this->mapping[$attr]['type'] = $outputType[$key];
279
+ $this->mapping[$attr]['limit'] = $limit[$key];
280
+ }
281
+ } else if (empty($attributes[$key])) {
282
+ if ($type[$key] == 'pattern') {
283
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
284
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
285
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
286
+ $this->mapping[$attr]['type'] = $outputType[$key];
287
+ $this->mapping[$attr]['limit'] = $limit[$key];
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ // Make Product feed array according to mapping
294
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
295
+ $i = 0;
296
+ foreach ($this->mapping as $attr => $rules) {
297
+ if (array_key_exists($rules['value'], $value)) {
298
+
299
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
300
+ // Format According to output type
301
+ if ($rules['type'] == 2) {
302
+ $output = strip_tags($output);
303
+ } elseif ($rules['type'] == 3) {
304
+ $output = absint($output);
305
+ }
306
+ // Format According to output limit
307
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
308
+ $output = substr($output, 0, $rules['limit']);
309
+ }
310
+ $attr = trim($attr);
311
+ $this->products[$key][$attr] = trim($output);
312
+ } else {
313
+ if (!empty($default[$i])) {
314
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
315
+ if ($rules['type'] == 2) {
316
+ $output = strip_tags($output);
317
+ } elseif ($rules['type'] == 3) {
318
+ $output = absint($output);
319
+ }
320
+ // Format According to output limit
321
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
322
+ $output = substr($output, 0, $rules['limit']);
323
+ }
324
+ $attr = trim($attr);
325
+ $this->products[$key][$attr] = trim($output);
326
+ }
327
+ }
328
+ $i++;
329
+ }
330
+ }
331
+
332
+
333
+ return $this->products;
334
+ }
335
+
336
+ public function mapAttribute($from, $to, $cdata = false)
337
+ {
338
+ $i = 0;
339
+ foreach ($this->products as $no => $product) {
340
+ foreach ($product as $key => $value) {
341
+ if ($key == $from) {
342
+ unset($this->products[$no][$from]);
343
+ if ($from == 'images') {
344
+ $this->products[$no][$to] = $value;
345
+ } else {
346
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
347
+ }
348
+
349
+ }
350
+ }
351
+ $i++;
352
+ }
353
+ }
354
+
355
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
356
+ {
357
+ //Make single line for XML
358
+ $c_leader = '';
359
+ $c_footer = '';
360
+ if ($cdata) {
361
+ $c_leader = '<![CDATA[';
362
+ $c_footer = ']]>';
363
+ }
364
+ //Allow force strip HTML
365
+ if ($stripHTML)
366
+ $value = strip_tags(html_entity_decode($value));
367
+
368
+
369
+ if ($utf8encode || $utf8encode == 1) {
370
+ $value = utf8_encode($value);
371
+ $attribute = utf8_encode($attribute);
372
+ }
373
+
374
+
375
+ if (!$cdata)
376
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
377
+
378
+ if (gettype($value) == 'array')
379
+ $value = json_encode($value);
380
+
381
+
382
+ return '
383
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
384
+ }
385
+
386
+ function change_key($array, $old_key, $new_key)
387
+ {
388
+ foreach ($this->products as $no => $product) {
389
+ if (!array_key_exists($old_key, $product))
390
+ return $array;
391
+
392
+ $keys = array_keys($array);
393
+ $keys[array_search($old_key, $keys)] = $new_key;
394
+ }
395
+ return array_combine($keys, $array);
396
+ }
397
+
398
+ public function get_feed_header()
399
+ {
400
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
401
+ <products>';
402
+ $output .= "\n";
403
+ return $output;
404
+ }
405
+
406
+ public function get_feed($items)
407
+ {
408
+ $feed = "";
409
+ $feed .= $this->get_feed_header();
410
+ $feed .= "\n";
411
+ foreach ($items as $item => $products) {
412
+ $feed .= " <" . $this->feedWrapper . ">";
413
+ foreach ($products as $key => $value) {
414
+ if (!empty($value))
415
+ $feed .= $value;
416
+ }
417
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
418
+ }
419
+ $feed .= $this->get_feed_footer();
420
+
421
+ return $feed;
422
+ }
423
+
424
+ public function get_feed_footer()
425
+ {
426
+ $footer = " </products>";
427
+ return $footer;
428
+ }
429
+
430
+ public function get_txt_feed()
431
+ {
432
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
433
+ $headers = array_keys($this->products[0]);
434
+ $feed[] = $headers;
435
+ foreach ($this->products as $no => $product) {
436
+ $row = array();
437
+ foreach ($headers as $key => $header) {
438
+ $row[] = $product[$header];
439
+ }
440
+ $feed[] = $row;
441
+ }
442
+ $str = "";
443
+ foreach ($feed as $fields) {
444
+ $str .= implode("\t", $fields) . "\n";
445
+ }
446
+ return $str;
447
+ }
448
+ return false;
449
+ }
450
+
451
+ public function get_csv_feed()
452
+ {
453
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
454
+ $headers = array_keys($this->products[0]);
455
+ $feed[] = $headers;
456
+ foreach ($this->products as $no => $product) {
457
+ $row = array();
458
+ foreach ($headers as $key => $header) {
459
+ $row[] = $product[$header];
460
+ }
461
+ $feed[] = $row;
462
+ }
463
+
464
+ return $feed;
465
+ }
466
+ return false;
467
+ }
468
  }
includes/feeds/class-woo-feed-shopping.php CHANGED
@@ -1,704 +1,704 @@
1
- <?php
2
-
3
- /**
4
- * Class Shopping
5
- *
6
- * Responsible for processing and generating feed for Shopping.com
7
- *
8
- * @since 1.0.0
9
- * @package Shopping
10
- *
11
- */
12
- class Shopping
13
- {
14
- /**
15
- * This variable is responsible for holding all product attributes and their values
16
- *
17
- * @since 1.0.0
18
- * @var array $products Contains all the product attributes to generate feed
19
- * @access public
20
- */
21
- public $products;
22
-
23
- /**
24
- * This variable is responsible for holding feed configuration form values
25
- *
26
- * @since 1.0.0
27
- * @var Shopping $rules Contains feed configuration form values
28
- * @access public
29
- */
30
- public $rules;
31
-
32
- /**
33
- * This variable is responsible for mapping store attributes to merchant attribute
34
- *
35
- * @since 1.0.0
36
- * @var Shopping $mapping Map store attributes to merchant attribute
37
- * @access public
38
- */
39
- public $mapping;
40
-
41
- /**
42
- * This variable is responsible for generate error logs
43
- *
44
- * @since 1.0.0
45
- * @var Shopping $errorLog Generate error logs
46
- * @access public
47
- */
48
- public $errorLog;
49
-
50
- /**
51
- * This variable is responsible for making error number
52
- *
53
- * @since 1.0.0
54
- * @var Shopping $errorCounter Generate error number
55
- * @access public
56
- */
57
- public $errorCounter;
58
-
59
- /**
60
- * Feed Wrapper text for enclosing each product information
61
- *
62
- * @since 1.0.0
63
- * @var Shopping $feedWrapper Feed Wrapper text
64
- * @access public
65
- */
66
- private $feedWrapper = 'product';
67
-
68
- /**
69
- * Define the core functionality to generate feed.
70
- *
71
- * Set the feed rules. Map products according to the rules and Check required attributes
72
- * and their values according to merchant specification.
73
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
74
- * @since 1.0.0
75
- */
76
- public function __construct($feedRule)
77
- {
78
- $this->errorCounter = 0;
79
- $this->rules = $feedRule;
80
- $this->mapProductsByRules();
81
- $this->formatRequiredField();
82
- $this->filterProductValues();
83
- if ($this->rules['feedType'] == 'xml') {
84
- $this->mapAttributeForXML();
85
- } else {
86
- $this->mapAttributeForCSVTEXT();
87
- }
88
- }
89
-
90
- /**
91
- * Configure merchant attributes for XML feed
92
- */
93
- public function mapAttributeForXML()
94
- {
95
- //Required Attributes
96
- $this->mapAttribute('Unique Merchant SKU', 'Merchant_SKU', true);
97
- $this->mapAttribute('Product Name', 'Product_Name', true);
98
- $this->mapAttribute('Product URL', 'Product_URL', true);
99
- $this->mapAttribute('Image URL', 'Image_URL', true);
100
- $this->mapAttribute('Current Price', 'Current_Price', true);
101
- $this->mapAttribute('Stock Availability', 'Stock_Availability', true);
102
- $this->mapAttribute('Condition', 'Condition', true);
103
- $this->mapAttribute('MPN', 'MPN', false);
104
- $this->mapAttribute('ISBN', 'ISBN', false);
105
- $this->mapAttribute('UPC', 'UPC', false);
106
- $this->mapAttribute('EAN', 'EAN', false);
107
-
108
- //Additional Attributes
109
- $this->mapAttribute('Shipping Rate', 'Shipping_Rate', false);
110
- $this->mapAttribute('Original Price', 'Original_Price', false);
111
- $this->mapAttribute('Coupon Code', 'Coupon_Code', false);
112
- $this->mapAttribute('Coupon Code Description', 'Coupon_Code_Description', true);
113
- $this->mapAttribute('Manufacturer', 'Manufacturer', true);
114
- $this->mapAttribute('Product Description', 'Product_Description', true);
115
- $this->mapAttribute('Product Type', 'Product_Type', true);
116
- $this->mapAttribute('Category', 'Category', true);
117
- $this->mapAttribute('Category ID', 'Category_ID', false);
118
- $this->mapAttribute('Parent SKU', 'Parent_SKU', true);
119
- $this->mapAttribute('Parent Name', 'Parent_Name', true);
120
- $this->mapAttribute('Top Seller Rank', 'Top_Seller_Rank', false);
121
- $this->mapAttribute('Estimated Ship Date', 'Estimated_Ship_Date', true);
122
- $this->mapAttribute('Gender', 'Gender', true);
123
- $this->mapAttribute('Color', 'Color', true);
124
- $this->mapAttribute('Material', 'Material', true);
125
- $this->mapAttribute('Size', 'Size', true);
126
- $this->mapAttribute('Size Unit of Measure', 'Size_Unit_of_Measure', true);
127
- $this->mapAttribute('Age Range', 'Age_Range', true);
128
- $this->mapAttribute('Stock Description', 'Stock_Description', true);
129
- $this->mapAttribute('Product Launch Date', 'Product_Launch_Date', false);
130
- $this->mapAttribute('Product Bullet Point 1', 'Product_Bullet_Point_1', false);
131
- $this->mapAttribute('Product Bullet Point 2', 'Product_Bullet_Point_2', false);
132
- $this->mapAttribute('Product Bullet Point 3', 'Product_Bullet_Point_3', false);
133
- $this->mapAttribute('Product Bullet Point 4', 'Product_Bullet_Point_4', false);
134
- $this->mapAttribute('Product Bullet Point 5', 'Product_Bullet_Point_5', false);
135
- $this->mapAttribute('Alternative Image URL 1', 'Alternative_Image_URL_1', false);
136
- $this->mapAttribute('Alternative Image URL 2', 'Alternative_Image_URL_2', false);
137
- $this->mapAttribute('Alternative Image URL 3', 'Alternative_Image_URL_3', false);
138
- $this->mapAttribute('Alternative Image URL 4', 'Alternative_Image_URL_4', false);
139
- $this->mapAttribute('Alternative Image URL 5', 'Alternative_Image_URL_5', false);
140
- $this->mapAttribute('Mobile URL', 'Mobile_URL', false);
141
- $this->mapAttribute('Related Products', 'Related_Products', false);
142
- $this->mapAttribute('Merchandising Type', 'Merchandising_Type', false);
143
- $this->mapAttribute('Zip Code', 'Zip_Code', false);
144
- $this->mapAttribute('Shipping Weight', 'Shipping_Weight', false);
145
- $this->mapAttribute('Format', 'Format', false);
146
- $this->mapAttribute('Unit Price', 'Unit_Price', false);
147
- $this->mapAttribute('Bundle', 'Bundle', false);
148
- $this->mapAttribute('Software Platform', 'Software_Platform', false);
149
- $this->mapAttribute('Watch Display Type', 'Watch_Display_Type', false);
150
- $this->mapAttribute('Custom', 'Custom', false);
151
-
152
- }
153
-
154
- /**
155
- * Configure merchant attributes for CSV and TXT feed
156
- */
157
- public function mapAttributeForCSVTEXT()
158
- {
159
- if ( is_countable( $this->products ) && count( $this->products ) ) {
160
- foreach ($this->products as $key => $values) {
161
- foreach ($values as $attr => $value) {
162
- // Allow force strip HTML
163
- $value = strip_tags(html_entity_decode($value));
164
- // Encode value and attribute
165
- $value = utf8_encode($value);
166
- $attr = utf8_encode($attr);
167
-
168
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
169
-
170
- if (gettype($value) == 'array')
171
- $value = json_encode($value);
172
-
173
- $this->products[$key][$attr] = $value;
174
- }
175
- }
176
- }
177
- }
178
-
179
- /**
180
- * Check all the required attributes and make error message
181
- */
182
- public function formatRequiredField()
183
- {
184
- foreach ($this->products as $no => $product) {
185
- $upn = 0;
186
- if (array_key_exists('Unique Merchant SKU', $product)) {
187
- $id = $product['Unique Merchant SKU'];
188
- } else {
189
- $id = $product['Product Name'];
190
- }
191
-
192
- if (!array_key_exists('Product Name', $product)) {
193
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product Name</b>] Missing for <b>$id</b>.";
194
- $this->errorCounter++;
195
- }
196
-
197
-
198
- if (!array_key_exists('Unique Merchant SKU', $product)) {
199
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique Merchant SKU</b>] Missing for <b>$id</b>.";
200
- $this->errorCounter++;
201
- }
202
-
203
- if (!array_key_exists('Product URL', $product)) {
204
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
205
- $this->errorCounter++;
206
- }
207
-
208
- if (!array_key_exists('Image URL', $product)) {
209
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
210
- $this->errorCounter++;
211
- }
212
-
213
- if (!array_key_exists('Current Price', $product)) {
214
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current Price</b>] Missing for <b>$id</b>.";
215
- $this->errorCounter++;
216
- }
217
-
218
- if (!array_key_exists('Stock Availability', $product)) {
219
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Stock Availability</b>] Missing for <b>$id</b>.";
220
- $this->errorCounter++;
221
- }
222
-
223
- if (!array_key_exists('Condition', $product)) {
224
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
225
- $this->errorCounter++;
226
- }
227
-
228
- if (!array_key_exists('MPN', $product) && !array_key_exists('ISBN', $product)) {
229
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>MPN / ISBN</b>] Missing for <b>$id</b>.";
230
- $this->errorCounter++;
231
- }
232
- if (!array_key_exists('UPC', $product) && !array_key_exists('EAN', $product)) {
233
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>UPC / EAN</b>] Missing for <b>$id</b>.";
234
- $this->errorCounter++;
235
- }
236
- }
237
- }
238
-
239
- /**
240
- * Return Feed
241
- *
242
- * @return array|bool|string
243
- */
244
- public function returnFinalProduct()
245
- {
246
- if ($this->rules['feedType'] == 'xml') {
247
- return $this->get_feed($this->products);
248
- } elseif ($this->rules['feedType'] == 'txt') {
249
- return $this->get_txt_feed();
250
- } elseif ($this->rules['feedType'] == 'csv') {
251
- return $this->get_csv_feed();
252
- }
253
- return false;
254
- }
255
-
256
-
257
- /**
258
- * Check product's attribute value according to merchant specifications
259
- */
260
- public function filterProductValues()
261
- {
262
- $getProduct = new Woo_Feed_Products();
263
- $products = $this->products;
264
-
265
- foreach ($products as $no => $product) {
266
- if (array_key_exists('Unique Merchant SKU', $product)) {
267
- $id = $product['Unique Merchant SKU'];
268
- } else {
269
- $id = $product['Product Name'];
270
- }
271
- // echo "<pre>";
272
- // print_r($product);
273
- foreach ($product as $key => $value) {
274
- switch ($key) {
275
- case "Product Name":
276
- if (strlen($value) > 90) {
277
- $this->errorLog[$this->errorCounter] = "<b>Product Name</b> is more that 90 character for $id.";
278
- $this->errorCounter++;
279
- }
280
- break;
281
- case "Image URL":
282
- list($width, $height) = getimagesize($value);
283
- if ($width < 150 || $height < 150) {
284
- $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 150px for $id.";
285
- $this->errorCounter++;
286
- }
287
- break;
288
- case "Stock Availability":
289
- if ($value == 'in stock') {
290
- $this->products[$no][$key] = "YES";
291
- } else if ($value == 'out of stock') {
292
- $this->products[$no][$key] = "NO";
293
- }
294
- break;
295
- case "Condition":
296
- if ($value != "New") {
297
- $this->errorLog[$this->errorCounter] = "<b>Condition</b> should be <b>New</b> for $id.";
298
- $this->errorCounter++;
299
- }
300
- break;
301
- case "MPN":
302
- if (strlen($value) != 13 || strlen($value) != 10) {
303
- $this->errorLog[$this->errorCounter] = "Product [<b>MPN</b>] should be 10 and 13 digit for $id.";
304
- $this->errorCounter++;
305
- }
306
- break;
307
- case "ISBN":
308
- if (strlen($value) != 13 || strlen($value) != 10) {
309
- $this->errorLog[$this->errorCounter] = "Product [<b>ISBN</b>] should be 10 and 13 digit for $id.";
310
- $this->errorCounter++;
311
- }
312
- break;
313
- case "UPC":
314
- if (strlen($value) != 12) {
315
- $this->errorLog[$this->errorCounter] = "Product [<b>UPC</b>] should be 12-digit Universal Product Codes for $id.";
316
- $this->errorCounter++;
317
- }
318
- if (!is_numeric($value)) {
319
- $this->errorLog[$this->errorCounter] = "Product [<b>UPC</b>] should be Numeric for $id.";
320
- $this->errorCounter++;
321
- }
322
- break;
323
- case "EAN":
324
- if (strlen($value) != 13) {
325
- $this->errorLog[$this->errorCounter] = "Product [<b>EAN</b>] should be 13-digit EAN for $id.";
326
- $this->errorCounter++;
327
- }
328
- if (!is_numeric($value)) {
329
- $this->errorLog[$this->errorCounter] = "Product [<b>EAN</b>] should be Numeric for $id.";
330
- $this->errorCounter++;
331
- }
332
- break;
333
- case "Coupon Code":
334
- if (strlen($value) > 20) {
335
- $this->errorLog[$this->errorCounter] = "[<b>Coupon Code</b>] is more that 20 character for $id.";
336
- $this->errorCounter++;
337
- }
338
- break;
339
- case "Coupon Code Description":
340
- if (strlen($value) > 150) {
341
- $this->errorLog[$this->errorCounter] = "[<b>Coupon Code Description</b>] is more that 150 character for $id.";
342
- $this->errorCounter++;
343
- }
344
- break;
345
- case "Product Description":
346
- if (strlen($value) > 4000) {
347
- $this->errorLog[$this->errorCounter] = "[<b>Product Description</b>] is more that 150 character for $id.";
348
- $this->errorCounter++;
349
- }
350
- break;
351
- case "Product Type":
352
- $this->products[$no][$key] = str_replace(">", ",", $value);
353
- break;
354
- default:
355
- break;
356
- }
357
- }
358
- }
359
- }
360
-
361
- /**
362
- * Return Dynamic Category Mapping Values by Parent Product Id
363
- *
364
- * @param string $mappingName Category Mapping Name
365
- * @param int $parent Parent id of the product
366
- * @return mixed
367
- */
368
- public function get_category_mapping_value($mappingName, $parent)
369
- {
370
- $getValue = unserialize(get_option($mappingName));
371
- $mapp = array_reverse($getValue['cmapping'], true);
372
- $categories = get_the_terms($parent, 'product_cat');
373
-
374
- foreach ($categories as $key => $category) {
375
- if (!empty($mapp[$category->term_id]))
376
- return $mapp[$category->term_id];
377
- }
378
- return false;
379
- }
380
-
381
- /**
382
- * Configure the feed according to the rules
383
- * @return Shopping
384
- */
385
- public function mapProductsByRules()
386
- {
387
- /**
388
- * Get WooCommerce Products
389
- * @package Woo_Feed_Products
390
- */
391
- $products = new Woo_Feed_Products();
392
-
393
- /**
394
- * This variable contain selected Woo attributes from feed making form
395
- *
396
- * @since 1.0.0
397
- * @var array $attributes contain selected Woo attributes from feed making form
398
- */
399
- $attributes = $this->rules['attributes'];
400
- /**
401
- * This variable contain selected Prefix Values from feed making form
402
- *
403
- * @since 1.0.0
404
- * @var array $prefix Prefix Values from feed making form
405
- */
406
- $prefix = $this->rules['prefix'];
407
- /**
408
- * This variable contain selected Prefix Values from feed making form
409
- *
410
- * @since 1.0.0
411
- * @var array $suffix Suffix Values from feed making form
412
- */
413
- $suffix = $this->rules['suffix'];
414
- /**
415
- * This variable contain selected Output Types from feed making form
416
- *
417
- * @since 1.0.0
418
- * @var array $outputType Output Types from feed making form
419
- */
420
- $outputType = $this->rules['output_type'];
421
-
422
- /**
423
- * This variable contain selected Output Limit from feed making form
424
- *
425
- * @since 1.0.0
426
- * @var array $limit Output Limit from feed making form
427
- */
428
- $limit = $this->rules['limit'];
429
- /**
430
- * This variable contain selected Merchant attributes from feed making form
431
- *
432
- * @since 1.0.0
433
- * @var array $merchantAttributes contain selected Woo attributes from feed making form
434
- */
435
- $merchantAttributes = $this->rules['mattributes'];
436
- /**
437
- * This variable contain attribute types from feed making form
438
- *
439
- * @since 1.0.0
440
- * @var array $type contain attribute types from feed making form
441
- */
442
- $type = $this->rules['type'];
443
- /**
444
- * This variable contain manual output of attribute from feed making form
445
- *
446
- * @since 1.0.0
447
- * @var array $default contain manual output of attribute
448
- */
449
- $default = $this->rules['default'];
450
-
451
- /**
452
- * This variable contain feed type
453
- *
454
- * @since 1.0.0
455
- * @var array $feedType contain feed type
456
- */
457
- $feedType = $this->rules['feedType'];
458
-
459
- // Map Merchant Attributes and Woo Attributes
460
- if (count($merchantAttributes)) {
461
- foreach ($merchantAttributes as $key => $attr) {
462
- if (!empty($attr) && !empty($attributes[$key])) {
463
- if ($type[$key] == 'attribute') {
464
- $this->mapping[$attr]['value'] = $attributes[$key];
465
- $this->mapping[$attr]['suffix'] = $suffix[$key];
466
- $this->mapping[$attr]['prefix'] = $prefix[$key];
467
- $this->mapping[$attr]['type'] = $outputType[$key];
468
- $this->mapping[$attr]['limit'] = $limit[$key];
469
- }
470
- } else if (empty($attributes[$key])) {
471
- if ($type[$key] == 'pattern') {
472
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
473
- $this->mapping[$attr]['suffix'] = $suffix[$key];
474
- $this->mapping[$attr]['prefix'] = $prefix[$key];
475
- $this->mapping[$attr]['type'] = $outputType[$key];
476
- $this->mapping[$attr]['limit'] = $limit[$key];
477
- }
478
- }
479
- }
480
- }
481
-
482
- // Make Product feed array according to mapping
483
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
484
- $i = 0;
485
- foreach ($this->mapping as $attr => $rules) {
486
- if (array_key_exists($rules['value'], $value)) {
487
-
488
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
489
- // Format According to output type
490
- if ($rules['type'] == 2) {
491
- $output = strip_tags($output);
492
- } elseif ($rules['type'] == 3) {
493
- $output = absint($output);
494
- }
495
- // Format According to output limit
496
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
497
- $output = substr($output, 0, $rules['limit']);
498
- }
499
- $attr = trim($attr);
500
- $this->products[$key][$attr] = trim($output);
501
- } else {
502
- if (!empty($default[$i])) {
503
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
504
-
505
- // Format output type
506
- if ($rules['type'] == 2) {
507
- $output = strip_tags($output);
508
- } elseif ($rules['type'] == 3) {
509
- $output = absint($output);
510
- }
511
- // Format According to output limit
512
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
513
- $output = substr($output, 0, $rules['limit']);
514
- }
515
- $attr = trim($attr);
516
- $this->products[$key][$attr] = trim($output);
517
- }
518
- }
519
- $i++;
520
- }
521
- }
522
- return $this->products;
523
- }
524
-
525
- /**
526
- * Change the products old array key and set new
527
- *
528
- * @param string $from Attribute Before
529
- * @param string $to Attribute After
530
- * @param bool $cdata Enclose Feed value
531
- */
532
- public function mapAttribute($from, $to, $cdata = false)
533
- {
534
- $i = 0;
535
- foreach ($this->products as $no => $product) {
536
- foreach ($product as $key => $value) {
537
- if ($key == $from) {
538
- unset($this->products[$no][$from]);
539
- if ($from == 'images') {
540
- $this->products[$no][$to] = $value;
541
- } else {
542
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
543
- }
544
-
545
- }
546
- }
547
- $i++;
548
- }
549
- }
550
-
551
- /**
552
- * Format and Make the XML node for the Feed
553
- *
554
- * @param $attribute
555
- * @param $value
556
- * @param bool $cdata
557
- * @param bool $stripHTML
558
- * @param bool $utf8encode
559
- * @param string $space
560
- * @return string
561
- */
562
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
563
- {
564
- //Make single line for XML
565
- $c_leader = '';
566
- $c_footer = '';
567
- if ($cdata) {
568
- $c_leader = '<![CDATA[';
569
- $c_footer = ']]>';
570
- }
571
- //Allow force strip HTML
572
- if ($stripHTML)
573
- $value = strip_tags(html_entity_decode($value));
574
-
575
-
576
- if ($utf8encode || $utf8encode == 1) {
577
- $value = utf8_encode($value);
578
- $attribute = utf8_encode($attribute);
579
- }
580
-
581
- if (!$cdata)
582
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
583
-
584
- if (gettype($value) == 'array')
585
- $value = json_encode($value);
586
-
587
- return '
588
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
589
- }
590
-
591
- /**
592
- * Responsible to change product array key
593
- *
594
- * @param $array
595
- * @param $old_key
596
- * @param $new_key
597
- * @return array
598
- */
599
- function change_key($array, $old_key, $new_key)
600
- {
601
- foreach ($this->products as $no => $product) {
602
- if (!array_key_exists($old_key, $product))
603
- return $array;
604
-
605
- $keys = array_keys($array);
606
- $keys[array_search($old_key, $keys)] = $new_key;
607
- }
608
- return array_combine($keys, $array);
609
- }
610
-
611
- /**
612
- * Responsible to make XML feed header
613
- * @return string
614
- */
615
- public function get_feed_header()
616
- {
617
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
618
- <products>';
619
- $output .= "\n";
620
- return $output;
621
- }
622
-
623
- /**
624
- * Responsible to make XML feed body
625
- * @var array $items Product array
626
- * @return string
627
- */
628
- public function get_feed($items)
629
- {
630
- $feed = "";
631
- $feed .= $this->get_feed_header();
632
- $feed .= "\n";
633
- foreach ($items as $item => $products) {
634
- $feed .= " <" . $this->feedWrapper . ">";
635
- foreach ($products as $key => $value) {
636
- if (!empty($value))
637
- $feed .= $value;
638
- }
639
- $feed .= "\n </" . $this->feedWrapper . ">\n";
640
- }
641
- $feed .= $this->get_feed_footer();
642
-
643
- return $feed;
644
- }
645
-
646
- /**
647
- * Responsible to make XML feed footer
648
- * @return string
649
- */
650
- public function get_feed_footer()
651
- {
652
- $footer = " </products>";
653
- return $footer;
654
- }
655
-
656
-
657
- /**
658
- * Responsible to make TXT feed
659
- * @return string
660
- */
661
- public function get_txt_feed()
662
- {
663
- if ( is_countable( $this->products ) && count( $this->products ) ) {
664
- $headers = array_keys($this->products[0]);
665
- $feed[] = $headers;
666
- foreach ($this->products as $no => $product) {
667
- $row = array();
668
- foreach ($headers as $key => $header) {
669
- $row[] = $product[$header];
670
- }
671
- $feed[] = $row;
672
- }
673
- $str = "";
674
- foreach ($feed as $fields) {
675
- $str .= implode("\t", $fields) . "\n";
676
- }
677
- return $str;
678
- }
679
- return false;
680
- }
681
-
682
- /**
683
- * Responsible to make CSV feed
684
- * @var $products
685
- * @return string
686
- */
687
- public function get_csv_feed()
688
- {
689
- if ( is_countable( $this->products ) && count( $this->products ) ) {
690
- $headers = array_keys($this->products[0]);
691
- $feed[] = $headers;
692
- foreach ($this->products as $no => $product) {
693
- $row = array();
694
- foreach ($headers as $key => $header) {
695
- $row[] = $product[$header];
696
- }
697
- $feed[] = $row;
698
- }
699
-
700
- return $feed;
701
- }
702
- return false;
703
- }
704
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Shopping
5
+ *
6
+ * Responsible for processing and generating feed for Shopping.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Shopping
10
+ *
11
+ */
12
+ class Shopping
13
+ {
14
+ /**
15
+ * This variable is responsible for holding all product attributes and their values
16
+ *
17
+ * @since 1.0.0
18
+ * @var array $products Contains all the product attributes to generate feed
19
+ * @access public
20
+ */
21
+ public $products;
22
+
23
+ /**
24
+ * This variable is responsible for holding feed configuration form values
25
+ *
26
+ * @since 1.0.0
27
+ * @var Shopping $rules Contains feed configuration form values
28
+ * @access public
29
+ */
30
+ public $rules;
31
+
32
+ /**
33
+ * This variable is responsible for mapping store attributes to merchant attribute
34
+ *
35
+ * @since 1.0.0
36
+ * @var Shopping $mapping Map store attributes to merchant attribute
37
+ * @access public
38
+ */
39
+ public $mapping;
40
+
41
+ /**
42
+ * This variable is responsible for generate error logs
43
+ *
44
+ * @since 1.0.0
45
+ * @var Shopping $errorLog Generate error logs
46
+ * @access public
47
+ */
48
+ public $errorLog;
49
+
50
+ /**
51
+ * This variable is responsible for making error number
52
+ *
53
+ * @since 1.0.0
54
+ * @var Shopping $errorCounter Generate error number
55
+ * @access public
56
+ */
57
+ public $errorCounter;
58
+
59
+ /**
60
+ * Feed Wrapper text for enclosing each product information
61
+ *
62
+ * @since 1.0.0
63
+ * @var Shopping $feedWrapper Feed Wrapper text
64
+ * @access public
65
+ */
66
+ private $feedWrapper = 'product';
67
+
68
+ /**
69
+ * Define the core functionality to generate feed.
70
+ *
71
+ * Set the feed rules. Map products according to the rules and Check required attributes
72
+ * and their values according to merchant specification.
73
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
74
+ * @since 1.0.0
75
+ */
76
+ public function __construct($feedRule)
77
+ {
78
+ $this->errorCounter = 0;
79
+ $this->rules = $feedRule;
80
+ $this->mapProductsByRules();
81
+ $this->formatRequiredField();
82
+ $this->filterProductValues();
83
+ if ($this->rules['feedType'] == 'xml') {
84
+ $this->mapAttributeForXML();
85
+ } else {
86
+ $this->mapAttributeForCSVTEXT();
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Configure merchant attributes for XML feed
92
+ */
93
+ public function mapAttributeForXML()
94
+ {
95
+ //Required Attributes
96
+ $this->mapAttribute('Unique Merchant SKU', 'Merchant_SKU', true);
97
+ $this->mapAttribute('Product Name', 'Product_Name', true);
98
+ $this->mapAttribute('Product URL', 'Product_URL', true);
99
+ $this->mapAttribute('Image URL', 'Image_URL', true);
100
+ $this->mapAttribute('Current Price', 'Current_Price', true);
101
+ $this->mapAttribute('Stock Availability', 'Stock_Availability', true);
102
+ $this->mapAttribute('Condition', 'Condition', true);
103
+ $this->mapAttribute('MPN', 'MPN', false);
104
+ $this->mapAttribute('ISBN', 'ISBN', false);
105
+ $this->mapAttribute('UPC', 'UPC', false);
106
+ $this->mapAttribute('EAN', 'EAN', false);
107
+
108
+ //Additional Attributes
109
+ $this->mapAttribute('Shipping Rate', 'Shipping_Rate', false);
110
+ $this->mapAttribute('Original Price', 'Original_Price', false);
111
+ $this->mapAttribute('Coupon Code', 'Coupon_Code', false);
112
+ $this->mapAttribute('Coupon Code Description', 'Coupon_Code_Description', true);
113
+ $this->mapAttribute('Manufacturer', 'Manufacturer', true);
114
+ $this->mapAttribute('Product Description', 'Product_Description', true);
115
+ $this->mapAttribute('Product Type', 'Product_Type', true);
116
+ $this->mapAttribute('Category', 'Category', true);
117
+ $this->mapAttribute('Category ID', 'Category_ID', false);
118
+ $this->mapAttribute('Parent SKU', 'Parent_SKU', true);
119
+ $this->mapAttribute('Parent Name', 'Parent_Name', true);
120
+ $this->mapAttribute('Top Seller Rank', 'Top_Seller_Rank', false);
121
+ $this->mapAttribute('Estimated Ship Date', 'Estimated_Ship_Date', true);
122
+ $this->mapAttribute('Gender', 'Gender', true);
123
+ $this->mapAttribute('Color', 'Color', true);
124
+ $this->mapAttribute('Material', 'Material', true);
125
+ $this->mapAttribute('Size', 'Size', true);
126
+ $this->mapAttribute('Size Unit of Measure', 'Size_Unit_of_Measure', true);
127
+ $this->mapAttribute('Age Range', 'Age_Range', true);
128
+ $this->mapAttribute('Stock Description', 'Stock_Description', true);
129
+ $this->mapAttribute('Product Launch Date', 'Product_Launch_Date', false);
130
+ $this->mapAttribute('Product Bullet Point 1', 'Product_Bullet_Point_1', false);
131
+ $this->mapAttribute('Product Bullet Point 2', 'Product_Bullet_Point_2', false);
132
+ $this->mapAttribute('Product Bullet Point 3', 'Product_Bullet_Point_3', false);
133
+ $this->mapAttribute('Product Bullet Point 4', 'Product_Bullet_Point_4', false);
134
+ $this->mapAttribute('Product Bullet Point 5', 'Product_Bullet_Point_5', false);
135
+ $this->mapAttribute('Alternative Image URL 1', 'Alternative_Image_URL_1', false);
136
+ $this->mapAttribute('Alternative Image URL 2', 'Alternative_Image_URL_2', false);
137
+ $this->mapAttribute('Alternative Image URL 3', 'Alternative_Image_URL_3', false);
138
+ $this->mapAttribute('Alternative Image URL 4', 'Alternative_Image_URL_4', false);
139
+ $this->mapAttribute('Alternative Image URL 5', 'Alternative_Image_URL_5', false);
140
+ $this->mapAttribute('Mobile URL', 'Mobile_URL', false);
141
+ $this->mapAttribute('Related Products', 'Related_Products', false);
142
+ $this->mapAttribute('Merchandising Type', 'Merchandising_Type', false);
143
+ $this->mapAttribute('Zip Code', 'Zip_Code', false);
144
+ $this->mapAttribute('Shipping Weight', 'Shipping_Weight', false);
145
+ $this->mapAttribute('Format', 'Format', false);
146
+ $this->mapAttribute('Unit Price', 'Unit_Price', false);
147
+ $this->mapAttribute('Bundle', 'Bundle', false);
148
+ $this->mapAttribute('Software Platform', 'Software_Platform', false);
149
+ $this->mapAttribute('Watch Display Type', 'Watch_Display_Type', false);
150
+ $this->mapAttribute('Custom', 'Custom', false);
151
+
152
+ }
153
+
154
+ /**
155
+ * Configure merchant attributes for CSV and TXT feed
156
+ */
157
+ public function mapAttributeForCSVTEXT()
158
+ {
159
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
160
+ foreach ($this->products as $key => $values) {
161
+ foreach ($values as $attr => $value) {
162
+ // Allow force strip HTML
163
+ $value = strip_tags(html_entity_decode($value));
164
+ // Encode value and attribute
165
+ $value = utf8_encode($value);
166
+ $attr = utf8_encode($attr);
167
+
168
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
169
+
170
+ if (gettype($value) == 'array')
171
+ $value = json_encode($value);
172
+
173
+ $this->products[$key][$attr] = $value;
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Check all the required attributes and make error message
181
+ */
182
+ public function formatRequiredField()
183
+ {
184
+ foreach ($this->products as $no => $product) {
185
+ $upn = 0;
186
+ if (array_key_exists('Unique Merchant SKU', $product)) {
187
+ $id = $product['Unique Merchant SKU'];
188
+ } else {
189
+ $id = $product['Product Name'];
190
+ }
191
+
192
+ if (!array_key_exists('Product Name', $product)) {
193
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product Name</b>] Missing for <b>$id</b>.";
194
+ $this->errorCounter++;
195
+ }
196
+
197
+
198
+ if (!array_key_exists('Unique Merchant SKU', $product)) {
199
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique Merchant SKU</b>] Missing for <b>$id</b>.";
200
+ $this->errorCounter++;
201
+ }
202
+
203
+ if (!array_key_exists('Product URL', $product)) {
204
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
205
+ $this->errorCounter++;
206
+ }
207
+
208
+ if (!array_key_exists('Image URL', $product)) {
209
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
210
+ $this->errorCounter++;
211
+ }
212
+
213
+ if (!array_key_exists('Current Price', $product)) {
214
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current Price</b>] Missing for <b>$id</b>.";
215
+ $this->errorCounter++;
216
+ }
217
+
218
+ if (!array_key_exists('Stock Availability', $product)) {
219
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Stock Availability</b>] Missing for <b>$id</b>.";
220
+ $this->errorCounter++;
221
+ }
222
+
223
+ if (!array_key_exists('Condition', $product)) {
224
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
225
+ $this->errorCounter++;
226
+ }
227
+
228
+ if (!array_key_exists('MPN', $product) && !array_key_exists('ISBN', $product)) {
229
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>MPN / ISBN</b>] Missing for <b>$id</b>.";
230
+ $this->errorCounter++;
231
+ }
232
+ if (!array_key_exists('UPC', $product) && !array_key_exists('EAN', $product)) {
233
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>UPC / EAN</b>] Missing for <b>$id</b>.";
234
+ $this->errorCounter++;
235
+ }
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Return Feed
241
+ *
242
+ * @return array|bool|string
243
+ */
244
+ public function returnFinalProduct()
245
+ {
246
+ if ($this->rules['feedType'] == 'xml') {
247
+ return $this->get_feed($this->products);
248
+ } elseif ($this->rules['feedType'] == 'txt') {
249
+ return $this->get_txt_feed();
250
+ } elseif ($this->rules['feedType'] == 'csv') {
251
+ return $this->get_csv_feed();
252
+ }
253
+ return false;
254
+ }
255
+
256
+
257
+ /**
258
+ * Check product's attribute value according to merchant specifications
259
+ */
260
+ public function filterProductValues()
261
+ {
262
+ $getProduct = new Woo_Feed_Products();
263
+ $products = $this->products;
264
+
265
+ foreach ($products as $no => $product) {
266
+ if (array_key_exists('Unique Merchant SKU', $product)) {
267
+ $id = $product['Unique Merchant SKU'];
268
+ } else {
269
+ $id = $product['Product Name'];
270
+ }
271
+ // echo "<pre>";
272
+ // print_r($product);
273
+ foreach ($product as $key => $value) {
274
+ switch ($key) {
275
+ case "Product Name":
276
+ if (strlen($value) > 90) {
277
+ $this->errorLog[$this->errorCounter] = "<b>Product Name</b> is more that 90 character for $id.";
278
+ $this->errorCounter++;
279
+ }
280
+ break;
281
+ case "Image URL":
282
+ list($width, $height) = getimagesize($value);
283
+ if ($width < 150 || $height < 150) {
284
+ $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 150px for $id.";
285
+ $this->errorCounter++;
286
+ }
287
+ break;
288
+ case "Stock Availability":
289
+ if ($value == 'in stock') {
290
+ $this->products[$no][$key] = "YES";
291
+ } else if ($value == 'out of stock') {
292
+ $this->products[$no][$key] = "NO";
293
+ }
294
+ break;
295
+ case "Condition":
296
+ if ($value != "New") {
297
+ $this->errorLog[$this->errorCounter] = "<b>Condition</b> should be <b>New</b> for $id.";
298
+ $this->errorCounter++;
299
+ }
300
+ break;
301
+ case "MPN":
302
+ if (strlen($value) != 13 || strlen($value) != 10) {
303
+ $this->errorLog[$this->errorCounter] = "Product [<b>MPN</b>] should be 10 and 13 digit for $id.";
304
+ $this->errorCounter++;
305
+ }
306
+ break;
307
+ case "ISBN":
308
+ if (strlen($value) != 13 || strlen($value) != 10) {
309
+ $this->errorLog[$this->errorCounter] = "Product [<b>ISBN</b>] should be 10 and 13 digit for $id.";
310
+ $this->errorCounter++;
311
+ }
312
+ break;
313
+ case "UPC":
314
+ if (strlen($value) != 12) {
315
+ $this->errorLog[$this->errorCounter] = "Product [<b>UPC</b>] should be 12-digit Universal Product Codes for $id.";
316
+ $this->errorCounter++;
317
+ }
318
+ if (!is_numeric($value)) {
319
+ $this->errorLog[$this->errorCounter] = "Product [<b>UPC</b>] should be Numeric for $id.";
320
+ $this->errorCounter++;
321
+ }
322
+ break;
323
+ case "EAN":
324
+ if (strlen($value) != 13) {
325
+ $this->errorLog[$this->errorCounter] = "Product [<b>EAN</b>] should be 13-digit EAN for $id.";
326
+ $this->errorCounter++;
327
+ }
328
+ if (!is_numeric($value)) {
329
+ $this->errorLog[$this->errorCounter] = "Product [<b>EAN</b>] should be Numeric for $id.";
330
+ $this->errorCounter++;
331
+ }
332
+ break;
333
+ case "Coupon Code":
334
+ if (strlen($value) > 20) {
335
+ $this->errorLog[$this->errorCounter] = "[<b>Coupon Code</b>] is more that 20 character for $id.";
336
+ $this->errorCounter++;
337
+ }
338
+ break;
339
+ case "Coupon Code Description":
340
+ if (strlen($value) > 150) {
341
+ $this->errorLog[$this->errorCounter] = "[<b>Coupon Code Description</b>] is more that 150 character for $id.";
342
+ $this->errorCounter++;
343
+ }
344
+ break;
345
+ case "Product Description":
346
+ if (strlen($value) > 4000) {
347
+ $this->errorLog[$this->errorCounter] = "[<b>Product Description</b>] is more that 150 character for $id.";
348
+ $this->errorCounter++;
349
+ }
350
+ break;
351
+ case "Product Type":
352
+ $this->products[$no][$key] = str_replace(">", ",", $value);
353
+ break;
354
+ default:
355
+ break;
356
+ }
357
+ }
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Return Dynamic Category Mapping Values by Parent Product Id
363
+ *
364
+ * @param string $mappingName Category Mapping Name
365
+ * @param int $parent Parent id of the product
366
+ * @return mixed
367
+ */
368
+ public function get_category_mapping_value($mappingName, $parent)
369
+ {
370
+ $getValue = unserialize(get_option($mappingName));
371
+ $mapp = array_reverse($getValue['cmapping'], true);
372
+ $categories = get_the_terms($parent, 'product_cat');
373
+
374
+ foreach ($categories as $key => $category) {
375
+ if (!empty($mapp[$category->term_id]))
376
+ return $mapp[$category->term_id];
377
+ }
378
+ return false;
379
+ }
380
+
381
+ /**
382
+ * Configure the feed according to the rules
383
+ * @return Shopping
384
+ */
385
+ public function mapProductsByRules()
386
+ {
387
+ /**
388
+ * Get WooCommerce Products
389
+ * @package Woo_Feed_Products
390
+ */
391
+ $products = new Woo_Feed_Products();
392
+
393
+ /**
394
+ * This variable contain selected Woo attributes from feed making form
395
+ *
396
+ * @since 1.0.0
397
+ * @var array $attributes contain selected Woo attributes from feed making form
398
+ */
399
+ $attributes = $this->rules['attributes'];
400
+ /**
401
+ * This variable contain selected Prefix Values from feed making form
402
+ *
403
+ * @since 1.0.0
404
+ * @var array $prefix Prefix Values from feed making form
405
+ */
406
+ $prefix = $this->rules['prefix'];
407
+ /**
408
+ * This variable contain selected Prefix Values from feed making form
409
+ *
410
+ * @since 1.0.0
411
+ * @var array $suffix Suffix Values from feed making form
412
+ */
413
+ $suffix = $this->rules['suffix'];
414
+ /**
415
+ * This variable contain selected Output Types from feed making form
416
+ *
417
+ * @since 1.0.0
418
+ * @var array $outputType Output Types from feed making form
419
+ */
420
+ $outputType = $this->rules['output_type'];
421
+
422
+ /**
423
+ * This variable contain selected Output Limit from feed making form
424
+ *
425
+ * @since 1.0.0
426
+ * @var array $limit Output Limit from feed making form
427
+ */
428
+ $limit = $this->rules['limit'];
429
+ /**
430
+ * This variable contain selected Merchant attributes from feed making form
431
+ *
432
+ * @since 1.0.0
433
+ * @var array $merchantAttributes contain selected Woo attributes from feed making form
434
+ */
435
+ $merchantAttributes = $this->rules['mattributes'];
436
+ /**
437
+ * This variable contain attribute types from feed making form
438
+ *
439
+ * @since 1.0.0
440
+ * @var array $type contain attribute types from feed making form
441
+ */
442
+ $type = $this->rules['type'];
443
+ /**
444
+ * This variable contain manual output of attribute from feed making form
445
+ *
446
+ * @since 1.0.0
447
+ * @var array $default contain manual output of attribute
448
+ */
449
+ $default = $this->rules['default'];
450
+
451
+ /**
452
+ * This variable contain feed type
453
+ *
454
+ * @since 1.0.0
455
+ * @var array $feedType contain feed type
456
+ */
457
+ $feedType = $this->rules['feedType'];
458
+
459
+ // Map Merchant Attributes and Woo Attributes
460
+ if (count($merchantAttributes)) {
461
+ foreach ($merchantAttributes as $key => $attr) {
462
+ if (!empty($attr) && !empty($attributes[$key])) {
463
+ if ($type[$key] == 'attribute') {
464
+ $this->mapping[$attr]['value'] = $attributes[$key];
465
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
466
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
467
+ $this->mapping[$attr]['type'] = $outputType[$key];
468
+ $this->mapping[$attr]['limit'] = $limit[$key];
469
+ }
470
+ } else if (empty($attributes[$key])) {
471
+ if ($type[$key] == 'pattern') {
472
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
473
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
474
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
475
+ $this->mapping[$attr]['type'] = $outputType[$key];
476
+ $this->mapping[$attr]['limit'] = $limit[$key];
477
+ }
478
+ }
479
+ }
480
+ }
481
+
482
+ // Make Product feed array according to mapping
483
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
484
+ $i = 0;
485
+ foreach ($this->mapping as $attr => $rules) {
486
+ if (array_key_exists($rules['value'], $value)) {
487
+
488
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
489
+ // Format According to output type
490
+ if ($rules['type'] == 2) {
491
+ $output = strip_tags($output);
492
+ } elseif ($rules['type'] == 3) {
493
+ $output = absint($output);
494
+ }
495
+ // Format According to output limit
496
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
497
+ $output = substr($output, 0, $rules['limit']);
498
+ }
499
+ $attr = trim($attr);
500
+ $this->products[$key][$attr] = trim($output);
501
+ } else {
502
+ if (!empty($default[$i])) {
503
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
504
+
505
+ // Format output type
506
+ if ($rules['type'] == 2) {
507
+ $output = strip_tags($output);
508
+ } elseif ($rules['type'] == 3) {
509
+ $output = absint($output);
510
+ }
511
+ // Format According to output limit
512
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
513
+ $output = substr($output, 0, $rules['limit']);
514
+ }
515
+ $attr = trim($attr);
516
+ $this->products[$key][$attr] = trim($output);
517
+ }
518
+ }
519
+ $i++;
520
+ }
521
+ }
522
+ return $this->products;
523
+ }
524
+
525
+ /**
526
+ * Change the products old array key and set new
527
+ *
528
+ * @param string $from Attribute Before
529
+ * @param string $to Attribute After
530
+ * @param bool $cdata Enclose Feed value
531
+ */
532
+ public function mapAttribute($from, $to, $cdata = false)
533
+ {
534
+ $i = 0;
535
+ foreach ($this->products as $no => $product) {
536
+ foreach ($product as $key => $value) {
537
+ if ($key == $from) {
538
+ unset($this->products[$no][$from]);
539
+ if ($from == 'images') {
540
+ $this->products[$no][$to] = $value;
541
+ } else {
542
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
543
+ }
544
+
545
+ }
546
+ }
547
+ $i++;
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Format and Make the XML node for the Feed
553
+ *
554
+ * @param $attribute
555
+ * @param $value
556
+ * @param bool $cdata
557
+ * @param bool $stripHTML
558
+ * @param bool $utf8encode
559
+ * @param string $space
560
+ * @return string
561
+ */
562
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
563
+ {
564
+ //Make single line for XML
565
+ $c_leader = '';
566
+ $c_footer = '';
567
+ if ($cdata) {
568
+ $c_leader = '<![CDATA[';
569
+ $c_footer = ']]>';
570
+ }
571
+ //Allow force strip HTML
572
+ if ($stripHTML)
573
+ $value = strip_tags(html_entity_decode($value));
574
+
575
+
576
+ if ($utf8encode || $utf8encode == 1) {
577
+ $value = utf8_encode($value);
578
+ $attribute = utf8_encode($attribute);
579
+ }
580
+
581
+ if (!$cdata)
582
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
583
+
584
+ if (gettype($value) == 'array')
585
+ $value = json_encode($value);
586
+
587
+ return '
588
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
589
+ }
590
+
591
+ /**
592
+ * Responsible to change product array key
593
+ *
594
+ * @param $array
595
+ * @param $old_key
596
+ * @param $new_key
597
+ * @return array
598
+ */
599
+ function change_key($array, $old_key, $new_key)
600
+ {
601
+ foreach ($this->products as $no => $product) {
602
+ if (!array_key_exists($old_key, $product))
603
+ return $array;
604
+
605
+ $keys = array_keys($array);
606
+ $keys[array_search($old_key, $keys)] = $new_key;
607
+ }
608
+ return array_combine($keys, $array);
609
+ }
610
+
611
+ /**
612
+ * Responsible to make XML feed header
613
+ * @return string
614
+ */
615
+ public function get_feed_header()
616
+ {
617
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
618
+ <products>';
619
+ $output .= "\n";
620
+ return $output;
621
+ }
622
+
623
+ /**
624
+ * Responsible to make XML feed body
625
+ * @var array $items Product array
626
+ * @return string
627
+ */
628
+ public function get_feed($items)
629
+ {
630
+ $feed = "";
631
+ $feed .= $this->get_feed_header();
632
+ $feed .= "\n";
633
+ foreach ($items as $item => $products) {
634
+ $feed .= " <" . $this->feedWrapper . ">";
635
+ foreach ($products as $key => $value) {
636
+ if (!empty($value))
637
+ $feed .= $value;
638
+ }
639
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
640
+ }
641
+ $feed .= $this->get_feed_footer();
642
+
643
+ return $feed;
644
+ }
645
+
646
+ /**
647
+ * Responsible to make XML feed footer
648
+ * @return string
649
+ */
650
+ public function get_feed_footer()
651
+ {
652
+ $footer = " </products>";
653
+ return $footer;
654
+ }
655
+
656
+
657
+ /**
658
+ * Responsible to make TXT feed
659
+ * @return string
660
+ */
661
+ public function get_txt_feed()
662
+ {
663
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
664
+ $headers = array_keys($this->products[0]);
665
+ $feed[] = $headers;
666
+ foreach ($this->products as $no => $product) {
667
+ $row = array();
668
+ foreach ($headers as $key => $header) {
669
+ $row[] = $product[$header];
670
+ }
671
+ $feed[] = $row;
672
+ }
673
+ $str = "";
674
+ foreach ($feed as $fields) {
675
+ $str .= implode("\t", $fields) . "\n";
676
+ }
677
+ return $str;
678
+ }
679
+ return false;
680
+ }
681
+
682
+ /**
683
+ * Responsible to make CSV feed
684
+ * @var $products
685
+ * @return string
686
+ */
687
+ public function get_csv_feed()
688
+ {
689
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
690
+ $headers = array_keys($this->products[0]);
691
+ $feed[] = $headers;
692
+ foreach ($this->products as $no => $product) {
693
+ $row = array();
694
+ foreach ($headers as $key => $header) {
695
+ $row[] = $product[$header];
696
+ }
697
+ $feed[] = $row;
698
+ }
699
+
700
+ return $feed;
701
+ }
702
+ return false;
703
+ }
704
  }
includes/feeds/class-woo-feed-shopzilla.php CHANGED
@@ -1,668 +1,668 @@
1
- <?php
2
-
3
- /**
4
- * Class Shopzilla
5
- *
6
- * Responsible for processing and generating feed for Shopzilla.com
7
- *
8
- * @since 1.0.0
9
- * @package Shopzilla
10
- *
11
- */
12
- class Shopzilla
13
- {
14
-
15
- /**
16
- * This variable is responsible for holding all product attributes and their values
17
- *
18
- * @since 1.0.0
19
- * @var array $products Contains all the product attributes to generate feed
20
- * @access public
21
- */
22
- public $products;
23
-
24
- /**
25
- * This variable is responsible for holding feed configuration form values
26
- *
27
- * @since 1.0.0
28
- * @var Shopzilla $rules Contains feed configuration form values
29
- * @access public
30
- */
31
- public $rules;
32
-
33
- /**
34
- * This variable is responsible for mapping store attributes to merchant attribute
35
- *
36
- * @since 1.0.0
37
- * @var Shopzilla $mapping Map store attributes to merchant attribute
38
- * @access public
39
- */
40
- public $mapping;
41
-
42
- /**
43
- * This variable is responsible for generate error logs
44
- *
45
- * @since 1.0.0
46
- * @var Shopzilla $errorLog Generate error logs
47
- * @access public
48
- */
49
- public $errorLog;
50
-
51
- /**
52
- * This variable is responsible for making error number
53
- *
54
- * @since 1.0.0
55
- * @var Shopzilla $errorCounter Generate error number
56
- * @access public
57
- */
58
- public $errorCounter;
59
-
60
- /**
61
- * Feed Wrapper text for enclosing each product information
62
- *
63
- * @since 1.0.0
64
- * @var Shopzilla $feedWrapper Feed Wrapper text
65
- * @access public
66
- */
67
- private $feedWrapper;
68
-
69
- /**
70
- * Define the core functionality to generate feed.
71
- *
72
- * Set the feed rules. Map products according to the rules and Check required attributes
73
- * and their values according to merchant specification.
74
- * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
- * @since 1.0.0
76
- */
77
- public function __construct($feedRule)
78
- {
79
- $this->feedWrapper = 'product';
80
- $this->errorCounter = 0;
81
- $this->rules = $feedRule;
82
- $this->mapProductsByRules();
83
- $this->formatRequiredField();
84
- $this->filterProductValues();
85
- if ($this->rules['feedType'] == 'xml') {
86
- $this->mapAttributeForXML();
87
- } else {
88
- $this->mapAttributeForCSVTEXT();
89
- }
90
- }
91
-
92
- /**
93
- * Configure merchant attributes for XML feed
94
- */
95
- public function mapAttributeForXML()
96
- {
97
- //Basic product information
98
-
99
- if ( is_countable( $this->products ) && count( $this->products ) ) {
100
- foreach ($this->products as $key => $values) {
101
- foreach ($values as $attr => $value) {
102
- $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
103
- }
104
- }
105
- }
106
- }
107
-
108
- /**
109
- * Configure merchant attributes for CSV and TXT feed
110
- */
111
- public function mapAttributeForCSVTEXT()
112
- {
113
- //Basic product information
114
-
115
- if ( is_countable( $this->products ) && count( $this->products ) ) {
116
- foreach ($this->products as $key => $values) {
117
- foreach ($values as $attr => $value) {
118
- //Allow force strip HTML
119
- $value = strip_tags(html_entity_decode($value));
120
- if ($attr != 'Category') {
121
- $value = utf8_encode($value);
122
- $attr = utf8_encode($attr);
123
-
124
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
-
126
- if (gettype($value) == 'array')
127
- $value = json_encode($value);
128
- }
129
-
130
- $this->products[$key][$attr] = $value;
131
- }
132
- }
133
- }
134
- }
135
-
136
- /**
137
- * Check all the required attributes and make error message
138
- */
139
- public function formatRequiredField()
140
- {
141
- foreach ($this->products as $no => $product) {
142
- $upn = 0;
143
- if (array_key_exists('Unique ID', $product)) {
144
- $id = $product['Unique ID'];
145
- } else {
146
- $id = $product['Title'];
147
- }
148
-
149
- if (!array_key_exists('Unique ID', $product)) {
150
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique ID</b>] Missing for <b>$id</b>.";
151
- $this->errorCounter++;
152
- }
153
-
154
-
155
- if (!array_key_exists('Title', $product)) {
156
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
157
- $this->errorCounter++;
158
- }
159
-
160
- if (!array_key_exists('Description', $product)) {
161
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
162
- $this->errorCounter++;
163
- }
164
-
165
- if (!array_key_exists('Category', $product)) {
166
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Category</b>] Missing for <b>$id</b>.";
167
- $this->errorCounter++;
168
- }
169
-
170
- if (!array_key_exists('Product URL', $product)) {
171
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
172
- $this->errorCounter++;
173
- }
174
-
175
- if (!array_key_exists('Image URL', $product)) {
176
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
177
- $this->errorCounter++;
178
- }
179
-
180
- if (!array_key_exists('Condition', $product)) {
181
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
182
- $this->errorCounter++;
183
- }
184
-
185
- if (!array_key_exists('Availability', $product)) {
186
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Availability</b>] Missing for <b>$id</b>.";
187
- $this->errorCounter++;
188
- }
189
-
190
- if (!array_key_exists('Current price', $product)) {
191
- $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current price</b>] Missing for <b>$id</b>.";
192
- $this->errorCounter++;
193
- }
194
- }
195
- }
196
-
197
- /**
198
- * Return Feed
199
- *
200
- * @return array|bool|string
201
- */
202
- public function returnFinalProduct()
203
- {
204
- if ($this->rules['feedType'] == 'xml') {
205
- return $this->get_feed($this->products);
206
- } elseif ($this->rules['feedType'] == 'txt') {
207
- return $this->get_txt_feed();
208
- } elseif ($this->rules['feedType'] == 'csv') {
209
- return $this->get_csv_feed();
210
- }
211
- return false;
212
- }
213
-
214
- /**
215
- * Check product's attribute value according to merchant specifications
216
- */
217
- public function filterProductValues()
218
- {
219
- $getProduct = new Woo_Feed_Products();
220
- $products = $this->products;
221
-
222
- foreach ($products as $no => $product) {
223
- if (array_key_exists('Unique ID', $product)) {
224
- $id = $product['Unique ID'];
225
- } else {
226
- $id = $product['Title'];
227
- }
228
- // echo "<pre>";
229
- // print_r($product);
230
- foreach ($product as $key => $value) {
231
- switch ($key) {
232
- case "Unique ID":
233
- if (strlen($value) > 100) {
234
- $this->errorLog[$this->errorCounter] = "[<b>Unique ID</b>] is more that 100 character for $id.";
235
- $this->errorCounter++;
236
- }
237
- break;
238
- case "Title":
239
- if (strlen($value) > 1000) {
240
- $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 1000 character for $id.";
241
- $this->errorCounter++;
242
- }
243
- break;
244
- case "Description":
245
- if (strlen($value) > 3000) {
246
- $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 3000 character for $id.";
247
- $this->errorCounter++;
248
- }
249
- break;
250
- case "Category":
251
- if (strlen($value) > 1000) {
252
- $this->errorLog[$this->errorCounter] = "[<b>Category</b>] is more that 1000 character for $id.";
253
- $this->errorCounter++;
254
- }
255
- break;
256
- case "Product URL":
257
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
258
- $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] must start with http:// or https:// for $id.";
259
- $this->errorCounter++;
260
- }
261
-
262
- if (strlen($value) > 2000) {
263
- $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] is more that 2000 character for $id.";
264
- $this->errorCounter++;
265
- }
266
-
267
- break;
268
- case "Image URL":
269
- if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
270
- $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] must start with http:// or https:// for $id.";
271
- $this->errorCounter++;
272
- }
273
-
274
- if (strlen($value) > 2000) {
275
- $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] is more that 2000 character for $id.";
276
- $this->errorCounter++;
277
- }
278
-
279
- list($width, $height) = getimagesize($value);
280
- if ($width < 450 || $height < 450) {
281
- $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 450px for $id.";
282
- $this->errorCounter++;
283
- }
284
-
285
- break;
286
- case "Condition":
287
- $condition = array("New", "Used", "Refurbished", "Open Box", "OEM");
288
- if (!array_key_exists($value, $condition)) {
289
- $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] = $value is acceptable for $id.";
290
- $this->errorCounter++;
291
- }
292
- break;
293
- case "Availability":
294
- $availability = array("In Stock", "Out of Stock", "Available for Order", "PreOrder");
295
- if ($value == 'in stock') {
296
- $this->products[$no][$key] = "In Stock";
297
- } else {
298
- $this->products[$no][$key] = "Out of Stock";
299
- }
300
-
301
- if (!array_key_exists($this->products[$no][$key], $availability)) {
302
- $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] = $value is acceptable for $id.";
303
- $this->errorCounter++;
304
- }
305
- break;
306
- case "Current price":
307
- if (!is_numeric($value)) {
308
- $this->errorLog[$this->errorCounter] = "[<b>Current price</b>] should be numeric for $id.";
309
- $this->errorCounter++;
310
- }
311
- break;
312
- case "Original Price":
313
- if (!is_numeric($value)) {
314
- $this->errorLog[$this->errorCounter] = "[<b>Original price</b>] should be numeric for $id.";
315
- $this->errorCounter++;
316
- }
317
- break;
318
- default:
319
- break;
320
- }
321
- }
322
- }
323
- }
324
-
325
- /**
326
- * Return Dynamic Category Mapping Values by Parent Product Id
327
- *
328
- * @param string $mappingName Category Mapping Name
329
- * @param int $parent Parent id of the product
330
- * @return mixed
331
- */
332
- public function get_category_mapping_value($mappingName, $parent)
333
- {
334
- $getValue = unserialize(get_option($mappingName));
335
- $mapp = array_reverse($getValue['cmapping'], true);
336
- $categories = get_the_terms($parent, 'product_cat');
337
-
338
- foreach ($categories as $key => $category) {
339
- if (!empty($mapp[$category->term_id]))
340
- return $mapp[$category->term_id];
341
- }
342
- return false;
343
- }
344
-
345
- /**
346
- * Configure the feed according to the rules
347
- * @return Shopping
348
- */
349
- public function mapProductsByRules()
350
- {
351
- /**
352
- * Get WooCommerce Products
353
- * @package Woo_Feed_Products
354
- */
355
- $products = new Woo_Feed_Products();
356
-
357
- /**
358
- * This variable contain selected Woo attributes from feed making form
359
- *
360
- * @since 1.0.0
361
- * @var array $attributes contain selected Woo attributes from feed making form
362
- */
363
- $attributes = $this->rules['attributes'];
364
- /**
365
- * This variable contain selected Prefix Values from feed making form
366
- *
367
- * @since 1.0.0
368
- * @var array $prefix Prefix Values from feed making form
369
- */
370
- $prefix = $this->rules['prefix'];
371
- /**
372
- * This variable contain selected Prefix Values from feed making form
373
- *
374
- * @since 1.0.0
375
- * @var array $suffix Suffix Values from feed making form
376
- */
377
- $suffix = $this->rules['suffix'];
378
- /**
379
- * This variable contain selected Output Types from feed making form
380
- *
381
- * @since 1.0.0
382
- * @var array $outputType Output Types from feed making form
383
- */
384
- $outputType = $this->rules['output_type'];
385
-
386
- /**
387
- * This variable contain selected Output Limit from feed making form
388
- *
389
- * @since 1.0.0
390
- * @var array $limit Output Limit from feed making form
391
- */
392
- $limit = $this->rules['limit'];
393
- /**
394
- * This variable contain selected Merchant attributes from feed making form
395
- *
396
- * @since 1.0.0
397
- * @var array $merchantAttributes contain selected Woo attributes from feed making form
398
- */
399
- $merchantAttributes = $this->rules['mattributes'];
400
- /**
401
- * This variable contain attribute types from feed making form
402
- *
403
- * @since 1.0.0
404
- * @var array $type contain attribute types from feed making form
405
- */
406
- $type = $this->rules['type'];
407
- /**
408
- * This variable contain manual output of attribute from feed making form
409
- *
410
- * @since 1.0.0
411
- * @var array $default contain manual output of attribute
412
- */
413
- $default = $this->rules['default'];
414
-
415
- /**
416
- * This variable contain feed type
417
- *
418
- * @since 1.0.0
419
- * @var array $feedType contain feed type
420
- */
421
- $feedType = $this->rules['feedType'];
422
-
423
- // Map Merchant Attributes and Woo Attributes
424
- if (count($merchantAttributes)) {
425
- foreach ($merchantAttributes as $key => $attr) {
426
- if (!empty($attr) && !empty($attributes[$key])) {
427
- if ($type[$key] == 'attribute') {
428
- $this->mapping[$attr]['value'] = $attributes[$key];
429
- $this->mapping[$attr]['suffix'] = $suffix[$key];
430
- $this->mapping[$attr]['prefix'] = $prefix[$key];
431
- $this->mapping[$attr]['type'] = $outputType[$key];
432
- $this->mapping[$attr]['limit'] = $limit[$key];
433
- }
434
- } else if (empty($attributes[$key])) {
435
- if ($type[$key] == 'pattern') {
436
- $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
437
- $this->mapping[$attr]['suffix'] = $suffix[$key];
438
- $this->mapping[$attr]['prefix'] = $prefix[$key];
439
- $this->mapping[$attr]['type'] = $outputType[$key];
440
- $this->mapping[$attr]['limit'] = $limit[$key];
441
- }
442
- }
443
- }
444
- }
445
-
446
- // Make Product feed array according to mapping
447
- foreach ($products->woo_feed_get_visible_product() as $key => $value) {
448
- $i = 0;
449
- foreach ($this->mapping as $attr => $rules) {
450
- if (array_key_exists($rules['value'], $value)) {
451
-
452
- $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
453
- // Format According to output type
454
- if ($rules['type'] == 2) {
455
- $output = strip_tags($output);
456
- } elseif ($rules['type'] == 3) {
457
- $output = absint($output);
458
- }
459
- // Format According to output limit
460
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
461
- $output = substr($output, 0, $rules['limit']);
462
- }
463
- $attr = trim($attr);
464
- $this->products[$key][$attr] = trim($output);
465
- } else {
466
- if (!empty($default[$i])) {
467
- $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
468
- if ($rules['type'] == 2) {
469
- $output = strip_tags($output);
470
- } elseif ($rules['type'] == 3) {
471
- $output = absint($output);
472
- }
473
- // Format According to output limit
474
- if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
475
- $output = substr($output, 0, $rules['limit']);
476
- }
477
- $attr = trim($attr);
478
- $this->products[$key][$attr] = trim($output);
479
- }
480
- }
481
- $i++;
482
- }
483
- }
484
-
485
-
486
- return $this->products;
487
- }
488
-
489
- /**
490
- * Change the products old array key and set new
491
- *
492
- * @param string $from Attribute Before
493
- * @param string $to Attribute After
494
- * @param bool $cdata Enclose Feed value
495
- */
496
- public function mapAttribute($from, $to, $cdata = false)
497
- {
498
- $i = 0;
499
- foreach ($this->products as $no => $product) {
500
- foreach ($product as $key => $value) {
501
- if ($key == $from) {
502
- unset($this->products[$no][$from]);
503
- if ($from == 'images') {
504
- $this->products[$no][$to] = $value;
505
- } else {
506
- $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
507
- }
508
-
509
- }
510
- }
511
- $i++;
512
- }
513
- }
514
-
515
- /**
516
- * Format and Make the XML node for the Feed
517
- *
518
- * @param $attribute
519
- * @param $value
520
- * @param bool $cdata
521
- * @param bool $stripHTML
522
- * @param bool $utf8encode
523
- * @param string $space
524
- * @return string
525
- */
526
- function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
527
- {
528
- //Make single line for XML
529
- $c_leader = '';
530
- $c_footer = '';
531
- if ($cdata) {
532
- $c_leader = '<![CDATA[';
533
- $c_footer = ']]>';
534
- }
535
- //Allow force strip HTML
536
- if ($stripHTML)
537
- $value = strip_tags(html_entity_decode($value));
538
-
539
-
540
- if ($utf8encode || $utf8encode == 1) {
541
- $value = utf8_encode($value);
542
- $attribute = utf8_encode($attribute);
543
- }
544
-
545
-
546
- if (!$cdata)
547
- $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
548
-
549
- if (gettype($value) == 'array')
550
- $value = json_encode($value);
551
-
552
-
553
- return '
554
- ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
555
- }
556
-
557
- /**
558
- * Responsible to change product array key
559
- *
560
- * @param $array
561
- * @param $old_key
562
- * @param $new_key
563
- * @return array
564
- */
565
- function change_key($array, $old_key, $new_key)
566
- {
567
- foreach ($this->products as $no => $product) {
568
- if (!array_key_exists($old_key, $product))
569
- return $array;
570
-
571
- $keys = array_keys($array);
572
- $keys[array_search($old_key, $keys)] = $new_key;
573
- }
574
- return array_combine($keys, $array);
575
- }
576
-
577
- /**
578
- * Responsible to make XML feed header
579
- * @return string
580
- */
581
- public function get_feed_header()
582
- {
583
- $output = '<?xml version="1.0" encoding="UTF-8" ?>
584
- <products>';
585
- $output .= "\n";
586
- return $output;
587
- }
588
-
589
- /**
590
- * Responsible to make XML feed body
591
- * @var array $item Product array
592
- * @return string
593
- */
594
- public function get_feed($items)
595
- {
596
- $feed = "";
597
- $feed .= $this->get_feed_header();
598
- $feed .= "\n";
599
- foreach ($items as $item => $products) {
600
- $feed .= " <" . $this->feedWrapper . ">";
601
- foreach ($products as $key => $value) {
602
- if (!empty($value))
603
- $feed .= $value;
604
- }
605
- $feed .= "\n </" . $this->feedWrapper . ">\n";
606
- }
607
- $feed .= $this->get_feed_footer();
608
-
609
- return $feed;
610
- }
611
-
612
- /**
613
- * Responsible to make XML feed footer
614
- * @return string
615
- */
616
- public function get_feed_footer()
617
- {
618
- $footer = " </products>";
619
- return $footer;
620
- }
621
-
622
- /**
623
- * Responsible to make TXT feed
624
- * @return string
625
- */
626
- public function get_txt_feed()
627
- {
628
- if ( is_countable( $this->products ) && count( $this->products ) ) {
629
- $headers = array_keys($this->products[0]);
630
- $feed[] = $headers;
631
- foreach ($this->products as $no => $product) {
632
- $row = array();
633
- foreach ($headers as $key => $header) {
634
- $row[] = $product[$header];
635
- }
636
- $feed[] = $row;
637
- }
638
- $str = "";
639
- foreach ($feed as $fields) {
640
- $str .= implode("\t", $fields) . "\n";
641
- }
642
- return $str;
643
- }
644
- return false;
645
- }
646
-
647
- /**
648
- * Responsible to make CSV feed
649
- * @return string
650
- */
651
- public function get_csv_feed()
652
- {
653
- if ( is_countable( $this->products ) && count( $this->products ) ) {
654
- $headers = array_keys($this->products[0]);
655
- $feed[] = $headers;
656
- foreach ($this->products as $no => $product) {
657
- $row = array();
658
- foreach ($headers as $key => $header) {
659
- $row[] = $product[$header];
660
- }
661
- $feed[] = $row;
662
- }
663
-
664
- return $feed;
665
- }
666
- return false;
667
- }
668
  }
1
+ <?php
2
+
3
+ /**
4
+ * Class Shopzilla
5
+ *
6
+ * Responsible for processing and generating feed for Shopzilla.com
7
+ *
8
+ * @since 1.0.0
9
+ * @package Shopzilla
10
+ *
11
+ */
12
+ class Shopzilla
13
+ {
14
+
15
+ /**
16
+ * This variable is responsible for holding all product attributes and their values
17
+ *
18
+ * @since 1.0.0
19
+ * @var array $products Contains all the product attributes to generate feed
20
+ * @access public
21
+ */
22
+ public $products;
23
+
24
+ /**
25
+ * This variable is responsible for holding feed configuration form values
26
+ *
27
+ * @since 1.0.0
28
+ * @var Shopzilla $rules Contains feed configuration form values
29
+ * @access public
30
+ */
31
+ public $rules;
32
+
33
+ /**
34
+ * This variable is responsible for mapping store attributes to merchant attribute
35
+ *
36
+ * @since 1.0.0
37
+ * @var Shopzilla $mapping Map store attributes to merchant attribute
38
+ * @access public
39
+ */
40
+ public $mapping;
41
+
42
+ /**
43
+ * This variable is responsible for generate error logs
44
+ *
45
+ * @since 1.0.0
46
+ * @var Shopzilla $errorLog Generate error logs
47
+ * @access public
48
+ */
49
+ public $errorLog;
50
+
51
+ /**
52
+ * This variable is responsible for making error number
53
+ *
54
+ * @since 1.0.0
55
+ * @var Shopzilla $errorCounter Generate error number
56
+ * @access public
57
+ */
58
+ public $errorCounter;
59
+
60
+ /**
61
+ * Feed Wrapper text for enclosing each product information
62
+ *
63
+ * @since 1.0.0
64
+ * @var Shopzilla $feedWrapper Feed Wrapper text
65
+ * @access public
66
+ */
67
+ private $feedWrapper;
68
+
69
+ /**
70
+ * Define the core functionality to generate feed.
71
+ *
72
+ * Set the feed rules. Map products according to the rules and Check required attributes
73
+ * and their values according to merchant specification.
74
+ * @var Woo_Generate_Feed $feedRule Contain Feed Configuration
75
+ * @since 1.0.0
76
+ */
77
+ public function __construct($feedRule)
78
+ {
79
+ $this->feedWrapper = 'product';
80
+ $this->errorCounter = 0;
81
+ $this->rules = $feedRule;
82
+ $this->mapProductsByRules();
83
+ $this->formatRequiredField();
84
+ $this->filterProductValues();
85
+ if ($this->rules['feedType'] == 'xml') {
86
+ $this->mapAttributeForXML();
87
+ } else {
88
+ $this->mapAttributeForCSVTEXT();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Configure merchant attributes for XML feed
94
+ */
95
+ public function mapAttributeForXML()
96
+ {
97
+ //Basic product information
98
+
99
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
100
+ foreach ($this->products as $key => $values) {
101
+ foreach ($values as $attr => $value) {
102
+ $this->products[$key][$attr] = $this->formatXMLLine($attr, $value, true, true, true);
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Configure merchant attributes for CSV and TXT feed
110
+ */
111
+ public function mapAttributeForCSVTEXT()
112
+ {
113
+ //Basic product information
114
+
115
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
116
+ foreach ($this->products as $key => $values) {
117
+ foreach ($values as $attr => $value) {
118
+ //Allow force strip HTML
119
+ $value = strip_tags(html_entity_decode($value));
120
+ if ($attr != 'Category') {
121
+ $value = utf8_encode($value);
122
+ $attr = utf8_encode($attr);
123
+
124
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
125
+
126
+ if (gettype($value) == 'array')
127
+ $value = json_encode($value);
128
+ }
129
+
130
+ $this->products[$key][$attr] = $value;
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Check all the required attributes and make error message
138
+ */
139
+ public function formatRequiredField()
140
+ {
141
+ foreach ($this->products as $no => $product) {
142
+ $upn = 0;
143
+ if (array_key_exists('Unique ID', $product)) {
144
+ $id = $product['Unique ID'];
145
+ } else {
146
+ $id = $product['Title'];
147
+ }
148
+
149
+ if (!array_key_exists('Unique ID', $product)) {
150
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Unique ID</b>] Missing for <b>$id</b>.";
151
+ $this->errorCounter++;
152
+ }
153
+
154
+
155
+ if (!array_key_exists('Title', $product)) {
156
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Title</b>] Missing for <b>$id</b>.";
157
+ $this->errorCounter++;
158
+ }
159
+
160
+ if (!array_key_exists('Description', $product)) {
161
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Description</b>] Missing for <b>$id</b>.";
162
+ $this->errorCounter++;
163
+ }
164
+
165
+ if (!array_key_exists('Category', $product)) {
166
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Category</b>] Missing for <b>$id</b>.";
167
+ $this->errorCounter++;
168
+ }
169
+
170
+ if (!array_key_exists('Product URL', $product)) {
171
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Product URL</b>] Missing for <b>$id</b>.";
172
+ $this->errorCounter++;
173
+ }
174
+
175
+ if (!array_key_exists('Image URL', $product)) {
176
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Image URL</b>] Missing for <b>$id</b>.";
177
+ $this->errorCounter++;
178
+ }
179
+
180
+ if (!array_key_exists('Condition', $product)) {
181
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Condition</b>] Missing for <b>$id</b>.";
182
+ $this->errorCounter++;
183
+ }
184
+
185
+ if (!array_key_exists('Availability', $product)) {
186
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Availability</b>] Missing for <b>$id</b>.";
187
+ $this->errorCounter++;
188
+ }
189
+
190
+ if (!array_key_exists('Current price', $product)) {
191
+ $this->errorLog[$this->errorCounter] = "Required Attribute [<b>Current price</b>] Missing for <b>$id</b>.";
192
+ $this->errorCounter++;
193
+ }
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Return Feed
199
+ *
200
+ * @return array|bool|string
201
+ */
202
+ public function returnFinalProduct()
203
+ {
204
+ if ($this->rules['feedType'] == 'xml') {
205
+ return $this->get_feed($this->products);
206
+ } elseif ($this->rules['feedType'] == 'txt') {
207
+ return $this->get_txt_feed();
208
+ } elseif ($this->rules['feedType'] == 'csv') {
209
+ return $this->get_csv_feed();
210
+ }
211
+ return false;
212
+ }
213
+
214
+ /**
215
+ * Check product's attribute value according to merchant specifications
216
+ */
217
+ public function filterProductValues()
218
+ {
219
+ $getProduct = new Woo_Feed_Products();
220
+ $products = $this->products;
221
+
222
+ foreach ($products as $no => $product) {
223
+ if (array_key_exists('Unique ID', $product)) {
224
+ $id = $product['Unique ID'];
225
+ } else {
226
+ $id = $product['Title'];
227
+ }
228
+ // echo "<pre>";
229
+ // print_r($product);
230
+ foreach ($product as $key => $value) {
231
+ switch ($key) {
232
+ case "Unique ID":
233
+ if (strlen($value) > 100) {
234
+ $this->errorLog[$this->errorCounter] = "[<b>Unique ID</b>] is more that 100 character for $id.";
235
+ $this->errorCounter++;
236
+ }
237
+ break;
238
+ case "Title":
239
+ if (strlen($value) > 1000) {
240
+ $this->errorLog[$this->errorCounter] = "[<b>Title</b>] is more that 1000 character for $id.";
241
+ $this->errorCounter++;
242
+ }
243
+ break;
244
+ case "Description":
245
+ if (strlen($value) > 3000) {
246
+ $this->errorLog[$this->errorCounter] = "[<b>Description</b>] is more that 3000 character for $id.";
247
+ $this->errorCounter++;
248
+ }
249
+ break;
250
+ case "Category":
251
+ if (strlen($value) > 1000) {
252
+ $this->errorLog[$this->errorCounter] = "[<b>Category</b>] is more that 1000 character for $id.";
253
+ $this->errorCounter++;
254
+ }
255
+ break;
256
+ case "Product URL":
257
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
258
+ $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] must start with http:// or https:// for $id.";
259
+ $this->errorCounter++;
260
+ }
261
+
262
+ if (strlen($value) > 2000) {
263
+ $this->errorLog[$this->errorCounter] = "[<b>Product URL</b>] is more that 2000 character for $id.";
264
+ $this->errorCounter++;
265
+ }
266
+
267
+ break;
268
+ case "Image URL":
269
+ if (strpos($value, 'http://') == false || strpos($value, 'https://') == false) {
270
+ $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] must start with http:// or https:// for $id.";
271
+ $this->errorCounter++;
272
+ }
273
+
274
+ if (strlen($value) > 2000) {
275
+ $this->errorLog[$this->errorCounter] = "[<b>Image URL</b>] is more that 2000 character for $id.";
276
+ $this->errorCounter++;
277
+ }
278
+
279
+ list($width, $height) = getimagesize($value);
280
+ if ($width < 450 || $height < 450) {
281
+ $this->errorLog[$this->errorCounter] = "<b>Image Width and Height</b> should be more that 450px for $id.";
282
+ $this->errorCounter++;
283
+ }
284
+
285
+ break;
286
+ case "Condition":
287
+ $condition = array("New", "Used", "Refurbished", "Open Box", "OEM");
288
+ if (!array_key_exists($value, $condition)) {
289
+ $this->errorLog[$this->errorCounter] = "[<b>Condition</b>] = $value is acceptable for $id.";
290
+ $this->errorCounter++;
291
+ }
292
+ break;
293
+ case "Availability":
294
+ $availability = array("In Stock", "Out of Stock", "Available for Order", "PreOrder");
295
+ if ($value == 'in stock') {
296
+ $this->products[$no][$key] = "In Stock";
297
+ } else {
298
+ $this->products[$no][$key] = "Out of Stock";
299
+ }
300
+
301
+ if (!array_key_exists($this->products[$no][$key], $availability)) {
302
+ $this->errorLog[$this->errorCounter] = "[<b>Availability</b>] = $value is acceptable for $id.";
303
+ $this->errorCounter++;
304
+ }
305
+ break;
306
+ case "Current price":
307
+ if (!is_numeric($value)) {
308
+ $this->errorLog[$this->errorCounter] = "[<b>Current price</b>] should be numeric for $id.";
309
+ $this->errorCounter++;
310
+ }
311
+ break;
312
+ case "Original Price":
313
+ if (!is_numeric($value)) {
314
+ $this->errorLog[$this->errorCounter] = "[<b>Original price</b>] should be numeric for $id.";
315
+ $this->errorCounter++;
316
+ }
317
+ break;
318
+ default:
319
+ break;
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Return Dynamic Category Mapping Values by Parent Product Id
327
+ *
328
+ * @param string $mappingName Category Mapping Name
329
+ * @param int $parent Parent id of the product
330
+ * @return mixed
331
+ */
332
+ public function get_category_mapping_value($mappingName, $parent)
333
+ {
334
+ $getValue = unserialize(get_option($mappingName));
335
+ $mapp = array_reverse($getValue['cmapping'], true);
336
+ $categories = get_the_terms($parent, 'product_cat');
337
+
338
+ foreach ($categories as $key => $category) {
339
+ if (!empty($mapp[$category->term_id]))
340
+ return $mapp[$category->term_id];
341
+ }
342
+ return false;
343
+ }
344
+
345
+ /**
346
+ * Configure the feed according to the rules
347
+ * @return Shopping
348
+ */
349
+ public function mapProductsByRules()
350
+ {
351
+ /**
352
+ * Get WooCommerce Products
353
+ * @package Woo_Feed_Products
354
+ */
355
+ $products = new Woo_Feed_Products();
356
+
357
+ /**
358
+ * This variable contain selected Woo attributes from feed making form
359
+ *
360
+ * @since 1.0.0
361
+ * @var array $attributes contain selected Woo attributes from feed making form
362
+ */
363
+ $attributes = $this->rules['attributes'];
364
+ /**
365
+ * This variable contain selected Prefix Values from feed making form
366
+ *
367
+ * @since 1.0.0
368
+ * @var array $prefix Prefix Values from feed making form
369
+ */
370
+ $prefix = $this->rules['prefix'];
371
+ /**
372
+ * This variable contain selected Prefix Values from feed making form
373
+ *
374
+ * @since 1.0.0
375
+ * @var array $suffix Suffix Values from feed making form
376
+ */
377
+ $suffix = $this->rules['suffix'];
378
+ /**
379
+ * This variable contain selected Output Types from feed making form
380
+ *
381
+ * @since 1.0.0
382
+ * @var array $outputType Output Types from feed making form
383
+ */
384
+ $outputType = $this->rules['output_type'];
385
+
386
+ /**
387
+ * This variable contain selected Output Limit from feed making form
388
+ *
389
+ * @since 1.0.0
390
+ * @var array $limit Output Limit from feed making form
391
+ */
392
+ $limit = $this->rules['limit'];
393
+ /**
394
+ * This variable contain selected Merchant attributes from feed making form
395
+ *
396
+ * @since 1.0.0
397
+ * @var array $merchantAttributes contain selected Woo attributes from feed making form
398
+ */
399
+ $merchantAttributes = $this->rules['mattributes'];
400
+ /**
401
+ * This variable contain attribute types from feed making form
402
+ *
403
+ * @since 1.0.0
404
+ * @var array $type contain attribute types from feed making form
405
+ */
406
+ $type = $this->rules['type'];
407
+ /**
408
+ * This variable contain manual output of attribute from feed making form
409
+ *
410
+ * @since 1.0.0
411
+ * @var array $default contain manual output of attribute
412
+ */
413
+ $default = $this->rules['default'];
414
+
415
+ /**
416
+ * This variable contain feed type
417
+ *
418
+ * @since 1.0.0
419
+ * @var array $feedType contain feed type
420
+ */
421
+ $feedType = $this->rules['feedType'];
422
+
423
+ // Map Merchant Attributes and Woo Attributes
424
+ if (count($merchantAttributes)) {
425
+ foreach ($merchantAttributes as $key => $attr) {
426
+ if (!empty($attr) && !empty($attributes[$key])) {
427
+ if ($type[$key] == 'attribute') {
428
+ $this->mapping[$attr]['value'] = $attributes[$key];
429
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
430
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
431
+ $this->mapping[$attr]['type'] = $outputType[$key];
432
+ $this->mapping[$attr]['limit'] = $limit[$key];
433
+ }
434
+ } else if (empty($attributes[$key])) {
435
+ if ($type[$key] == 'pattern') {
436
+ $this->mapping[$attr]['value'] = "wf_pattern_$default[$key]";
437
+ $this->mapping[$attr]['suffix'] = $suffix[$key];
438
+ $this->mapping[$attr]['prefix'] = $prefix[$key];
439
+ $this->mapping[$attr]['type'] = $outputType[$key];
440
+ $this->mapping[$attr]['limit'] = $limit[$key];
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ // Make Product feed array according to mapping
447
+ foreach ($products->woo_feed_get_visible_product() as $key => $value) {
448
+ $i = 0;
449
+ foreach ($this->mapping as $attr => $rules) {
450
+ if (array_key_exists($rules['value'], $value)) {
451
+
452
+ $output = $rules['prefix'] . $value[$rules['value']] . " " . $rules['suffix'];
453
+ // Format According to output type
454
+ if ($rules['type'] == 2) {
455
+ $output = strip_tags($output);
456
+ } elseif ($rules['type'] == 3) {
457
+ $output = absint($output);
458
+ }
459
+ // Format According to output limit
460
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
461
+ $output = substr($output, 0, $rules['limit']);
462
+ }
463
+ $attr = trim($attr);
464
+ $this->products[$key][$attr] = trim($output);
465
+ } else {
466
+ if (!empty($default[$i])) {
467
+ $output = $rules['prefix'] . str_replace("wf_pattern_", "", $rules['value']) . " " . $rules['suffix'];
468
+ if ($rules['type'] == 2) {
469
+ $output = strip_tags($output);
470
+ } elseif ($rules['type'] == 3) {
471
+ $output = absint($output);
472
+ }
473
+ // Format According to output limit
474
+ if (!empty($rules['limit']) && is_numeric($rules['limit'])) {
475
+ $output = substr($output, 0, $rules['limit']);
476
+ }
477
+ $attr = trim($attr);
478
+ $this->products[$key][$attr] = trim($output);
479
+ }
480
+ }
481
+ $i++;
482
+ }
483
+ }
484
+
485
+
486
+ return $this->products;
487
+ }
488
+
489
+ /**
490
+ * Change the products old array key and set new
491
+ *
492
+ * @param string $from Attribute Before
493
+ * @param string $to Attribute After
494
+ * @param bool $cdata Enclose Feed value
495
+ */
496
+ public function mapAttribute($from, $to, $cdata = false)
497
+ {
498
+ $i = 0;
499
+ foreach ($this->products as $no => $product) {
500
+ foreach ($product as $key => $value) {
501
+ if ($key == $from) {
502
+ unset($this->products[$no][$from]);
503
+ if ($from == 'images') {
504
+ $this->products[$no][$to] = $value;
505
+ } else {
506
+ $this->products[$no][$to] = $this->formatXMLLine($to, $value, $cdata, true, true);
507
+ }
508
+
509
+ }
510
+ }
511
+ $i++;
512
+ }
513
+ }
514
+
515
+ /**
516
+ * Format and Make the XML node for the Feed
517
+ *
518
+ * @param $attribute
519
+ * @param $value
520
+ * @param bool $cdata
521
+ * @param bool $stripHTML
522
+ * @param bool $utf8encode
523
+ * @param string $space
524
+ * @return string
525
+ */
526
+ function formatXMLLine($attribute, $value, $cdata = false, $stripHTML = true, $utf8encode = true, $space = ' ')
527
+ {
528
+ //Make single line for XML
529
+ $c_leader = '';
530
+ $c_footer = '';
531
+ if ($cdata) {
532
+ $c_leader = '<![CDATA[';
533
+ $c_footer = ']]>';
534
+ }
535
+ //Allow force strip HTML
536
+ if ($stripHTML)
537
+ $value = strip_tags(html_entity_decode($value));
538
+
539
+
540
+ if ($utf8encode || $utf8encode == 1) {
541
+ $value = utf8_encode($value);
542
+ $attribute = utf8_encode($attribute);
543
+ }
544
+
545
+
546
+ if (!$cdata)
547
+ $value = htmlentities($value, ENT_QUOTES, 'UTF-8');
548
+
549
+ if (gettype($value) == 'array')
550
+ $value = json_encode($value);
551
+
552
+
553
+ return '
554
+ ' . $space . '<' . $attribute . '>' . $c_leader . $value . $c_footer . '</' . $attribute . '>';
555
+ }
556
+
557
+ /**
558
+ * Responsible to change product array key
559
+ *
560
+ * @param $array
561
+ * @param $old_key
562
+ * @param $new_key
563
+ * @return array
564
+ */
565
+ function change_key($array, $old_key, $new_key)
566
+ {
567
+ foreach ($this->products as $no => $product) {
568
+ if (!array_key_exists($old_key, $product))
569
+ return $array;
570
+
571
+ $keys = array_keys($array);
572
+ $keys[array_search($old_key, $keys)] = $new_key;
573
+ }
574
+ return array_combine($keys, $array);
575
+ }
576
+
577
+ /**
578
+ * Responsible to make XML feed header
579
+ * @return string
580
+ */
581
+ public function get_feed_header()
582
+ {
583
+ $output = '<?xml version="1.0" encoding="UTF-8" ?>
584
+ <products>';
585
+ $output .= "\n";
586
+ return $output;
587
+ }
588
+
589
+ /**
590
+ * Responsible to make XML feed body
591
+ * @var array $item Product array
592
+ * @return string
593
+ */
594
+ public function get_feed($items)
595
+ {
596
+ $feed = "";
597
+ $feed .= $this->get_feed_header();
598
+ $feed .= "\n";
599
+ foreach ($items as $item => $products) {
600
+ $feed .= " <" . $this->feedWrapper . ">";
601
+ foreach ($products as $key => $value) {
602
+ if (!empty($value))
603
+ $feed .= $value;
604
+ }
605
+ $feed .= "\n </" . $this->feedWrapper . ">\n";
606
+ }
607
+ $feed .= $this->get_feed_footer();
608
+
609
+ return $feed;
610
+ }
611
+
612
+ /**
613
+ * Responsible to make XML feed footer
614
+ * @return string
615
+ */
616
+ public function get_feed_footer()
617
+ {
618
+ $footer = " </products>";
619
+ return $footer;
620
+ }
621
+
622
+ /**
623
+ * Responsible to make TXT feed
624
+ * @return string
625
+ */
626
+ public function get_txt_feed()
627
+ {
628
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
629
+ $headers = array_keys($this->products[0]);
630
+ $feed[] = $headers;
631
+ foreach ($this->products as $no => $product) {
632
+ $row = array();
633
+ foreach ($headers as $key => $header) {
634
+ $row[] = $product[$header];
635
+ }
636
+ $feed[] = $row;
637
+ }
638
+ $str = "";
639
+ foreach ($feed as $fields) {
640
+ $str .= implode("\t", $fields) . "\n";
641
+ }
642
+ return $str;
643
+ }
644
+ return false;
645
+ }
646
+
647
+ /**
648
+ * Responsible to make CSV feed
649
+ * @return string
650
+ */
651
+ public function get_csv_feed()
652
+ {
653
+ if ( is_countable( $this->products ) && count( $this->products ) ) {
654
+ $headers = array_keys($this->products[0]);
655
+ $feed[] = $headers;
656
+ foreach ($this->products as $no => $product) {
657
+ $row = array();
658
+ foreach ($headers as $key => $header) {
659
+ $row[] = $product[$header];
660
+ }
661
+ $feed[] = $row;
662
+ }
663
+
664
+ return $feed;
665
+ }
666
+ return false;
667
+ }
668
  }
includes/helper.php CHANGED
@@ -45,10 +45,10 @@ if( ! function_exists( 'wooFeed_deactivate_plugins' ) ) {
45
  * @param mixed $network_wide Whether to deactivate the plugin for all sites in the network.
46
  * @return void
47
  */
48
- function wooFeed_deactivate_plugins( $plugins, $silent = false, $network_wide = null ) {
49
- if ( ! function_exists( 'deactivate_plugins' ) ) require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
50
- deactivate_plugins( $plugins, $silent, $network_wide );
51
- }
52
  }
53
  if( ! function_exists( 'wooFeed_is_supported_php' ) ) {
54
  /**
@@ -56,15 +56,38 @@ if( ! function_exists( 'wooFeed_is_supported_php' ) ) {
56
  * @since 3.1.41
57
  * @return bool
58
  */
59
- function wooFeed_is_supported_php(){
60
- // PHP version need to be => WOO_FEED_MIN_PHP_VERSION
61
- return ! version_compare( PHP_VERSION, WOO_FEED_MIN_PHP_VERSION, '<' );
62
- }
63
  }
64
  if( ! function_exists( 'wooFeed_check_WC' ) ) {
65
- function wooFeed_check_WC(){
66
- return class_exists( 'WooCommerce', false );
67
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
  if( ! function_exists( 'wooFeed_Admin_Notices' ) ) {
70
  /**
@@ -73,19 +96,31 @@ if( ! function_exists( 'wooFeed_Admin_Notices' ) ) {
73
  * @since 3.1.41
74
  * @return void
75
  */
76
- function wooFeed_Admin_Notices(){
77
- //@TODO Refactor this function with admin message class
78
- // WC Missing Notice..
79
- if ( ! wooFeed_check_WC() ) {
80
- $plugin_url = self_admin_url( 'plugin-install.php?s=woocommerce&tab=search&type=term' );
81
- /** @noinspection HtmlUnknownTarget */
82
- $plugin_url = sprintf( '<a href="%s">%s</a>', $plugin_url, esc_html__( 'WooCommerce', 'woocommerce' ) );
83
- $plugin_name = sprintf( '<code>%s</code>', esc_html__( 'WooCommerce Product Feed', 'woo-feed' ) );
84
- $wc_name = sprintf( '<code>%s</code>', esc_html__( 'WooCommerce', 'woocommerce' ) );
85
- $message = sprintf( esc_html__( '%s requires %s to be installed and active. You can installed/activate %s here.', 'woo-feed' ), $plugin_name, $wc_name, $plugin_url );
86
- printf( '<div class="error"><p><strong>%1$s</strong></p></div>', $message );
87
- }
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
90
  if( ! function_exists( 'checkFTP_connection' ) ) {
91
  /**
@@ -107,4 +142,72 @@ if( ! function_exists( 'checkSFTP_connection' ) ) {
107
  return ( extension_loaded('ssh2' ) || function_exists( 'ssh2_connect' ) );
108
  }
109
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  // End of file helper.php
45
  * @param mixed $network_wide Whether to deactivate the plugin for all sites in the network.
46
  * @return void
47
  */
48
+ function wooFeed_deactivate_plugins( $plugins, $silent = false, $network_wide = null ) {
49
+ if ( ! function_exists( 'deactivate_plugins' ) ) require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
50
+ deactivate_plugins( $plugins, $silent, $network_wide );
51
+ }
52
  }
53
  if( ! function_exists( 'wooFeed_is_supported_php' ) ) {
54
  /**
56
  * @since 3.1.41
57
  * @return bool
58
  */
59
+ function wooFeed_is_supported_php(){
60
+ // PHP version need to be => WOO_FEED_MIN_PHP_VERSION
61
+ return ! version_compare( PHP_VERSION, WOO_FEED_MIN_PHP_VERSION, '<' );
62
+ }
63
  }
64
  if( ! function_exists( 'wooFeed_check_WC' ) ) {
65
+ function wooFeed_check_WC(){
66
+ return class_exists( 'WooCommerce', false );
67
+ }
68
+ }
69
+ if( ! function_exists( 'wooFeed_is_WC_supported' ) ) {
70
+ function wooFeed_is_WC_supported() {
71
+ // Ensure WC is loaded before checking version
72
+ return ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, WOO_FEED_MIN_WC_VERSION, '>=' ) );
73
+ }
74
+ }
75
+ if( ! function_exists( 'woo_feed_wc_version_check' ) ) {
76
+ /**
77
+ * Check WooCommerce Version
78
+ * @param string $version
79
+ * @return bool
80
+ */
81
+ function woo_feed_wc_version_check( $version = '3.0' ) {
82
+ // calling this function too early (before wc loaded) will not give correct output
83
+ if ( defined( WC_VERSION ) ) {
84
+ if ( version_compare( WC_VERSION, $version, ">=" ) ) {
85
+ return true;
86
+ }
87
+ }
88
+ return false;
89
+ }
90
+
91
  }
92
  if( ! function_exists( 'wooFeed_Admin_Notices' ) ) {
93
  /**
96
  * @since 3.1.41
97
  * @return void
98
  */
99
+ function wooFeed_Admin_Notices(){
100
+ //@TODO Refactor this function with admin message class
101
+ // WC Missing Notice..
102
+ if ( ! wooFeed_check_WC() ) {
103
+ $plugin_url = self_admin_url( 'plugin-install.php?s=woocommerce&tab=search&type=term' );
104
+ /** @noinspection HtmlUnknownTarget */
105
+ $plugin_url = sprintf( '<a href="%s">%s</a>', $plugin_url, esc_html__( 'WooCommerce', 'woocommerce' ) );
106
+ $plugin_name = sprintf( '<code>%s</code>', esc_html__( 'WooCommerce Product Feed', 'woo-feed' ) );
107
+ $wc_name = sprintf( '<code>%s</code>', esc_html__( 'WooCommerce', 'woocommerce' ) );
108
+ $message = sprintf( esc_html__( '%s requires %s to be installed and active. You can installed/activate %s here.', 'woo-feed' ), $plugin_name, $wc_name, $plugin_url );
109
+ printf( '<div class="error"><p><strong>%1$s</strong></p></div>', $message );
110
+ }
111
+ if( wooFeed_check_WC() && ! wooFeed_is_WC_supported() ) {
112
+ $plugin_url = self_admin_url( 'plugin-install.php?s=woocommerce&tab=search&type=term' );
113
+ $wcVersion = defined( 'WC_VERSION' ) ? '<code>'.WC_VERSION.'</code>' : '<code>UNKNOWN</code>';
114
+ $minVersion = '<code>'.WOO_FEED_MIN_WC_VERSION.'</code>';
115
+ /** @noinspection HtmlUnknownTarget */
116
+ $plugin_url = sprintf( '<a href="%s">%s</a>', $plugin_url, esc_html__( 'WooCommerce', 'woocommerce' ) );
117
+ $plugin_name = sprintf( '<code>%s</code>', esc_html__( 'WooCommerce Product Feed', 'woo-feed' ) );
118
+ $wc_name = sprintf( '<code>%s</code>', esc_html__( 'WooCommerce', 'woocommerce' ) );
119
+ $message = sprintf( esc_html__( '%1$s requires %2$s version %3$s or above and %4$s found. Please upgrade %2$s to the latest version here %5$s', 'woo-feed' ),
120
+ $plugin_name, $wc_name, $minVersion, $wcVersion, $plugin_url );
121
+ printf( '<div class="error"><p><strong>%1$s</strong></p></div>', $message );
122
+ }
123
+ }
124
  }
125
  if( ! function_exists( 'checkFTP_connection' ) ) {
126
  /**
142
  return ( extension_loaded('ssh2' ) || function_exists( 'ssh2_connect' ) );
143
  }
144
  }
145
+ if( ! function_exists( 'array_splice_assoc' ) ) {
146
+ /**
147
+ * Array Splice Associative Array
148
+ * @see https://www.php.net/manual/en/function.array-splice.php#111204
149
+ * @param array $input
150
+ * @param int $offset
151
+ * @param int $length
152
+ * @param array $replacement
153
+ *
154
+ * @return array
155
+ */
156
+ function array_splice_assoc( $input, $offset, $length, $replacement) {
157
+ $replacement = (array) $replacement;
158
+ $key_indices = array_flip(array_keys($input));
159
+ if (isset($input[$offset]) && is_string($offset)) {
160
+ $offset = $key_indices[$offset];
161
+ }
162
+ if (isset($input[$length]) && is_string($length)) {
163
+ $length = $key_indices[$length] - $offset;
164
+ }
165
+
166
+ $input = array_slice($input, 0, $offset, TRUE)
167
+ + $replacement
168
+ + array_slice($input, $offset + $length, NULL, TRUE);
169
+ return $input;
170
+ }
171
+ }
172
+ // Pro functions...
173
+ if( ! function_exists( 'woo_feed_get_variable_visibility_options' ) ) {
174
+ /**
175
+ * Get Variable visibility options for feed editor
176
+ * @return array
177
+ */
178
+ function woo_feed_get_variable_visibility_options(){
179
+ return apply_filters( 'woo_feed_variable_visibility_options', [
180
+ 'n' => __( 'Only Variable Products', 'woo-feed' ),
181
+ 'y' => __( 'Only Product Variations', 'woo-feed' ),
182
+ 'both' => __( 'Both Variable Products and Product Variations', 'woo-feed' ),
183
+ ] );
184
+ }
185
+ }
186
+ if( ! function_exists( 'woo_feed_get_variable_price_options' ) ) {
187
+ /**
188
+ * Get Variable price options for feed editor
189
+ * @return array
190
+ */
191
+ function woo_feed_get_variable_price_options(){
192
+ return apply_filters( 'woo_feed_variable_price_options', [
193
+ 'first' => __( 'First Variation Price', 'woo-feed' ),
194
+ 'max' => __( 'Max Variation Price', 'woo-feed' ),
195
+ 'min' => __( 'Min Variation Price', 'woo-feed' ),
196
+ ] );
197
+ }
198
+ }
199
+ if( ! function_exists( 'woo_feed_get_variable_quantity_options' ) ) {
200
+ /**
201
+ * Get Variable quantity options for feed editor
202
+ * @return array
203
+ */
204
+ function woo_feed_get_variable_quantity_options(){
205
+ return apply_filters( 'woo_feed_variable_quantity_options', [
206
+ 'first' => __( 'First Variation Quantity', 'woo-feed' ),
207
+ 'max' => __( 'Max Variation Quantity', 'woo-feed' ),
208
+ 'min' => __( 'Min Variation Quantity', 'woo-feed' ),
209
+ 'sum' => __( 'Sum of Variation Quantity', 'woo-feed' ),
210
+ ] );
211
+ }
212
+ }
213
  // End of file helper.php
includes/wc-legacy-support.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Legacy WooCommerce Support
4
+ */
5
+ if( ! function_exists( 'wc_get_attribute_taxonomy_labels' ) && ! woo_feed_wc_version_check( '3.6.0' ) ) {
6
+ /**
7
+ * Support for wc < 3.6.0
8
+ * Get (cached) attribute taxonomy label and name pairs.
9
+ * @return array
10
+ */
11
+ function wc_get_attribute_taxonomy_labels(){
12
+ $prefix = WC_Cache_Helper::get_cache_prefix( 'woocommerce-attributes' );
13
+ $cache_key = $prefix . 'labels';
14
+ $cache_value = wp_cache_get( $cache_key, 'woocommerce-attributes' );
15
+
16
+ if ( $cache_value ) {
17
+ return $cache_value;
18
+ }
19
+
20
+ $taxonomy_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' );
21
+
22
+ wp_cache_set( $cache_key, $taxonomy_labels, 'woocommerce-attributes' );
23
+
24
+ return $taxonomy_labels;
25
+ }
26
+ }
woo-feed.php CHANGED
@@ -15,14 +15,20 @@
15
  * Plugin Name: WooCommerce Product Feed
16
  * Plugin URI: https://webappick.com/
17
  * Description: This plugin generate WooCommerce product feed for Shopping Engines like Google Shopping,Facebook Product Feed,eBay,Amazon,Idealo and many more..
18
- * Version: 3.1.44
19
  * Author: WebAppick
20
  * Author URI: https://webappick.com/
21
  * License: GPL v2
22
  * License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23
  * Text Domain: woo-feed
24
  * Domain Path: /languages
25
- * WC requires at least: 2.6
 
 
 
 
 
 
26
  * WC tested up to: 3.7.1
27
  *
28
  */
@@ -34,7 +40,7 @@ if( ! defined( 'WOO_FEED_VERSION' ) ) {
34
  * Plugin Version
35
  * @var string
36
  */
37
- define( 'WOO_FEED_VERSION', '3.1.44' );
38
  }
39
  if( ! defined( 'WOO_FEED_FREE_FILE') ) {
40
  /**
@@ -82,6 +88,14 @@ if( ! defined( 'WOO_FEED_MIN_PHP_VERSION' ) ) {
82
  */
83
  define( 'WOO_FEED_MIN_PHP_VERSION', '5.6' );
84
  }
 
 
 
 
 
 
 
 
85
  if( ! defined( 'WOO_FEED_PLUGIN_BASE_NAME' ) ) {
86
  /**
87
  * Plugin Base name..
@@ -398,22 +412,6 @@ if( ! function_exists( 'woo_feed_get_product_information' ) ) {
398
  }
399
  add_action('wp_ajax_get_product_information', 'woo_feed_get_product_information');
400
  }
401
- if( ! function_exists( 'woo_feed_wc_version_check' ) ) {
402
- /**
403
- * Check WooCommerce Version
404
- * @param string $version
405
- * @return bool
406
- */
407
- function woo_feed_wc_version_check( $version = '3.0' ) {
408
- if ( class_exists( 'WooCommerce' ) ) {
409
- global $woocommerce;
410
- if ( version_compare( $woocommerce->version, $version, ">=" ) ) {
411
- return true;
412
- }
413
- }
414
- return false;
415
- }
416
- }
417
  if( ! function_exists( 'woo_feed_generate_feed_data' ) ) {
418
  function woo_feed_generate_feed_data($info){
419
 
15
  * Plugin Name: WooCommerce Product Feed
16
  * Plugin URI: https://webappick.com/
17
  * Description: This plugin generate WooCommerce product feed for Shopping Engines like Google Shopping,Facebook Product Feed,eBay,Amazon,Idealo and many more..
18
+ * Version: 3.1.45
19
  * Author: WebAppick
20
  * Author URI: https://webappick.com/
21
  * License: GPL v2
22
  * License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23
  * Text Domain: woo-feed
24
  * Domain Path: /languages
25
+ *
26
+ * WP Requirement & Test
27
+ * Requires at least: 4.4
28
+ * Tested up to: 5.3
29
+ *
30
+ * WC Requirement & Test
31
+ * WC requires at least: 3.2
32
  * WC tested up to: 3.7.1
33
  *
34
  */
40
  * Plugin Version
41
  * @var string
42
  */
43
+ define( 'WOO_FEED_VERSION', '3.1.45' );
44
  }
45
  if( ! defined( 'WOO_FEED_FREE_FILE') ) {
46
  /**
88
  */
89
  define( 'WOO_FEED_MIN_PHP_VERSION', '5.6' );
90
  }
91
+ if( ! defined( 'WOO_FEED_MIN_WC_VERSION' ) ) {
92
+ /**
93
+ * Minimum PHP Version Supported
94
+ * @var string
95
+ * @since 3.1.45
96
+ */
97
+ define( 'WOO_FEED_MIN_WC_VERSION', '3.2' );
98
+ }
99
  if( ! defined( 'WOO_FEED_PLUGIN_BASE_NAME' ) ) {
100
  /**
101
  * Plugin Base name..
412
  }
413
  add_action('wp_ajax_get_product_information', 'woo_feed_get_product_information');
414
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  if( ! function_exists( 'woo_feed_generate_feed_data' ) ) {
416
  function woo_feed_generate_feed_data($info){
417