Amazon Associates Link Builder - Version 1.9.0

Version Description

Download this release

Release Info

Developer amazonlinkbuilder
Plugin Icon 128x128 Amazon Associates Link Builder
Version 1.9.0
Comparing to
See all releases

Code changes from version 1.8.0 to 1.9.0

Files changed (45) hide show
  1. admin/plugin_admin.php +27 -2
  2. amazon-associates-link-builder.php +1 -1
  3. cache/cache_template_loader.php +0 -53
  4. cache/display_unit_cache_loader.php +130 -0
  5. cache/item_lookup_response_cache.php +157 -0
  6. cache/item_lookup_response_cache_loader.php +204 -0
  7. cache/{cache_loader.php → marketplace_config_cache_loader.php} +21 -22
  8. configuration/config_loader.php +5 -6
  9. constants/cron_constants.php +45 -0
  10. constants/db_constants.php +3 -1
  11. constants/gb_block_constants.php +33 -0
  12. constants/plugin_constants.php +2 -2
  13. cron/cron_manager.php +117 -0
  14. cron/cron_schedule_manager.php +57 -0
  15. cron/update_table_cron_task.php +107 -0
  16. css/aalb_admin.css +6 -2
  17. helper/paapi_helper.php +49 -4
  18. helper/plugin_helper.php +4 -2
  19. includes/aalb_initializer.php +3 -0
  20. includes/activator.php +10 -1
  21. includes/autoloader.php +2 -0
  22. includes/deactivator.php +10 -0
  23. includes/gb_block_manager.php +117 -0
  24. includes/item_lookup_response_manager.php +121 -0
  25. includes/plugin_manager.php +24 -0
  26. js/aalb_admin.js +71 -4
  27. js/aalb_gb_block.js +162 -0
  28. plugin_config.php +8 -1
  29. rendering/impression_generator.php +2 -3
  30. rendering/template_engine.php +2 -116
  31. rendering/xml_manipulator.php +79 -44
  32. shortcode/shortcode_helper.php +0 -17
  33. shortcode/shortcode_manager.php +17 -8
  34. sql/sql_helper.php +218 -0
  35. template/ProductCarousel.mustache +1 -1
  36. vendor/a5hleyrich/wp-background-processing/README.md +158 -0
  37. vendor/a5hleyrich/wp-background-processing/classes/wp-async-request.php +163 -0
  38. vendor/a5hleyrich/wp-background-processing/classes/wp-background-process.php +506 -0
  39. vendor/a5hleyrich/wp-background-processing/license.txt +280 -0
  40. vendor/a5hleyrich/wp-background-processing/wp-background-processing.php +20 -0
  41. vendor/autoload.php +1 -1
  42. vendor/composer/autoload_classmap.php +2 -0
  43. vendor/composer/autoload_real.php +4 -4
  44. vendor/composer/autoload_static.php +10 -4
  45. vendor/composer/installed.json +38 -0
admin/plugin_admin.php CHANGED
@@ -23,6 +23,9 @@ use AmazonAssociatesLinkBuilder\configuration\Config_Loader;
23
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
24
  use AmazonAssociatesLinkBuilder\constants\Library_Endpoints;
25
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
 
 
 
26
 
27
  /**
28
  * The class responsible for handling all the functionalities in the admin area.
@@ -42,6 +45,8 @@ class Plugin_Admin {
42
  private $helper;
43
  private $migration_helper;
44
  private $config_loader;
 
 
45
 
46
  public function __construct() {
47
  $this->paapi_helper = new Paapi_Helper();
@@ -50,6 +55,8 @@ class Plugin_Admin {
50
  $this->helper = new Plugin_Helper();
51
  $this->migration_helper = new Settings_Page_Migration_Helper();
52
  $this->config_loader = new Config_Loader();
 
 
53
  }
54
 
55
  /**
@@ -199,6 +206,10 @@ class Plugin_Admin {
199
  $this->helper->aalb_initialize_wp_filesystem_api();
200
  $this->helper->refresh_template_list();
201
  $this->migration_helper->run_migration_logic();
 
 
 
 
202
  update_option( Db_Constants::PLUGIN_VERSION, Plugin_Constants::PLUGIN_CURRENT_VERSION );
203
  }
204
 
@@ -254,7 +265,7 @@ class Plugin_Admin {
254
 
255
  //Only allow users who can edit post to make the request.
256
  if ( current_user_can( 'edit_posts' ) ) {
257
- $url = $this->paapi_helper->get_item_search_url( $_GET['keywords'], array_search( $_GET['marketplace'], $this->config_loader->fetch_marketplaces() ), $_GET['store_id'] );
258
  try {
259
  echo $this->remote_loader->load( $url );
260
  } catch ( \Exception $e ) {
@@ -309,6 +320,20 @@ class Plugin_Admin {
309
  }
310
  wp_die();
311
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  }
313
 
314
- ?>
23
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
24
  use AmazonAssociatesLinkBuilder\constants\Library_Endpoints;
25
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
26
+ use AmazonAssociatesLinkBuilder\includes\GB_Block_Manager;
27
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
28
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
29
 
30
  /**
31
  * The class responsible for handling all the functionalities in the admin area.
45
  private $helper;
46
  private $migration_helper;
47
  private $config_loader;
48
+ private $gb_block_manager;
49
+ private $item_lookup_response_cache;
50
 
51
  public function __construct() {
52
  $this->paapi_helper = new Paapi_Helper();
55
  $this->helper = new Plugin_Helper();
56
  $this->migration_helper = new Settings_Page_Migration_Helper();
57
  $this->config_loader = new Config_Loader();
58
+ $this->gb_block_manager = new GB_Block_Manager();
59
+ $this->item_lookup_response_cache = new Item_Lookup_Response_Cache( new Sql_Helper( DB_NAME, Db_Constants::ITEM_LOOKUP_RESPONSE_TABLE_NAME ) );
60
  }
61
 
62
  /**
206
  $this->helper->aalb_initialize_wp_filesystem_api();
207
  $this->helper->refresh_template_list();
208
  $this->migration_helper->run_migration_logic();
209
+
210
+ // To init item lookup response cache in update.
211
+ $this->item_lookup_response_cache->init();
212
+
213
  update_option( Db_Constants::PLUGIN_VERSION, Plugin_Constants::PLUGIN_CURRENT_VERSION );
214
  }
215
 
265
 
266
  //Only allow users who can edit post to make the request.
267
  if ( current_user_can( 'edit_posts' ) ) {
268
+ $url = $this->paapi_helper->get_item_search_url( $_GET['keywords'], $_GET['marketplace'] , $_GET['store_id'] );
269
  try {
270
  echo $this->remote_loader->load( $url );
271
  } catch ( \Exception $e ) {
320
  }
321
  wp_die();
322
  }
323
+
324
+ /**
325
+ * Registers GutenBerg editor block of Amazon Associates Link Builder if supported.
326
+ */
327
+ public function register_gb_block_if_supported()
328
+ {
329
+ if ($this->gb_block_manager->is_gb_block_supported()) {
330
+ $this->aalb_enqueue_styles();
331
+ $this->aalb_enqueue_scripts();
332
+ $this->gb_block_manager->register_gb_block();
333
+ }
334
+ }
335
+
336
+
337
  }
338
 
339
+ ?>
amazon-associates-link-builder.php CHANGED
@@ -8,7 +8,7 @@
8
  /*
9
  Plugin Name: Amazon Associates Link Builder
10
  Description: Amazon Associates Link Builder is the official free Amazon Associates Program plugin for WordPress. The plugin enables you to search for products in the Amazon catalog, access real-time price and availability information, and easily create links in your posts to products on Amazon.com. You will be able to generate text links, create custom ad units, or take advantage of out-of-the-box widgets that we’ve designed and included with the plugin.
11
- Version: 1.8.0
12
  Author: Amazon Associates Program
13
  Author URI: https://affiliate-program.amazon.com/
14
  License: GPLv2
8
  /*
9
  Plugin Name: Amazon Associates Link Builder
10
  Description: Amazon Associates Link Builder is the official free Amazon Associates Program plugin for WordPress. The plugin enables you to search for products in the Amazon catalog, access real-time price and availability information, and easily create links in your posts to products on Amazon.com. You will be able to generate text links, create custom ad units, or take advantage of out-of-the-box widgets that we’ve designed and included with the plugin.
11
+ Version: 1.9.0
12
  Author: Amazon Associates Program
13
  Author URI: https://affiliate-program.amazon.com/
14
  License: GPLv2
cache/cache_template_loader.php DELETED
@@ -1,53 +0,0 @@
1
- <?php
2
-
3
- /*
4
- Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
-
6
- Licensed under the GNU General Public License as published by the Free Software Foundation,
7
- Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
- A copy of the License is located in the "license" file accompanying this file.
9
-
10
- This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
- either express or implied. See the License for the specific language governing permissions
12
- and limitations under the License.
13
- */
14
- namespace AmazonAssociatesLinkBuilder\cache;
15
-
16
- /**
17
- * Cache Loader for rendered templates.
18
- *
19
- * Loads ands saves the display unit in the cache.
20
- *
21
- * @since 1.0.0
22
- * @package AmazonAssociatesLinkBuilder
23
- * @subpackage AmazonAssociatesLinkBuilder/includes
24
- */
25
- class Cache_Template_Loader {
26
- /**
27
- * Get the html of the display unit from the cache
28
- *
29
- * @since 1.0.0
30
- *
31
- * @param string $key Unique Key for the display unit in cache.
32
- *
33
- * @return string HTML of the display unit.
34
- */
35
- public function get_display_unit( $key ) {
36
- return get_transient( $key );
37
- }
38
-
39
- /**
40
- * Get the product information.
41
- *
42
- * @since 1.0.0
43
- *
44
- * @param string $key Unique identification of the product.
45
- * @param string $display_unit HTML of the display unit to save in the cache.
46
- */
47
- public function save_display_unit( $key, $display_unit ) {
48
- set_transient( $key, $display_unit, AALB_CACHE_FOR_ASIN_ADUNIT_TTL );
49
- }
50
-
51
- }
52
-
53
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cache/display_unit_cache_loader.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\cache;
16
+
17
+ use AmazonAssociatesLinkBuilder\configuration\Config_Helper;
18
+ use AmazonAssociatesLinkBuilder\exceptions\Invalid_Marketplace_Exception;
19
+ use AmazonAssociatesLinkBuilder\rendering\Template_Engine;
20
+ use AmazonAssociatesLinkBuilder\rendering\Impression_Generator;
21
+
22
+ /**
23
+ * Cache Loader for rendered templates.
24
+ *
25
+ * Loads ands saves the display unit in the cache.
26
+ *
27
+ * @since 1.8.0
28
+ * @package AmazonAssociatesLinkBuilder
29
+ * @subpackage AmazonAssociatesLinkBuilder/cache
30
+ */
31
+ class Display_Unit_Cache_Loader {
32
+
33
+ private $item_lookup_response_cache_loader;
34
+ private $template_engine;
35
+ private $impression_generator;
36
+
37
+ public function __construct( Template_Engine $template_engine, Item_Lookup_Response_Cache_Loader $item_lookup_response_cache_loader, Impression_Generator $impression_generator ) {
38
+ $this->template_engine = $template_engine;
39
+ $this->item_lookup_response_cache_loader = $item_lookup_response_cache_loader;
40
+ $this->impression_generator = $impression_generator;
41
+ }
42
+
43
+ /**
44
+ * Get the html of the display unit from the cache
45
+ *
46
+ * @since 1.8.0
47
+ *
48
+ * @param string $display_unit_cache_key Key to lookup in transients cache
49
+ * @param string $template
50
+ * @param string $marketplace Marketplace
51
+ * @param string $link_code Link code
52
+ * @param string $store_id Store_id
53
+ * @param string $asin_group Group of asins separated by ","
54
+ *
55
+ * @return string HTML of the display unit.
56
+ */
57
+ public function get( $display_unit_cache_key, $template, $marketplace, $link_code, $store_id, $asin_group ) {
58
+ $display_unit = $this->lookup( $display_unit_cache_key );
59
+ $asins_array = explode( ",", $asin_group );
60
+
61
+ return $display_unit === false ? $this->create_cache_entry( $display_unit_cache_key, $template, $marketplace, $link_code, $store_id, $asins_array ) : $display_unit;
62
+ }
63
+
64
+ /**
65
+ * Lookup in transient cache for the display unit
66
+ *
67
+ * @since 1.8.0
68
+ *
69
+ * @param string $display_unit_cache_key Key to search for in transients cache
70
+ *
71
+ * @return String | false Return response cached in transient
72
+ */
73
+ protected function lookup( $display_unit_cache_key ) {
74
+ return get_transient( $display_unit_cache_key );
75
+ }
76
+
77
+ /**
78
+ * Create the display unit from response returned by level 2 cache
79
+ *
80
+ * @since 1.8.0
81
+ *
82
+ * @param string $template
83
+ *
84
+ * @return String Response from level 2 cache
85
+ */
86
+ protected function create_cache_entry( $display_unit_cache_key, $template, $marketplace, $link_code, $store_id, $asins_array ) {
87
+ $products = $this->item_lookup_response_cache_loader->get( $marketplace, $link_code, $store_id, $asins_array );
88
+
89
+ $display_unit = $this->template_engine->render_xml( $products, $template );
90
+ $display_unit = $this->add_html_for_impression_tracking( $display_unit, $marketplace, $link_code, $store_id, $asins_array );
91
+
92
+ // Add entry in the cache only if products information of all requested asins is returned
93
+ if ( sizeof( $products->Item ) === sizeof( $asins_array ) ) {
94
+ set_transient( $display_unit_cache_key, $display_unit, AALB_CACHE_FOR_ASIN_ADUNIT_TTL );
95
+ }
96
+
97
+ return $display_unit;
98
+ }
99
+
100
+ /**
101
+ * Adds pixel image HTML element to the display unit
102
+ *
103
+ * @since 1.6.0
104
+ *
105
+ * @param string $display_unit HTML of the display unit.
106
+ * @param String $marketplace marketplace
107
+ * @param String $store_id Store id of associate
108
+ * @param String $link_code Link code used for tracking
109
+ * @param array $asins_array Array of asins
110
+ *
111
+ * @return string $display_unit HTML of the display unit along with pixel image
112
+ */
113
+ public function add_html_for_impression_tracking( $display_unit, $marketplace, $link_code, $store_id, $asins_array ) {
114
+ try {
115
+ $impression = $this->impression_generator->get_impression( $marketplace, $link_code, $store_id, $asins_array );
116
+ $display_unit = $impression . $display_unit;
117
+ } catch ( Invalid_Marketplace_Exception $e ) {
118
+ //Do Nothing as it is because of a new marketplace added and we are currently not racling impression for this new marketplace.
119
+ } catch ( \InvalidArgumentException $e ) {
120
+ error_log( "Aalb_Template_Engine::add_html_for_impression_tracking " . $e->getMessage() );
121
+ } catch ( \Exception $e ) {
122
+ error_log( "Aalb_Template_Engine::add_html_for_impression_tracking " . $e->getMessage() );
123
+ }
124
+
125
+ return $display_unit;
126
+ }
127
+
128
+ }
129
+
130
+ ?>
cache/item_lookup_response_cache.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\cache;
16
+
17
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
18
+
19
+ /**
20
+ * Load response from Asin_Response_Table if it exists and is valid and on cache miss fetch the same via making a call to ItemLookUpAPI.
21
+ *
22
+ * @since 1.8.0
23
+ * @package AmazonAssociatesLinkBuilder
24
+ * @subpackage AmazonAssociatesLinkBuilder/cache
25
+ */
26
+ class Item_Lookup_Response_Cache {
27
+
28
+ private $sql_helper;
29
+
30
+ public function __construct( Sql_Helper $sql_helper ) {
31
+ $this->sql_helper = $sql_helper;
32
+ }
33
+
34
+ /**
35
+ * Init cache by creating the table
36
+ *
37
+ * @since 1.8.0
38
+ */
39
+ public function init() {
40
+ $columns = array(
41
+ "`asin` VARCHAR(10) NOT NULL",
42
+ "`marketplace` VARCHAR(5) NOT NULL",
43
+ "`item_lookup_response` TEXT",
44
+ "`last_updated_time` TIMESTAMP DEFAULT 0",
45
+ "`last_access_time` TIMESTAMP DEFAULT 0"
46
+ );
47
+
48
+ $indices = array( "`index_last_updated_time` (`last_updated_time`)" );
49
+ $primary_key = "(`asin`, `marketplace`)";
50
+
51
+ $this->sql_helper->create_table( $columns, $indices, $primary_key );
52
+ }
53
+
54
+ /**
55
+ * Clear the cache by truncating the table
56
+ *
57
+ * @since 1.8.0
58
+ */
59
+ public function clear() {
60
+ $result = $this->sql_helper->truncate_table();
61
+ if ( $result === false ) {
62
+ error_log( 'There was a problem while truncating the table' );
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Remove the cache by dropping table
68
+ *
69
+ * @since 1.8.0
70
+ */
71
+ public function delete() {
72
+ $result = $this->sql_helper->drop_table();
73
+ if ( $result === false ) {
74
+ error_log( 'There was a problem while deleting the table' );
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Adds entry in the cache for given asin, marketplace and response.
80
+ *
81
+ * @since 1.8.0
82
+ *
83
+ * @param array $items_array Array of asin => response pairs
84
+ * @param string marketplace
85
+ */
86
+ public function add( $items_array, $marketplace, $update_last_access_time = true ) {
87
+ $entries = array();
88
+
89
+ foreach ( $items_array as $asin => $response ) {
90
+ $escaped_response = esc_sql( $response );
91
+ $entries[] = array( "'{$asin}'", "'{$marketplace}'", "'{$escaped_response}'", "CURRENT_TIMESTAMP()", "CURRENT_TIMESTAMP()" );
92
+ }
93
+
94
+ $columns = array( "`asin`", "`marketplace`", "`item_lookup_response`", "`last_updated_time`", "`last_access_time`" );
95
+ $on_duplicate_key_update_columns = array( "`item_lookup_response`", "`last_updated_time`" );
96
+ if( $update_last_access_time ){
97
+ $on_duplicate_key_update_columns[] = "`last_access_time`";
98
+ }
99
+
100
+ $result = $this->sql_helper->add_rows_in_table( $columns, $entries, $on_duplicate_key_update_columns );
101
+ if ( $result === false ) {
102
+ error_log( "There was a problem while adding entry in the table" );
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Add empty response entry for given asins and marketplace
108
+ *
109
+ * @since 1.8.0
110
+ *
111
+ * @param array $asins_array Array of asins
112
+ * @param String $marketplace Marketplace
113
+ */
114
+ public function add_empty_response( $asins_array, $marketplace ){
115
+ $entries = array();
116
+
117
+ foreach ( $asins_array as $asin ) {
118
+ $entries[] = array( "'{$asin}'", "'{$marketplace}'", "''", "0", "CURRENT_TIMESTAMP()" );
119
+ }
120
+
121
+ $columns = array( "`asin`", "`marketplace`", "`item_lookup_response`", "`last_updated_time`", "`last_access_time`" );
122
+ $on_duplicate_key_update_columns = array( "`last_updated_time`", "`last_access_time`" );
123
+
124
+ $result = $this->sql_helper->add_rows_in_table( $columns, $entries, $on_duplicate_key_update_columns );
125
+ if ( $result === false ) {
126
+ error_log( "There was a problem while adding entry in the table" );
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Delete entries from table which haven't been accessed in the last 24 hours
132
+ *
133
+ * @since 1.8.0
134
+ */
135
+ public function delete_old_asins(){
136
+ $result = $this->sql_helper->delete_old_asins();
137
+ if( $result===False ){
138
+ error_log("There was a problem while deleting asins from the table");
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Get asins which are about to expire.
144
+ *
145
+ * @since 1.8.0
146
+ */
147
+ public function get_asins_to_update() {
148
+ $result = $this->sql_helper->get_asins_to_update();
149
+ if ($result===False){
150
+ error_log("There was a problem while fetching asins to update from the table");
151
+ $result = array();
152
+ }
153
+ return $result;
154
+ }
155
+ }
156
+
157
+ ?>
cache/item_lookup_response_cache_loader.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\cache;
16
+
17
+ use AmazonAssociatesLinkBuilder\rendering\Xml_Manipulator;
18
+ use AmazonAssociatesLinkBuilder\helper\Paapi_Helper;
19
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
20
+ use AmazonAssociatesLinkBuilder\includes\Item_Lookup_Response_Manager;
21
+
22
+ /**
23
+ * Load response from Asin_Response_Table if it exists and is valid and on cache miss fetch the same via making a call to ItemLookUpAPI.
24
+ *
25
+ * @since 1.8.0
26
+ * @package AmazonAssociatesLinkBuilder
27
+ * @subpackage AmazonAssociatesLinkBuilder/cache
28
+ */
29
+ class Item_Lookup_Response_Cache_Loader {
30
+
31
+ private $sql_helper;
32
+ private $xml_manipulator;
33
+ private $paapi_helper;
34
+ private $item_lookup_response_manager;
35
+ private $item_lookup_response_cache;
36
+
37
+ public function __construct( Xml_Manipulator $xml_manipulator, Paapi_Helper $paapi_helper, Item_Lookup_Response_Manager $item_lookup_response_manager, Sql_Helper $sql_helper, Item_Lookup_Response_Cache $item_lookup_response_cache ) {
38
+ $this->sql_helper = $sql_helper;
39
+ $this->xml_manipulator = $xml_manipulator;
40
+ $this->paapi_helper = $paapi_helper;
41
+ $this->item_lookup_response_manager = $item_lookup_response_manager;
42
+ $this->item_lookup_response_cache = $item_lookup_response_cache;
43
+ }
44
+
45
+ /**
46
+ * Load the response from Aalb_Asin_Response table and on cache miss fetch the same via making a call to ItemLookupAPI
47
+ *
48
+ * @since 1.8.0
49
+ *
50
+ * @param string $marketplace Marketplace
51
+ * @param string $link_code Link code
52
+ * @param string $store_id Store_id
53
+ * @param array $asins_array Array of asins
54
+ *
55
+ * @return \SimpleXMLElement Final updated response items
56
+ */
57
+ public function get( $marketplace, $link_code, $store_id, $asins_array ) {
58
+ $items = $this->lookup( $marketplace, $asins_array );
59
+ $items = $this->is_all_entries_present( $items, $asins_array ) ? $items : $this->merge_cached_and_non_cached_response_items( $items, $this->create_cache_entry( $items, $marketplace, $store_id, $asins_array ) );
60
+
61
+ return $this->create_final_response( $items, $asins_array, $marketplace, $link_code, $store_id );
62
+ }
63
+
64
+ /**
65
+ * Check if all the entries are present in response retrieved from cache
66
+ *
67
+ * @since 1.8.0
68
+ *
69
+ * @param array $items Asin => response map retrieved from cache
70
+ * @param array $asins_array Array of asins
71
+ *
72
+ * @return bool
73
+ */
74
+ private function is_all_entries_present( $items, $asins_array ) {
75
+ return sizeof( $items ) == sizeof( $asins_array );
76
+ }
77
+
78
+ /**
79
+ * Merge the items of response found in cache and those not found in cache
80
+ *
81
+ * @since 1.8.0
82
+ *
83
+ * @param array $cached_response_items Array of items retrieved from cache
84
+ * @param array $non_cached_response_items Array of items which were not in cache and so fetched by making a call to ItemLookUpAPI
85
+ *
86
+ * @return array Merged response of items found in cache and those not found in cache
87
+ */
88
+ private function merge_cached_and_non_cached_response_items( $cached_response_items, $non_cached_response_items ){
89
+ return array_merge( $cached_response_items, $non_cached_response_items );
90
+ }
91
+
92
+ /**
93
+ * Create final response from merged array of response of found asins and response loaded from PA-API of missing asins
94
+ *
95
+ * @since 1.8.0
96
+ *
97
+ * @param array $fetched_asins_responses Array of asin => response pairs
98
+ * @param array $requested_asins Array of asins (required to preserve order)
99
+ *
100
+ * @return \SimpleXMLElement Final response
101
+ */
102
+ private function create_final_response( $fetched_asins_responses, $requested_asins, $marketplace, $link_code, $store_id ) {
103
+ $final_response = array();
104
+ // Reorder the items array such that order of asins in shortcode is preserved
105
+ foreach ( $requested_asins as $asin ){
106
+ if ( array_key_exists( $asin, $fetched_asins_responses ) ) {
107
+ $final_response[] = $fetched_asins_responses[$asin];
108
+ }
109
+ }
110
+
111
+ $items_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><Items>" . implode( "", $final_response ) . "</Items></root>";
112
+ $modified_items_xml = $this->xml_manipulator->get_customized_response( $items_xml, $store_id, $link_code, $marketplace );
113
+
114
+ return $modified_items_xml;
115
+ }
116
+
117
+ /**
118
+ * Load the information with a GET request and save it in the cache. Return the loaded information.
119
+ *
120
+ * @since 1.8.0
121
+ *
122
+ * @param array $found_items Asin => response of found asins
123
+ * @param string $marketplace Marketplace
124
+ * @param string $store_id Store_id
125
+ * @param array $asins_array Array of asins
126
+ *
127
+ * @return array Response broken into asin => response pairs.
128
+ */
129
+ protected function create_cache_entry( $found_items, $marketplace, $store_id, $asins_array ) {
130
+ $found_asins_array = array_keys( $found_items );
131
+ $missing_asins_array = $this->get_missing_asins( $asins_array, $found_asins_array );
132
+
133
+ try {
134
+ // Make a call to ItemLookUpAPI function
135
+ $items_array = $this->item_lookup_response_manager->get_response( $marketplace, $missing_asins_array, $store_id );
136
+ $this->item_lookup_response_cache->add( $items_array, $marketplace );
137
+ } catch ( \Exception $e ) {
138
+ $this->item_lookup_response_cache->add_empty_response( $missing_asins_array, $marketplace );
139
+ error_log( 'Item_Lookup_Response_Cache_Loader :: create_cache_entry::' . $this->paapi_helper->get_error_message( $e->getMessage() ) );
140
+ $items_array = array();
141
+ }
142
+
143
+ return $items_array;
144
+ }
145
+
146
+ /**
147
+ * Lookup in the cache for given asins and marketplace.
148
+ * If the key exists in the cache, the data is returned.
149
+ * Else false is returned.
150
+ *
151
+ * @since 1.8.0
152
+ *
153
+ * @param string $marketplace Marketplace
154
+ * @param array $asins_array Array of asins
155
+ *
156
+ * @return array Data in the cache (array of array of asin and item_lookup_response).
157
+ */
158
+ protected function lookup( $marketplace, $asins_array ) {
159
+ if ( sizeof( $asins_array ) === 0 ) {
160
+ return array();
161
+ }
162
+ $lookup_result = $this->sql_helper->lookup_asin_response_in_table( $asins_array, $marketplace );
163
+
164
+ $asin_response_map = array();
165
+ foreach ( $lookup_result as $item ){
166
+ if ( $this->is_valid_result( $item ) ){
167
+ $asin_response_map[$item->asin] = $item->item_lookup_response;
168
+ }
169
+ }
170
+
171
+ $this->sql_helper->update_last_access_time( $asins_array, $marketplace );
172
+
173
+ return $asin_response_map;
174
+ }
175
+
176
+ /**
177
+ * Check if the response is valid
178
+ *
179
+ * @since 1.8.0
180
+ *
181
+ * @param Object $response Object which represents an entry in cache
182
+ *
183
+ * @return bool
184
+ */
185
+ private function is_valid_result( $response ){
186
+ return $response->is_valid === '1' && ! empty( $response->item_lookup_response );
187
+ }
188
+
189
+ /**
190
+ * Get the asins not found in cache
191
+ *
192
+ * @since 1.8.0
193
+ *
194
+ * @param array $asins_array Array of all asins
195
+ * @param array $found_asins_array Array of asins found in cache
196
+ *
197
+ * @return array Array of missing asins
198
+ */
199
+ private function get_missing_asins( $asins_array, $found_asins_array ) {
200
+ return array_diff( $asins_array, $found_asins_array );
201
+ }
202
+ }
203
+
204
+ ?>
cache/{cache_loader.php → marketplace_config_cache_loader.php} RENAMED
@@ -11,9 +11,10 @@ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS O
11
  either express or implied. See the License for the specific language governing permissions
12
  and limitations under the License.
13
  */
 
14
  namespace AmazonAssociatesLinkBuilder\cache;
15
 
16
- use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
17
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
18
 
19
  /**
@@ -22,37 +23,36 @@ use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
22
  * Generic class that can be used by any class to get the data from the cache.
23
  * If the data is not available in the cache, a remote GET request is made.
24
  *
25
- * @since 1.0.0
26
  * @package AmazonAssociatesLinkBuilder
27
- * @subpackage AmazonAssociatesLinkBuilder/includes
28
  */
29
- class Cache_Loader {
30
 
31
- public $loader;
32
- protected $helper;
33
 
34
- public function __construct( $loader ) {
35
  $this->loader = $loader;
36
- $this->helper = new Plugin_Helper();
37
  }
38
 
39
  /**
40
  * If the information is in the cache, then retrieve the information from the cache.
41
  * Else get the information by making a GET request.
42
  *
 
 
43
  * @param string $key Unique identification of the information.
44
  * @param string $url URL for making a request.
45
  * @param string $link_code Link Code to be entered in URLS for attribution purposes.
46
  *
47
  * @return string GET Response.
48
  */
49
- public function load( $key, $url, $link_code = Plugin_Constants::DEFAULT_LINK_CODE ) {
50
  $info = $this->lookup( $key );
51
- if ( $info !== false ) {
52
- return $info;
53
- } else {
54
- return $this->load_and_save( $key, $url, $link_code );
55
- }
56
  }
57
 
58
  /**
@@ -60,31 +60,30 @@ class Cache_Loader {
60
  * If the key exists in the cache, the data is return.
61
  * Else false is returned.
62
  *
 
 
63
  * @param string $key Unique identification of the information.
64
  *
65
  * @return string Data in the cache.
66
  */
67
- private function lookup( $key ) {
68
  return get_transient( $key );
69
  }
70
 
71
  /**
72
  * Load the information with a GET request and save it in the cache. Return the loaded information.
73
  *
 
 
74
  * @param string $key Unique identification of the information.
75
  * @param string $url URL for making a request.
76
  * @param string $link_code Link Code to be entered in URLS for attribution purposes.
77
  *
78
  * @return string GET Response.
79
  */
80
- private function load_and_save( $key, $url, $link_code ) {
81
  $info = $this->loader->load( $url );
82
-
83
- //use wordpress linkcode
84
- $info = preg_replace( "/linkCode(%3D|=)\w{1,3}/", "linkCode$1" . $link_code, $info );
85
-
86
- $this->helper->clear_expired_transients_at_intervals();
87
- set_transient( $key, $info, AALB_CACHE_FOR_ASIN_RAWINFO_TTL );
88
 
89
  return $info;
90
  }
11
  either express or implied. See the License for the specific language governing permissions
12
  and limitations under the License.
13
  */
14
+
15
  namespace AmazonAssociatesLinkBuilder\cache;
16
 
17
+ use AmazonAssociatesLinkBuilder\includes\Remote_Loader;
18
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
19
 
20
  /**
23
  * Generic class that can be used by any class to get the data from the cache.
24
  * If the data is not available in the cache, a remote GET request is made.
25
  *
26
+ * @since 1.8.0
27
  * @package AmazonAssociatesLinkBuilder
28
+ * @subpackage AmazonAssociatesLinkBuilder/cache
29
  */
30
+ class Marketplace_Config_Cache_Loader {
31
 
32
+ private $loader;
33
+ private $helper;
34
 
35
+ public function __construct( Remote_Loader $loader, Plugin_Helper $plugin_helper ) {
36
  $this->loader = $loader;
37
+ $this->helper = $plugin_helper;
38
  }
39
 
40
  /**
41
  * If the information is in the cache, then retrieve the information from the cache.
42
  * Else get the information by making a GET request.
43
  *
44
+ * @since 1.8.0
45
+ *
46
  * @param string $key Unique identification of the information.
47
  * @param string $url URL for making a request.
48
  * @param string $link_code Link Code to be entered in URLS for attribution purposes.
49
  *
50
  * @return string GET Response.
51
  */
52
+ public function get( $key, $url ) {
53
  $info = $this->lookup( $key );
54
+
55
+ return $info !== false ? $info : $this->create_cache_entry( $key, $url );
 
 
 
56
  }
57
 
58
  /**
60
  * If the key exists in the cache, the data is return.
61
  * Else false is returned.
62
  *
63
+ * @since 1.8.0
64
+ *
65
  * @param string $key Unique identification of the information.
66
  *
67
  * @return string Data in the cache.
68
  */
69
+ protected function lookup( $key ) {
70
  return get_transient( $key );
71
  }
72
 
73
  /**
74
  * Load the information with a GET request and save it in the cache. Return the loaded information.
75
  *
76
+ * @since 1.8.0
77
+ *
78
  * @param string $key Unique identification of the information.
79
  * @param string $url URL for making a request.
80
  * @param string $link_code Link Code to be entered in URLS for attribution purposes.
81
  *
82
  * @return string GET Response.
83
  */
84
+ protected function create_cache_entry( $key, $url ) {
85
  $info = $this->loader->load( $url );
86
+ set_transient( $key, $info, AALB_CACHE_FOR_MARKETPLACE_CONFIG_TTL );
 
 
 
 
 
87
 
88
  return $info;
89
  }
configuration/config_loader.php CHANGED
@@ -13,11 +13,11 @@ and limitations under the License.
13
  */
14
  namespace AmazonAssociatesLinkBuilder\configuration;
15
 
16
- use AmazonAssociatesLinkBuilder\cache\Cache_Loader;
17
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
18
  use AmazonAssociatesLinkBuilder\constants\Paapi_Constants;
 
19
  use AmazonAssociatesLinkBuilder\includes\Remote_Loader;
20
- use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
21
 
22
  /**
23
  * The class responsible for getting all the configuration
@@ -30,10 +30,9 @@ use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
30
  */
31
  class Config_Loader {
32
 
33
- private $cache_loader;
34
-
35
  public function __construct() {
36
- $this->cache_loader = new Cache_Loader( new Remote_Loader() );
37
  }
38
 
39
  /**
@@ -46,7 +45,7 @@ class Config_Loader {
46
  */
47
  public function fetch_marketplaces() {
48
  try {
49
- $body = $this->cache_loader->load( Db_Constants::MARKETPLACE_NAMES, Paapi_Constants::MARKETPLACES_URL );
50
 
51
  return $this->parse_json( $body );
52
  } catch ( \Exception $e ) {
13
  */
14
  namespace AmazonAssociatesLinkBuilder\configuration;
15
 
16
+ use AmazonAssociatesLinkBuilder\cache\Marketplace_Config_Cache_Loader;
17
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
18
  use AmazonAssociatesLinkBuilder\constants\Paapi_Constants;
19
+ use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
20
  use AmazonAssociatesLinkBuilder\includes\Remote_Loader;
 
21
 
22
  /**
23
  * The class responsible for getting all the configuration
30
  */
31
  class Config_Loader {
32
 
33
+ private $marketplace_config_cache_loader;
 
34
  public function __construct() {
35
+ $this->marketplace_config_cache_loader = new Marketplace_Config_Cache_Loader( new Remote_Loader(), new Plugin_Helper() );
36
  }
37
 
38
  /**
45
  */
46
  public function fetch_marketplaces() {
47
  try {
48
+ $body = $this->marketplace_config_cache_loader->get( Db_Constants::MARKETPLACE_NAMES, Paapi_Constants::MARKETPLACES_URL );
49
 
50
  return $this->parse_json( $body );
51
  } catch ( \Exception $e ) {
constants/cron_constants.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
+
5
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
6
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
7
+ A copy of the License is located in the "license" file accompanying this file.
8
+
9
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
10
+ either express or implied. See the License for the specific language governing permissions
11
+ and limitations under the License.
12
+ */
13
+
14
+ namespace AmazonAssociatesLinkBuilder\constants;
15
+
16
+ /**
17
+ * Class for Holding constants required for wp-cron.
18
+ *
19
+ * @since 1.8.0
20
+ * @package AmazonAssociatesLinkBuilder
21
+ * @subpackage AmazonAssociatesLinkBuilder/constants
22
+ */
23
+
24
+ class Cron_Constants {
25
+ const BACKGROUND_PROCESSING_ACTION = 'update_table';
26
+ const BACKGROUND_PROCESSING_PREFIX = 'aalb';
27
+ const ASIN_KEY = 'asins';
28
+ const MARKETPLACE_KEY = 'marketplace';
29
+ const UPDATE_TABLE_HOOK = 'aalb_update_table_hook';
30
+ const DELETE_FROM_TABLE_HOOK = 'aalb_delete_from_table_hook';
31
+ const UPDATE_TABLE_CRON = 'aalb_update_table_cron';
32
+ const UPDATE_TABLE_CRON_SCHEDULE_NAME = 'fifteen_minutes';
33
+ const UPDATE_TABLE_CRON_SCHEDULE_DEFAULT_VALUE = 15 * MINUTE_IN_SECONDS;
34
+ const DELETE_FROM_TABLE_CRON_SCHEDULE_NAME = 'six_hours';
35
+ const DELETE_FROM_TABLE_CRON_SCHEDULE_VALUE = 6 * HOUR_IN_SECONDS;
36
+ const CACHE_REFRESH_AGE = '25 MINUTE';
37
+ const CACHE_EVICT_AGE = '24 HOUR';
38
+ const DELAY_EXPONENT_ON_PAAPI_THROTTLE = 'aalb_delay_exponent_on_paapi_throttle';
39
+ const DELAY_CONSTANT_VALUE = 100;
40
+ const DELAY_BASE_VALUE = 2;
41
+ const MAX_DELAY_LIMIT = 5000;
42
+ const DELAY_EXPONENT_INITIAL_VALUE = 0;
43
+ }
44
+
45
+ ?>
constants/db_constants.php CHANGED
@@ -41,6 +41,8 @@ class Db_Constants {
41
  const GEOLITE_DB_DOWNLOAD_NEXT_RETRY_TIME = 'aalb_geolite_db_download_next_retry_time';
42
  const GEOLITE_DB_DOWNLOAD_RETRY_ON_FAILURE_DURATION = 'aalb_geolite_db_download_retry_on_failure_duration';
43
  const GEOLITE_DB_DOWNLOAD_FAILED_ATTEMPTS = 'aalb_geolite_db_download_failed_attempts';
 
 
44
 
45
  //Defaults in case DB doesn't contain them.
46
  const DEFAULT_TEMPLATE_NAME = 'ProductCarousel';
@@ -48,4 +50,4 @@ class Db_Constants {
48
  const DEFAULT_STORE_ID_NAME = 'not-specified';
49
  }
50
 
51
- ?>
41
  const GEOLITE_DB_DOWNLOAD_NEXT_RETRY_TIME = 'aalb_geolite_db_download_next_retry_time';
42
  const GEOLITE_DB_DOWNLOAD_RETRY_ON_FAILURE_DURATION = 'aalb_geolite_db_download_retry_on_failure_duration';
43
  const GEOLITE_DB_DOWNLOAD_FAILED_ATTEMPTS = 'aalb_geolite_db_download_failed_attempts';
44
+ const ITEM_LOOKUP_RESPONSE_TABLE_NAME = 'Aalb_Asin_Response';
45
+ const CRON_UPDATE_INTERVAL = 'aalb_update_table_cron_interval';
46
 
47
  //Defaults in case DB doesn't contain them.
48
  const DEFAULT_TEMPLATE_NAME = 'ProductCarousel';
50
  const DEFAULT_STORE_ID_NAME = 'not-specified';
51
  }
52
 
53
+ ?>
constants/gb_block_constants.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
+
5
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
6
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
7
+ A copy of the License is located in the "license" file accompanying this file.
8
+
9
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
10
+ either express or implied. See the License for the specific language governing permissions
11
+ and limitations under the License.
12
+ */
13
+
14
+ namespace AmazonAssociatesLinkBuilder\constants;
15
+
16
+ /**
17
+ * Class for Holding constants required for Gutenberg editor.
18
+ *
19
+ * @since 1.9.0
20
+ * @package AmazonAssociatesLinkBuilder
21
+ * @subpackage AmazonAssociatesLinkBuilder/constants
22
+ */
23
+
24
+ class GB_Block_Constants
25
+ {
26
+ const GB_SCRIPT_HANDLE = 'amazon-associates-link-builder-gb-block';
27
+ const SHORTCODE_ATTR = 'shortCodeContent';
28
+ const SHORTCODE_ATTR_TYPE = 'string';
29
+ const SEARCH_KEYWORD = 'searchKeyword';
30
+ const SEARCH_KEYWORD_TYPE = 'string';
31
+ const GB_SUPPORTED_IDENTIFIER_METHOD = 'register_block_type';
32
+ }
33
+ ?>
constants/plugin_constants.php CHANGED
@@ -23,7 +23,7 @@ namespace AmazonAssociatesLinkBuilder\constants;
23
  */
24
 
25
  class Plugin_Constants {
26
- const PLUGIN_CURRENT_VERSION = '1.8.0';
27
  //Version no. with multi locale settings page
28
  const MULTI_LOCALE_SETTINGS_PLUGIN_VERSION = '1.4.12';
29
  const WORDPRESS_REQUEST_TIMEOUT_IN_MS = 40000;
@@ -70,4 +70,4 @@ class Plugin_Constants {
70
  const IMPRESSION_RECORDER_SERVICE_KEY = 'impression_recorder_service';
71
  const ENDPOINT_KEY = 'endpoint';
72
  const ORG_UNIT_ID_KEY = 'org_unit_id';
73
- }
23
  */
24
 
25
  class Plugin_Constants {
26
+ const PLUGIN_CURRENT_VERSION = '1.9.0';
27
  //Version no. with multi locale settings page
28
  const MULTI_LOCALE_SETTINGS_PLUGIN_VERSION = '1.4.12';
29
  const WORDPRESS_REQUEST_TIMEOUT_IN_MS = 40000;
70
  const IMPRESSION_RECORDER_SERVICE_KEY = 'impression_recorder_service';
71
  const ENDPOINT_KEY = 'endpoint';
72
  const ORG_UNIT_ID_KEY = 'org_unit_id';
73
+ }
cron/cron_manager.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\cron;
16
+
17
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
18
+ use AmazonAssociatesLinkBuilder\constants\Cron_Constants;
19
+ use AmazonAssociatesLinkBuilder\constants\Db_Constants;
20
+ use AmazonAssociatesLinkBuilder\cron\Update_Table_Cron_Task;
21
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
22
+
23
+ /**
24
+ * Class which manages all cron operations
25
+ *
26
+ * @since 1.8.0
27
+ * @package AmazonAssociatesLinkBuilder
28
+ * @subpackage AmazonAssociatesLinkBuilder/cron
29
+ */
30
+ class Cron_Manager {
31
+
32
+ private $update_table_cron_task;
33
+ private $item_lookup_response_cache;
34
+
35
+ public function __construct( Sql_Helper $sql_helper ) {
36
+ $this->update_table_cron_task = new Update_Table_Cron_Task();
37
+ $this->item_lookup_response_cache = new Item_Lookup_Response_Cache( $sql_helper );
38
+ }
39
+
40
+ /**
41
+ * Get asins to update and add them in queue for background processing.
42
+ *
43
+ * @since 1.8.0
44
+ */
45
+ public function update_table() {
46
+ $asins_list = $this->item_lookup_response_cache->get_asins_to_update();
47
+
48
+ if ( sizeof( $asins_list ) == 0 ) {
49
+ return;
50
+ }
51
+
52
+ $marketplace_asins_list_map = array();
53
+ foreach ( $asins_list as $item ) {
54
+ $marketplace_asins_list_map[$item->marketplace][] = $item->asin;
55
+ }
56
+ $marketplace_asins_chunks_map = array_map( array( $this, 'break_into_chunks' ), $marketplace_asins_list_map );
57
+
58
+ foreach ( $marketplace_asins_chunks_map as $marketplace => $asins_chunk_array ) {
59
+ foreach ( $asins_chunk_array as $asins_chunk ) {
60
+ $queue_item = array( Cron_Constants::ASIN_KEY => $asins_chunk, Cron_Constants::MARKETPLACE_KEY => $marketplace );
61
+ $this->update_table_cron_task->push_to_queue( $queue_item );
62
+ }
63
+ }
64
+
65
+ $this->update_table_cron_task->save()->dispatch();
66
+ }
67
+
68
+ private function break_into_chunks( $item ) {
69
+ return array_chunk( $item, 10 );
70
+ }
71
+
72
+ /**
73
+ * Delete entries with last access time more than 24 hours from the table
74
+ *
75
+ * @since 1.8.0
76
+ */
77
+ public function delete_from_table() {
78
+ $this->item_lookup_response_cache->delete_old_asins();
79
+ }
80
+
81
+ /**
82
+ * Add cron intervals for cron tasks which update and delete the entries in the table.
83
+ *
84
+ * @since 1.8.0
85
+ *
86
+ * @param array $schedules Array containing cron schedules.
87
+ *
88
+ * @return array Modified schedules.
89
+ */
90
+ public function add_cron_intervals( $schedules ) {
91
+ if ( ! array_key_exists( Cron_Constants::UPDATE_TABLE_CRON_SCHEDULE_NAME, $schedules ) ) {
92
+ $schedules[Cron_Constants::UPDATE_TABLE_CRON_SCHEDULE_NAME] = array(
93
+ 'interval' => $this->get_cron_interval_value(),
94
+ 'display' => esc_html__( Cron_Constants::UPDATE_TABLE_CRON_SCHEDULE_NAME ),
95
+ );
96
+ }
97
+ if ( ! array_key_exists( Cron_Constants::DELETE_FROM_TABLE_CRON_SCHEDULE_NAME, $schedules ) ) {
98
+ $schedules[Cron_Constants::DELETE_FROM_TABLE_CRON_SCHEDULE_NAME] = array(
99
+ 'interval' => Cron_Constants::DELETE_FROM_TABLE_CRON_SCHEDULE_VALUE,
100
+ 'display' => esc_html__( Cron_Constants::DELETE_FROM_TABLE_CRON_SCHEDULE_NAME ),
101
+ );
102
+ }
103
+
104
+ return $schedules;
105
+ }
106
+
107
+ /**
108
+ * Get cron schedule value from wp_options if it is available, otherwise it returns default value.
109
+ * The purpose of making it to read from wp_option is to make it testable.
110
+ * @return int cron interval value.
111
+ */
112
+ private function get_cron_interval_value()
113
+ {
114
+ return get_option(Db_Constants::CRON_UPDATE_INTERVAL, Cron_Constants::UPDATE_TABLE_CRON_SCHEDULE_DEFAULT_VALUE);;
115
+ }
116
+
117
+ }
cron/cron_schedule_manager.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\cron;
16
+
17
+ use AmazonAssociatesLinkBuilder\constants\Cron_Constants;
18
+ /**
19
+ * Class which schedules and unschedules cron tasks
20
+ *
21
+ * @since 1.8.0
22
+ * @package AmazonAssociatesLinkBuilder
23
+ * @subpackage AmazonAssociatesLinkBuilder/cron
24
+ */
25
+ class Cron_Schedule_Manager {
26
+
27
+ /**
28
+ * Schedule cron tasks which update table and delete entries from the table
29
+ *
30
+ * @since 1.8.0
31
+ */
32
+ public function schedule_cron_tasks() {
33
+ if ( ! wp_next_scheduled( Cron_Constants::UPDATE_TABLE_HOOK ) ) {
34
+ wp_schedule_event( time(), Cron_Constants::UPDATE_TABLE_CRON_SCHEDULE_NAME, Cron_Constants::UPDATE_TABLE_HOOK );
35
+ }
36
+ if ( ! wp_next_scheduled( Cron_Constants::DELETE_FROM_TABLE_HOOK ) ) {
37
+ wp_schedule_event( time(), Cron_Constants::DELETE_FROM_TABLE_CRON_SCHEDULE_NAME, Cron_Constants::DELETE_FROM_TABLE_HOOK );
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Unschedule cron tasks which update table and delete entries from the table.
43
+ *
44
+ * @since 1.8.0
45
+ */
46
+ public function unschedule_cron_tasks() {
47
+ if ( $timestamp = wp_next_scheduled( Cron_Constants::UPDATE_TABLE_HOOK ) ) {
48
+ wp_unschedule_event( $timestamp, Cron_Constants::UPDATE_TABLE_HOOK );
49
+ }
50
+ if ( $timestamp = wp_next_scheduled( Cron_Constants::DELETE_FROM_TABLE_HOOK ) ) {
51
+ wp_unschedule_event( $timestamp, Cron_Constants::DELETE_FROM_TABLE_HOOK );
52
+ }
53
+ if ( $timestamp = wp_next_scheduled( Cron_Constants::UPDATE_TABLE_CRON ) ) {
54
+ wp_unschedule_event( $timestamp, Cron_Constants::UPDATE_TABLE_CRON );
55
+ }
56
+ }
57
+ }
cron/update_table_cron_task.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\cron;
16
+
17
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
18
+ use AmazonAssociatesLinkBuilder\configuration\Config_Helper;
19
+ use AmazonAssociatesLinkBuilder\constants\Cron_Constants;
20
+ use AmazonAssociatesLinkBuilder\constants\Db_Constants;
21
+ use AmazonAssociatesLinkBuilder\constants\HTTP_Constants;
22
+ use AmazonAssociatesLinkBuilder\helper\Paapi_Helper;
23
+ use AmazonAssociatesLinkBuilder\helper\Xml_Helper;
24
+ use AmazonAssociatesLinkBuilder\includes\Item_Lookup_Response_Manager;
25
+ use AmazonAssociatesLinkBuilder\rendering\Xml_Manipulator;
26
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
27
+
28
+ /**
29
+ * Class which extends background processing and overrides the task function
30
+ *
31
+ * @since 1.8.0
32
+ * @package AmazonAssociatesLinkBuilder
33
+ * @subpackage AmazonAssociatesLinkBuilder/cron
34
+ */
35
+ class Update_Table_Cron_Task extends \WP_Background_Process {
36
+
37
+ private $paapi_helper;
38
+ private $xml_manipulator;
39
+ private $item_lookup_response_cache;
40
+ private $item_lookup_response_manager;
41
+ // Action string is used in WP_Background_Process's constructor, so it needs to be set here
42
+ protected $prefix = Cron_Constants::BACKGROUND_PROCESSING_PREFIX;
43
+ protected $action = Cron_Constants::BACKGROUND_PROCESSING_ACTION;
44
+
45
+ public function __construct() {
46
+ parent::__construct();
47
+ $this->paapi_helper = new Paapi_Helper();
48
+ $this->xml_manipulator = new Xml_Manipulator( new Xml_Helper( new Config_Helper() ) );
49
+ $this->item_lookup_response_cache = new Item_Lookup_Response_Cache( new Sql_Helper( DB_NAME, Db_Constants::ITEM_LOOKUP_RESPONSE_TABLE_NAME ));
50
+ $this->item_lookup_response_manager = new Item_Lookup_Response_Manager( $this->xml_manipulator );
51
+ }
52
+
53
+ /**
54
+ * Task function which is used to process an item (array of group of asins separated by ",")
55
+ *
56
+ * @since 1.8.0
57
+ *
58
+ * @param array $queue_item Queue item to iterate over
59
+ *
60
+ * @return mixed False is returned if item is completely processed, else modified item is returned for further processing.
61
+ */
62
+ protected function task( $queue_item ) {
63
+ if ( ! $queue_item ) {
64
+ return false;
65
+ }
66
+
67
+ $asins_array = $queue_item[Cron_Constants::ASIN_KEY];
68
+ $marketplace = $queue_item[Cron_Constants::MARKETPLACE_KEY];
69
+ $store_id = $this->paapi_helper->get_store_id_for_marketplace( $marketplace );
70
+
71
+ try {
72
+ $items_array = $this->item_lookup_response_manager->get_response( $marketplace, $asins_array, $store_id );
73
+ $this->item_lookup_response_cache->add( $items_array, $marketplace, false );
74
+ delete_option( Cron_Constants::DELAY_EXPONENT_ON_PAAPI_THROTTLE );
75
+
76
+ // If item is completely processed, remove the item from the queue
77
+ return false;
78
+ } catch ( \Exception $e ) {
79
+ error_log( $this->paapi_helper->get_error_message( $e->getMessage() ) );
80
+
81
+ if( $e->getMessage() === HTTP_Constants::THROTTLE ) {
82
+ $this->exponential_backoff();
83
+ return $queue_item;
84
+ }
85
+ else {
86
+ // Remove item from Queue if there is any other exception (e.g. InvalidParameter etc).
87
+ // The next cron will handle it. Or the item will get evicted after 24 hours from the cache.
88
+ return false;
89
+ }
90
+
91
+ }
92
+ }
93
+
94
+ private function exponential_backoff(){
95
+ if ( ! $delay_exponent = get_option( Cron_Constants::DELAY_EXPONENT_ON_PAAPI_THROTTLE ) ){
96
+ $delay_exponent = Cron_Constants::DELAY_EXPONENT_INITIAL_VALUE;
97
+ }
98
+ $delay = pow( Cron_Constants::DELAY_BASE_VALUE, $delay_exponent) * Cron_Constants::DELAY_CONSTANT_VALUE;
99
+ if( $delay > Cron_Constants::MAX_DELAY_LIMIT ){
100
+ $delay = Cron_Constants::MAX_DELAY_LIMIT;
101
+ } else{
102
+ $delay_exponent++;
103
+ }
104
+ update_option( Cron_Constants::DELAY_EXPONENT_ON_PAAPI_THROTTLE, $delay_exponent );
105
+ usleep( $delay*1000 );
106
+ }
107
+ }
css/aalb_admin.css CHANGED
@@ -19,10 +19,14 @@ input.aalb-admin-input-search {
19
  margin-left: 3px;
20
  margin-right: 3px;
21
  height: 28px;
22
- border: 1px solid #F0C14B;
23
  /* Below width is hardcoded so that placeholder string fits input box for different languages. */
24
  width: 190px;
25
  }
 
 
 
 
26
 
27
  .aalb-admin-searchbox a.aalb-admin-button-create-amazon-shortcode {
28
  box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.4) inset;
@@ -535,4 +539,4 @@ input.aalb-admin-input-search:disabled {
535
 
536
  .aalb-width-10 {
537
  width: 10%
538
- }
19
  margin-left: 3px;
20
  margin-right: 3px;
21
  height: 28px;
22
+ border: 1px solid #F0C14B !important;
23
  /* Below width is hardcoded so that placeholder string fits input box for different languages. */
24
  width: 190px;
25
  }
26
+ .aalb-admin-input-search:focus {
27
+ border-color: #5b9dd9 !important;
28
+ box-shadow: 0 0 2px rgba(30, 140, 190, .8) !important;
29
+ }
30
 
31
  .aalb-admin-searchbox a.aalb-admin-button-create-amazon-shortcode {
32
  box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.4) inset;
539
 
540
  .aalb-width-10 {
541
  width: 10%
542
+ }
helper/paapi_helper.php CHANGED
@@ -18,6 +18,7 @@ use AmazonAssociatesLinkBuilder\constants\Db_Constants;
18
  use AmazonAssociatesLinkBuilder\constants\Paapi_Constants;
19
  use AmazonAssociatesLinkBuilder\constants\HTTP_Constants;
20
  use AmazonAssociatesLinkBuilder\constants\Plugin_Urls;
 
21
 
22
  /**
23
  * Helper class for Paapi
@@ -28,6 +29,12 @@ use AmazonAssociatesLinkBuilder\constants\Plugin_Urls;
28
  */
29
  class Paapi_Helper {
30
 
 
 
 
 
 
 
31
  /**
32
  * Returns the item lookup URL for asins
33
  *
@@ -37,11 +44,13 @@ class Paapi_Helper {
37
  *
38
  * @return string Signed URL for item lookup.
39
  */
40
- function get_item_lookup_url( $asin, $marketplace, $tracking_id ) {
 
 
41
  $params = array(
42
  "Operation" => "ItemLookup", "ItemId" => "$asin", "IdType" => "ASIN", "ResponseGroup" => "Images,ItemAttributes,OfferFull", "AssociateTag" => "$tracking_id",
43
  );
44
- $url = $this->aws_signed_url( $params, $marketplace );
45
 
46
  return $url;
47
  }
@@ -99,10 +108,11 @@ class Paapi_Helper {
99
  * @return string Signed URL for item search.
100
  */
101
  function get_item_search_url( $search_keywords, $marketplace, $tracking_id ) {
 
102
  $params = array(
103
  "Operation" => "ItemSearch", "SearchIndex" => "All", "Keywords" => "$search_keywords", "ResponseGroup" => "Images,ItemAttributes,Offers", "AssociateTag" => "$tracking_id",
104
  );
105
- $url = $this->aws_signed_url( $params, $marketplace );
106
 
107
  return $url;
108
  }
@@ -142,6 +152,41 @@ class Paapi_Helper {
142
  }
143
  }
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  }
146
 
147
- ?>
18
  use AmazonAssociatesLinkBuilder\constants\Paapi_Constants;
19
  use AmazonAssociatesLinkBuilder\constants\HTTP_Constants;
20
  use AmazonAssociatesLinkBuilder\constants\Plugin_Urls;
21
+ use AmazonAssociatesLinkBuilder\configuration\Config_Loader;
22
 
23
  /**
24
  * Helper class for Paapi
29
  */
30
  class Paapi_Helper {
31
 
32
+ private $config_loader;
33
+
34
+ public function __construct() {
35
+ $this->config_loader = new Config_Loader();
36
+ }
37
+
38
  /**
39
  * Returns the item lookup URL for asins
40
  *
44
  *
45
  * @return string Signed URL for item lookup.
46
  */
47
+ function get_item_lookup_url( $asin_array, $marketplace, $tracking_id ) {
48
+ $marketplace_endpoint = $this->get_marketplace_endpoint( $marketplace );
49
+ $asin = implode( ",", $asin_array );
50
  $params = array(
51
  "Operation" => "ItemLookup", "ItemId" => "$asin", "IdType" => "ASIN", "ResponseGroup" => "Images,ItemAttributes,OfferFull", "AssociateTag" => "$tracking_id",
52
  );
53
+ $url = $this->aws_signed_url( $params, $marketplace_endpoint );
54
 
55
  return $url;
56
  }
108
  * @return string Signed URL for item search.
109
  */
110
  function get_item_search_url( $search_keywords, $marketplace, $tracking_id ) {
111
+ $marketplace_endpoint = $this->get_marketplace_endpoint( $marketplace );
112
  $params = array(
113
  "Operation" => "ItemSearch", "SearchIndex" => "All", "Keywords" => "$search_keywords", "ResponseGroup" => "Images,ItemAttributes,Offers", "AssociateTag" => "$tracking_id",
114
  );
115
+ $url = $this->aws_signed_url( $params, $marketplace_endpoint );
116
 
117
  return $url;
118
  }
152
  }
153
  }
154
 
155
+ /**
156
+ * Get marketplace endpoint for marketplace abbreviation
157
+ *
158
+ * @since 1.8.0
159
+ *
160
+ * @param string $marketplace_abbr Marketplace Abbreviation from shortcode
161
+ *
162
+ * @return string $marketplace_endpoint Marketplace endpoint
163
+ */
164
+ private function get_marketplace_endpoint( $marketplace_abbr ) {
165
+ $aalb_marketplace_names = $this->config_loader->fetch_marketplaces();
166
+ $marketplace_endpoint = array_search( $marketplace_abbr, $aalb_marketplace_names );
167
+
168
+ return $marketplace_endpoint;
169
+ }
170
+
171
+ /**
172
+ * Returns default store_id for given marketplace.
173
+ *
174
+ * @param $marketplace
175
+ *
176
+ * @return string store_id for given marketplace
177
+ */
178
+ public function get_store_id_for_marketplace( $marketplace ){
179
+ try{
180
+ $store_ids_list = json_decode( get_option( Db_Constants::STORE_IDS ));
181
+ $store_ids = $store_ids_list->{$marketplace};
182
+ $store_id = $store_ids[0];
183
+ } catch( \Exception $e ){
184
+ error_log("No store_id found for marketplace {$marketplace}");
185
+ $store_id = get_option( Db_Constants::DEFAULT_STORE_ID );
186
+ }
187
+ return $store_id;
188
+ }
189
+
190
  }
191
 
192
+ ?>
helper/plugin_helper.php CHANGED
@@ -15,6 +15,7 @@ namespace AmazonAssociatesLinkBuilder\helper;
15
 
16
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
17
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
 
18
 
19
  /**
20
  * Helper class for commonly used functions in the plugin.
@@ -37,7 +38,7 @@ class Plugin_Helper {
37
  *
38
  * @return string Template cache key.
39
  */
40
- public function build_template_cache_key( $asins, $marketplace, $store, $template ) {
41
  return 'aalb' . '-' . $asins . '-' . $marketplace . '-' . $store . '-' . $template;
42
  }
43
 
@@ -326,7 +327,8 @@ class Plugin_Helper {
326
  Db_Constants::MAXMIND_DB_LAST_UPLOAD_PATH => get_option( Db_Constants::CUSTOM_UPLOAD_PATH ),
327
  Db_Constants::GEOLITE_DB_DOWNLOAD_RETRY_ON_FAILURE_DURATION => AALB_GEOLITE_DB_DOWNLOAD_RETRY_DURATION_MIN,
328
  Db_Constants::GEOLITE_DB_DOWNLOAD_FAILED_ATTEMPTS => 0,
329
- Db_Constants::MARKETPLACE_NAMES => array()
 
330
  );
331
  }
332
 
15
 
16
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
17
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
18
+ use AmazonAssociatesLinkBuilder\constants\Cron_Constants;
19
 
20
  /**
21
  * Helper class for commonly used functions in the plugin.
38
  *
39
  * @return string Template cache key.
40
  */
41
+ public function build_display_unit_cache_key( $asins, $marketplace, $store, $template ) {
42
  return 'aalb' . '-' . $asins . '-' . $marketplace . '-' . $store . '-' . $template;
43
  }
44
 
327
  Db_Constants::MAXMIND_DB_LAST_UPLOAD_PATH => get_option( Db_Constants::CUSTOM_UPLOAD_PATH ),
328
  Db_Constants::GEOLITE_DB_DOWNLOAD_RETRY_ON_FAILURE_DURATION => AALB_GEOLITE_DB_DOWNLOAD_RETRY_DURATION_MIN,
329
  Db_Constants::GEOLITE_DB_DOWNLOAD_FAILED_ATTEMPTS => 0,
330
+ Db_Constants::MARKETPLACE_NAMES => array(),
331
+ Db_Constants::CRON_UPDATE_INTERVAL => Cron_Constants::UPDATE_TABLE_CRON_SCHEDULE_DEFAULT_VALUE
332
  );
333
  }
334
 
includes/aalb_initializer.php CHANGED
@@ -16,6 +16,9 @@ use AmazonAssociatesLinkBuilder\includes\Plugin_Manager;
16
  use AmazonAssociatesLinkBuilder\includes\Deactivator;
17
  use AmazonAssociatesLinkBuilder\includes\Activator;
18
  use AmazonAssociatesLinkBuilder\includes\Autoloader;
 
 
 
19
 
20
  /**
21
  * The class does all the initialisation of the plugin
16
  use AmazonAssociatesLinkBuilder\includes\Deactivator;
17
  use AmazonAssociatesLinkBuilder\includes\Activator;
18
  use AmazonAssociatesLinkBuilder\includes\Autoloader;
19
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
20
+ use AmazonAssociatesLinkBuilder\constants\Db_Constants;
21
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
22
 
23
  /**
24
  * The class does all the initialisation of the plugin
includes/activator.php CHANGED
@@ -14,7 +14,10 @@ and limitations under the License.
14
 
15
  namespace AmazonAssociatesLinkBuilder\includes;
16
 
 
 
17
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
 
18
 
19
  /**
20
  * Fired during the plugin activation
@@ -26,6 +29,11 @@ use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
26
  * @subpackage AmazonAssociatesLinkBuilder/includes
27
  */
28
  class Activator {
 
 
 
 
 
29
  /**
30
  * Add the template names to the database from the filesystem.
31
  *
@@ -43,7 +51,8 @@ class Activator {
43
  */
44
  function activate() {
45
  $this->load_templates();
 
46
  }
47
  }
48
 
49
- ?>
14
 
15
  namespace AmazonAssociatesLinkBuilder\includes;
16
 
17
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
18
+ use AmazonAssociatesLinkBuilder\constants\Db_Constants;
19
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
20
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
21
 
22
  /**
23
  * Fired during the plugin activation
29
  * @subpackage AmazonAssociatesLinkBuilder/includes
30
  */
31
  class Activator {
32
+ private $item_lookup_response_cache;
33
+
34
+ public function __construct() {
35
+ $this->item_lookup_response_cache = new Item_Lookup_Response_Cache( new Sql_Helper( DB_NAME, Db_Constants::ITEM_LOOKUP_RESPONSE_TABLE_NAME ) );
36
+ }
37
  /**
38
  * Add the template names to the database from the filesystem.
39
  *
51
  */
52
  function activate() {
53
  $this->load_templates();
54
+ $this->item_lookup_response_cache->init();
55
  }
56
  }
57
 
58
+ ?>
includes/autoloader.php CHANGED
@@ -60,7 +60,9 @@ class Autoloader {
60
  new self( AALB_CONFIGURATION_DIR );
61
  new self( AALB_RENDERING_DIR );
62
  new self( AALB_CACHE_DIR );
 
63
  new self( AALB_CONSTANTS_DIR );
 
64
  }
65
 
66
  /**
60
  new self( AALB_CONFIGURATION_DIR );
61
  new self( AALB_RENDERING_DIR );
62
  new self( AALB_CACHE_DIR );
63
+ new self( AALB_SQL_DIR );
64
  new self( AALB_CONSTANTS_DIR );
65
+ new self( AALB_CRON_DIR );
66
  }
67
 
68
  /**
includes/deactivator.php CHANGED
@@ -13,7 +13,11 @@ and limitations under the License.
13
  */
14
  namespace AmazonAssociatesLinkBuilder\includes;
15
 
 
 
 
16
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
 
17
 
18
  /**
19
  * Fired during the plugin deactivation
@@ -27,9 +31,13 @@ use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
27
  */
28
  class Deactivator {
29
  private $plugin_helper;
 
 
30
 
31
  public function __construct() {
32
  $this->plugin_helper = new Plugin_Helper();
 
 
33
  }
34
 
35
  /**
@@ -47,6 +55,8 @@ class Deactivator {
47
  * @since 1.8.0
48
  */
49
  public function deactivate() {
 
 
50
  $this->remove_cache();
51
  }
52
  }
13
  */
14
  namespace AmazonAssociatesLinkBuilder\includes;
15
 
16
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
17
+ use AmazonAssociatesLinkBuilder\constants\Db_Constants;
18
+ use AmazonAssociatesLinkBuilder\cron\Cron_Schedule_Manager;
19
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
20
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
21
 
22
  /**
23
  * Fired during the plugin deactivation
31
  */
32
  class Deactivator {
33
  private $plugin_helper;
34
+ private $item_lookup_response_cache;
35
+ private $cron_schedule_manager;
36
 
37
  public function __construct() {
38
  $this->plugin_helper = new Plugin_Helper();
39
+ $this->item_lookup_response_cache = new Item_Lookup_Response_Cache( new Sql_Helper( DB_NAME, Db_Constants::ITEM_LOOKUP_RESPONSE_TABLE_NAME ) );
40
+ $this->cron_schedule_manager = new Cron_Schedule_Manager();
41
  }
42
 
43
  /**
55
  * @since 1.8.0
56
  */
57
  public function deactivate() {
58
+ $this->item_lookup_response_cache->clear();
59
+ $this->cron_schedule_manager->unschedule_cron_tasks();
60
  $this->remove_cache();
61
  }
62
  }
includes/gb_block_manager.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\includes;
16
+
17
+ use AmazonAssociatesLinkBuilder\constants\GB_Block_Constants;
18
+ use AmazonAssociatesLinkBuilder\shortcode\Shortcode_Loader;
19
+
20
+ /**
21
+ * Class to manage plugin's gutenberg block.
22
+ * @since 1.9.0
23
+ * @package AmazonAssociatesLinkBuilder
24
+ * @subpackage AmazonAssociatesLinkBuilder\includes
25
+ */
26
+ class GB_Block_Manager
27
+ {
28
+ private $shortcode_loader;
29
+
30
+ const OPENING_SQUARE_BRACKET = '[';
31
+ const CLOSING_SQUARE_BRACKET = ']';
32
+ const TYPE_ARRAY = 'array';
33
+ const ASIN = 'asin';
34
+ const ASINS = 'asins';
35
+
36
+ public function __construct()
37
+ {
38
+ $this->shortcode_loader = new Shortcode_Loader();
39
+ }
40
+
41
+ /**
42
+ * Register Gutenberg block.
43
+ */
44
+ public function register_gb_block()
45
+ {
46
+ /**
47
+ * Check to confirm if Gutenberg is active.
48
+ */
49
+ if (!$this->is_gb_block_supported()) {
50
+ // Gutenberg is not active.
51
+ return false;
52
+ }
53
+
54
+ wp_register_script(
55
+ GB_Block_Constants::GB_SCRIPT_HANDLE,
56
+ AALB_GB_BLOCK_JS_URL,
57
+ array('wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'wp-i18n', 'wp-edit-post', 'wp-element', 'wp-editor', 'wp-components', 'wp-data', 'wp-plugins', 'wp-edit-post', 'wp-api', 'wp-blocks'),
58
+ filemtime(AALB_GB_BLOCK_JS_FILE)
59
+ );
60
+
61
+ register_block_type('amazon-associates-link-builder/aalb-gutenberg-block', array(
62
+ 'attributes' => array(
63
+ GB_Block_Constants::SHORTCODE_ATTR => array(
64
+ 'type' => GB_Block_Constants::SHORTCODE_ATTR_TYPE,
65
+ ),
66
+ GB_Block_Constants::SEARCH_KEYWORD => array(
67
+ 'type' => GB_Block_Constants::SEARCH_KEYWORD_TYPE,
68
+ )
69
+ ),
70
+ 'editor_script' => 'amazon-associates-link-builder-gb-block',
71
+ 'render_callback' => function ($attributes) {
72
+ $shortcode_val = $this->get_shortcode_value_from_attributes($attributes);
73
+ return $this->is_valid_shortcode($shortcode_val) ? $this->get_render_output($shortcode_val) : null;
74
+ }
75
+ ));
76
+ }
77
+
78
+ /**
79
+ * @return bool - returns whether Gutenberg editor supported or not.
80
+ */
81
+ public function is_gb_block_supported()
82
+ {
83
+ return function_exists(GB_Block_Constants::GB_SUPPORTED_IDENTIFIER_METHOD);
84
+ }
85
+
86
+ /**
87
+ * Check if a shortcode is valid or not.
88
+ * It validate by checking the following :-
89
+ * * If type of $shortcode is array.
90
+ * * If $shortcode contains 'asin' or 'asins' keys.
91
+ *
92
+ * This method is used to check if shortcode attributes are added or not.
93
+ *
94
+ * @param $shortcode - shortcode.
95
+ * @return bool
96
+ */
97
+ private function is_valid_shortcode($shortcode)
98
+ {
99
+ return (gettype($shortcode) == $this::TYPE_ARRAY) && ($shortcode[$this::ASIN] != null || $shortcode[$this::ASINS] != null);
100
+ }
101
+
102
+ private function get_render_output($shortcode_val)
103
+ {
104
+ return $this->shortcode_loader->amazon_link_shortcode_callback($shortcode_val);
105
+ }
106
+
107
+ /**
108
+ * @param $attributes
109
+ * @return mixed
110
+ */
111
+ private function get_shortcode_value_from_attributes($attributes)
112
+ {
113
+ return shortcode_parse_atts(trim(trim($attributes[GB_Block_Constants::SHORTCODE_ATTR], $this::OPENING_SQUARE_BRACKET), $this::CLOSING_SQUARE_BRACKET));
114
+ }
115
+ }
116
+
117
+ ?>
includes/item_lookup_response_manager.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\includes;
16
+
17
+ use AmazonAssociatesLinkBuilder\constants\Paapi_Constants;
18
+ use AmazonAssociatesLinkBuilder\helper\Paapi_Helper;
19
+ use AmazonAssociatesLinkBuilder\rendering\Xml_Manipulator;
20
+
21
+ /**
22
+ * Class to manage item lookup response
23
+ *
24
+ * @since 1.8.0
25
+ * @package AmazonAssociatesLinkBuilder
26
+ * @subpackage AmazonAssociatesLinkBuilder/includes
27
+ */
28
+ class Item_Lookup_Response_Manager {
29
+
30
+ private $xml_manipulator;
31
+ private $paapi_helper;
32
+ private $remote_loader;
33
+
34
+ public function __construct( Xml_Manipulator $xml_manipulator ) {
35
+ $this->xml_manipulator = $xml_manipulator;
36
+ $this->paapi_helper = new Paapi_Helper();
37
+ $this->remote_loader = new Remote_Loader();
38
+ }
39
+
40
+ /**
41
+ * Parses the item lookup response and checks if the SIMPLE XML element object is generated successfully and has no error code from PA-API
42
+ *
43
+ * @since 1.8.0
44
+ *
45
+ * @param string $response Well-formed XML string
46
+ *
47
+ * @throws \Exception if xml object has an error code from PA-API
48
+ */
49
+ public function validate( $xml_response ) {
50
+ if ( ! $this->should_render_xml( $xml_response ) ) {
51
+ throw new \Exception( $xml_response->Items->Request->Errors->Error->Code );
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Whether to allow xml to be rendered
57
+ *
58
+ * @since 1.4.7
59
+ *
60
+ * @param \SimpleXMLElement $xml Well-formed XML string
61
+ *
62
+ * @return boolean should_render_xml
63
+ */
64
+ private function should_render_xml( $xml ) {
65
+ return ! isset( $xml->Items->Request->Errors->Error ) || $this->is_error_acceptable( $xml );
66
+ }
67
+
68
+ /**
69
+ * Whether the error is acceptable. For now, It is acceptable for Invalid Parameter value with at least one item set.
70
+ * This handles the case when an expired ASIN is present in a list of products and thus unblocks the ad rendering.
71
+ *
72
+ * @since 1.8.0
73
+ *
74
+ * @param \SimpleXMLElement $xml Well-formed XML string
75
+ *
76
+ * @return boolean is_error_acceptable
77
+ */
78
+ private function is_error_acceptable( $xml ) {
79
+ return $xml->Items->Request->Errors->Error->Code == Paapi_Constants::INVALID_PARAMETER_VALUE_ERROR && isset( $xml->Items->Item );
80
+ }
81
+
82
+ /**
83
+ * Get the item lookup response by creating required parameters and then making a GET request.
84
+ *
85
+ * @param String $marketplace marketplace
86
+ * @param array $asins_array array of asins
87
+ * @param String $store_id store id of associate
88
+ *
89
+ * @return array array of asin => response items
90
+ */
91
+ public function get_response( $marketplace, $asins_array, $store_id ) {
92
+ $url = $this->paapi_helper->get_item_lookup_url( $asins_array, $marketplace, $store_id );
93
+ $response = $this->remote_loader->load( $url );
94
+
95
+ $xml_response = $this->xml_manipulator->parse( $response );
96
+ $this->validate( $xml_response );
97
+
98
+ $customized_response = $this->xml_manipulator->get_customized_items_object( $this->xml_manipulator->unescape_numeric_character_references( $response ), $marketplace );
99
+ $items_array = $this->break_response_into_asin_response_map( $customized_response );
100
+
101
+ return $items_array;
102
+ }
103
+
104
+ /**
105
+ * Break the response into asin response map
106
+ *
107
+ * @since 1.8.0
108
+ *
109
+ * @param \SimpleXMLElement $response Xml response
110
+ *
111
+ * @return array Asin => response map
112
+ */
113
+ private function break_response_into_asin_response_map( $response ){
114
+ $items_array = array();
115
+ foreach ( $response->Item as $item ){
116
+ $items_array[$item->ASIN->__toString()] = $item->asXML();
117
+ }
118
+
119
+ return $items_array;
120
+ }
121
+ }
includes/plugin_manager.php CHANGED
@@ -13,6 +13,9 @@ and limitations under the License.
13
  */
14
  namespace AmazonAssociatesLinkBuilder\includes;
15
 
 
 
 
16
  use AmazonAssociatesLinkBuilder\shortcode\Shortcode_Manager;
17
  use AmazonAssociatesLinkBuilder\shortcode\Shortcode_Loader;
18
  use AmazonAssociatesLinkBuilder\includes\Hook_Loader;
@@ -24,6 +27,7 @@ use AmazonAssociatesLinkBuilder\admin\Plugin_Admin;
24
  use AmazonAssociatesLinkBuilder\admin\sidebar\Sidebar;
25
  use AmazonAssociatesLinkBuilder\rendering\Content_Filter;
26
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
 
27
 
28
  /**
29
  * The class that manages all the events of the wordpress.
@@ -37,11 +41,15 @@ class Plugin_Manager {
37
  protected $hook_loader;
38
  protected $shortcode_loader;
39
  protected $shortcode_manager;
 
 
40
 
41
  public function __construct() {
42
  $this->hook_loader = new Hook_Loader();
43
  $this->shortcode_loader = new Shortcode_Loader();
44
  $this->shortcode_manager = new Shortcode_Manager();
 
 
45
 
46
  //add the hooks specific to admin.
47
  $this->add_admin_hooks();
@@ -51,6 +59,9 @@ class Plugin_Manager {
51
 
52
  //Add the hooks for the rendering Settings page of plugin
53
  $this->add_credentials_hooks();
 
 
 
54
  }
55
 
56
  /**
@@ -65,6 +76,7 @@ class Plugin_Manager {
65
  $this->hook_loader->add_action( 'wp_ajax_get_link_code', $plugin_admin, 'get_link_code' );
66
  $this->hook_loader->add_action( 'wp_ajax_get_custom_template_content', $plugin_admin, 'get_custom_template_content' );
67
  $this->hook_loader->add_action( 'media_buttons', $plugin_admin, 'admin_display_callback' );
 
68
  $this->hook_loader->add_action( 'admin_footer', $plugin_admin, 'admin_footer_callback' );
69
  $this->hook_loader->add_action( 'plugins_loaded', $plugin_admin, 'check_update' );
70
 
@@ -96,6 +108,18 @@ class Plugin_Manager {
96
  $this->hook_loader->add_action( 'admin_enqueue_scripts', $credentials_helper, 'aalb_credentials_enqueue_script' );
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  /**
100
  * Execute all the wordpress hooks and shortcodes.
101
  *
13
  */
14
  namespace AmazonAssociatesLinkBuilder\includes;
15
 
16
+ use AmazonAssociatesLinkBuilder\constants\Cron_Constants;
17
+ use AmazonAssociatesLinkBuilder\cron\Cron_Manager;
18
+ use AmazonAssociatesLinkBuilder\cron\Cron_Schedule_Manager;
19
  use AmazonAssociatesLinkBuilder\shortcode\Shortcode_Manager;
20
  use AmazonAssociatesLinkBuilder\shortcode\Shortcode_Loader;
21
  use AmazonAssociatesLinkBuilder\includes\Hook_Loader;
27
  use AmazonAssociatesLinkBuilder\admin\sidebar\Sidebar;
28
  use AmazonAssociatesLinkBuilder\rendering\Content_Filter;
29
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
30
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
31
 
32
  /**
33
  * The class that manages all the events of the wordpress.
41
  protected $hook_loader;
42
  protected $shortcode_loader;
43
  protected $shortcode_manager;
44
+ private $cron_manager;
45
+ private $cron_schedule_manager;
46
 
47
  public function __construct() {
48
  $this->hook_loader = new Hook_Loader();
49
  $this->shortcode_loader = new Shortcode_Loader();
50
  $this->shortcode_manager = new Shortcode_Manager();
51
+ $this->cron_manager = new Cron_Manager( new Sql_Helper( DB_NAME, Db_Constants::ITEM_LOOKUP_RESPONSE_TABLE_NAME ) );
52
+ $this->cron_schedule_manager = new Cron_Schedule_Manager();
53
 
54
  //add the hooks specific to admin.
55
  $this->add_admin_hooks();
59
 
60
  //Add the hooks for the rendering Settings page of plugin
61
  $this->add_credentials_hooks();
62
+
63
+ //Add the hooks for auto updating the cache
64
+ $this->add_item_lookup_cache_auto_update_hooks();
65
  }
66
 
67
  /**
76
  $this->hook_loader->add_action( 'wp_ajax_get_link_code', $plugin_admin, 'get_link_code' );
77
  $this->hook_loader->add_action( 'wp_ajax_get_custom_template_content', $plugin_admin, 'get_custom_template_content' );
78
  $this->hook_loader->add_action( 'media_buttons', $plugin_admin, 'admin_display_callback' );
79
+ $this->hook_loader->add_action( 'init', $plugin_admin, 'register_gb_block_if_supported');
80
  $this->hook_loader->add_action( 'admin_footer', $plugin_admin, 'admin_footer_callback' );
81
  $this->hook_loader->add_action( 'plugins_loaded', $plugin_admin, 'check_update' );
82
 
108
  $this->hook_loader->add_action( 'admin_enqueue_scripts', $credentials_helper, 'aalb_credentials_enqueue_script' );
109
  }
110
 
111
+ /**
112
+ * Add actions to item lookup cache auto update hooks
113
+ *
114
+ * @since 1.8.0
115
+ */
116
+ private function add_item_lookup_cache_auto_update_hooks(){
117
+ $this->hook_loader->add_action( Cron_Constants::UPDATE_TABLE_HOOK, $this->cron_manager, 'update_table' );
118
+ $this->hook_loader->add_action( Cron_Constants::DELETE_FROM_TABLE_HOOK, $this->cron_manager, 'delete_from_table' );
119
+ add_filter( 'cron_schedules', array($this->cron_manager, 'add_cron_intervals') );
120
+ $this->cron_schedule_manager->schedule_cron_tasks();
121
+ }
122
+
123
  /**
124
  * Execute all the wordpress hooks and shortcodes.
125
  *
js/aalb_admin.js CHANGED
@@ -38,6 +38,7 @@ var aalb_admin_object = (function( $ ) {
38
  var tab_counter = 2;
39
  var marketplace_pop_up_json = [];
40
  var keyword_for_search = "";
 
41
 
42
  var meta_box_tab_context = {
43
  "searchbox_placeholder" : aalb_strings.searchbox_placeholder,
@@ -216,6 +217,21 @@ var aalb_admin_object = (function( $ ) {
216
  }
217
  }
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  /**
220
  * Returns elements not present in second array but in first
221
  *
@@ -526,6 +542,34 @@ var aalb_admin_object = (function( $ ) {
526
  }
527
  }
528
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  /**
530
  * Search items from within the thickbox
531
  *
@@ -677,7 +721,7 @@ var aalb_admin_object = (function( $ ) {
677
  * @param Object shortcodeJson Object describing the shortcode
678
  */
679
  function add_shortcode_click_handler( shortcodeJson ) {
680
- create_shortcode( shortcodeJson );
681
  tb_remove();
682
  }
683
 
@@ -729,6 +773,15 @@ var aalb_admin_object = (function( $ ) {
729
  send_to_editor( buildShortcode( shortcodeJson ) );
730
  }
731
 
 
 
 
 
 
 
 
 
 
732
  /**
733
  * Gets the selected Asins
734
  *
@@ -848,9 +901,23 @@ var aalb_admin_object = (function( $ ) {
848
  admin_searchbox_tooltip.removeClass( 'aalb-admin-hide-display' );
849
  }
850
 
 
 
 
 
 
 
 
 
851
  return {
852
- admin_show_create_shortcode_popup : admin_show_create_shortcode_popup,
853
- editor_searchbox_keypress_event_handler: editor_searchbox_keypress_event_handler
 
 
 
 
 
 
854
  };
855
 
856
- })( jQuery );
38
  var tab_counter = 2;
39
  var marketplace_pop_up_json = [];
40
  var keyword_for_search = "";
41
+ var gb_props;
42
 
43
  var meta_box_tab_context = {
44
  "searchbox_placeholder" : aalb_strings.searchbox_placeholder,
217
  }
218
  }
219
 
220
+ /**
221
+ * onKeyPress event handler for editor search box for gutenberg editor.
222
+ *
223
+ * @param HTML_DOM_EVENT event OnKeyPress event
224
+ * @param HTMLElement caller_element caller of this function
225
+ *
226
+ * @since 1.9.0
227
+ */
228
+ function gutenberg_editor_onkeypress(event, props) {
229
+ if (event.keyCode === ENTER_KEY_CODE) {
230
+ event.preventDefault();
231
+ admin_show_create_shortcode_popup_gutenberg(props);
232
+ }
233
+ }
234
+
235
  /**
236
  * Returns elements not present in second array but in first
237
  *
542
  }
543
  }
544
 
545
+ /**
546
+ * Display pop up thickbox in gutenberg editor.
547
+ * @param props - Gutenberg props.
548
+ */
549
+ function admin_show_create_shortcode_popup_gutenberg(props) {
550
+ if (props && props.attributes.searchKeyword) {
551
+ gb_props = props;
552
+ keyword_for_search = props.attributes.searchKeyword;
553
+ $('#aalb-search-pop-up').remove();
554
+ tab_counter = 2;
555
+ load_search_pop_up();
556
+
557
+ var pop_up_container = $('#aalb-tabs').find('.aalb-pop-up-container');
558
+ add_tab();
559
+ insert_search_loading_box(pop_up_container);
560
+ add_entry_in_marketplace_json(default_marketplace, default_store_id);
561
+ tb_show(aalb_strings.add_aalb_shortcode, '#TB_inline?inlineId=aalb-admin-popup-container', false);
562
+ resize_thickbox();
563
+ // Getting the Itemsearch results
564
+ admin_get_item_search_items(keyword_for_search, pop_up_container, props);
565
+ //Setting search input of shortcode popup with search keyword.
566
+ $(".aalb-admin-popup-input-search").attr('value', keyword_for_search);
567
+
568
+ } else {
569
+ alert(aalb_strings.empty_product_search_bar);
570
+ }
571
+ }
572
+
573
  /**
574
  * Search items from within the thickbox
575
  *
721
  * @param Object shortcodeJson Object describing the shortcode
722
  */
723
  function add_shortcode_click_handler( shortcodeJson ) {
724
+ is_editor_gutenberg() ? create_shortcode_in_gb(shortcodeJson) : create_shortcode(shortcodeJson);
725
  tb_remove();
726
  }
727
 
773
  send_to_editor( buildShortcode( shortcodeJson ) );
774
  }
775
 
776
+ /**
777
+ * Add shortcode attribute in gutenberg block attribute.
778
+ * @param shortcodeJson
779
+ */
780
+ function create_shortcode_in_gb(shortcodeJson) {
781
+ shortCoeValue = buildShortcode(shortcodeJson);
782
+ gb_props.setAttributes({shortCodeContent: shortCoeValue});
783
+ }
784
+
785
  /**
786
  * Gets the selected Asins
787
  *
901
  admin_searchbox_tooltip.removeClass( 'aalb-admin-hide-display' );
902
  }
903
 
904
+ /**
905
+ * Function to check whether Gutenberg is activated and the current editor is set to load Gutenberg.
906
+ * gb_props will not be set if editor is not gutenberg.
907
+ */
908
+ function is_editor_gutenberg() {
909
+ return (gb_props != null);
910
+ }
911
+
912
  return {
913
+ admin_show_create_shortcode_popup : admin_show_create_shortcode_popup,
914
+ editor_searchbox_keypress_event_handler : editor_searchbox_keypress_event_handler,
915
+
916
+ // Callbacks for gutenberg editor.
917
+ admin_show_create_shortcode_popup_gutenberg : admin_show_create_shortcode_popup_gutenberg,
918
+ gutenberg_editor_onkeypress : gutenberg_editor_onkeypress
919
+
920
+
921
  };
922
 
923
+ })( jQuery );
js/aalb_gb_block.js ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function (blocks, editor, element) {
2
+ var RichText = editor.RichText;
3
+
4
+ var el = element.createElement;
5
+ var ENTER_KEY_CODE = 13;
6
+ const AMZN_ICON_URL = 'https://images-na.ssl-images-amazon.com/images/G/01/PAAPI/AmazonAssociatesLinkBuilder/amazon_icon._V506839993_.png';
7
+ const AALB_GB_BLOCK_TITLE = 'Amazon Associates Link Builder';
8
+
9
+
10
+ blocks.registerBlockType('amazon-associates-link-builder/aalb-gutenberg-block', {
11
+ title: AALB_GB_BLOCK_TITLE,
12
+ icon: el('img',
13
+ {
14
+ id: 'aalb-img',
15
+ className: 'aalb-admin-searchbox-amzlogo',
16
+ src: AMZN_ICON_URL
17
+ }
18
+ ),
19
+ category: 'widgets',
20
+
21
+ attributes: {
22
+ shortCodeContent: {
23
+ type: 'string',
24
+ },
25
+ searchKeyword: {
26
+ type: 'string',
27
+ },
28
+ },
29
+
30
+ edit: function (props) {
31
+
32
+ var searchKeyword = props.attributes.searchKeyword;
33
+ var shortCodeContent = props.attributes.shortCodeContent;
34
+ var isSearchDisabled = api_pref.IS_PAAPI_CREDENTIALS_NOT_SET || api_pref.IS_STORE_ID_CREDENTIALS_NOT_SET;
35
+
36
+ function onChangeContent(event) {
37
+ props.setAttributes({searchKeyword: event.target.value});
38
+ }
39
+
40
+ function onChangeShortCodeContent(newContent) {
41
+ props.setAttributes({shortCodeContent: newContent});
42
+ }
43
+
44
+ var onSearchClick = function (event) {
45
+ aalb_admin_object.admin_show_create_shortcode_popup_gutenberg(props);
46
+ };
47
+
48
+ function getSearchButtonClassName() {
49
+ return isSearchDisabled ?
50
+ 'button aalb-admin-button-create-amazon-shortcode aalb-admin-button-create-amazon-shortcode-disabled'
51
+ : 'button aalb-admin-button-create-amazon-shortcode' ;
52
+ }
53
+
54
+ function getSpanClassName() {
55
+ return isSearchDisabled ? 'aalb-admin-searchbox-tooltip-text' : 'aalb-admin-editor-tooltip aalb-admin-hide-display';
56
+ }
57
+
58
+ function getSpanErrorMsg() {
59
+ if (api_pref.IS_PAAPI_CREDENTIALS_NOT_SET)
60
+ return aalb_strings.paapi_credentials_not_set;
61
+ else if (api_pref.IS_STORE_ID_CREDENTIALS_NOT_SET)
62
+ return aalb_strings.store_id_credentials_not_set;
63
+ }
64
+
65
+
66
+ return (el('div', {className: 'aalb-admin-inline aalb-admin-searchbox'},
67
+
68
+ el('span',
69
+ {
70
+ className: getSpanClassName(),
71
+ children: el(RichText.Content,
72
+ {
73
+ value: getSpanErrorMsg(),
74
+ }
75
+ )
76
+ }
77
+ ),
78
+
79
+ /**
80
+ * Amazon logo.
81
+ */
82
+ el('img',
83
+ {
84
+ className: 'aalb-admin-searchbox-amzlogo',
85
+ src: AMZN_ICON_URL
86
+ }
87
+ ),
88
+
89
+ /**
90
+ * Search box.
91
+ */
92
+ el('input',
93
+ {
94
+ type: 'text',
95
+ className: 'aalb-admin-input-search',
96
+ name: 'aalb-admin-input-search',
97
+ placeholder: aalb_strings.searchbox_placeholder,
98
+ onKeyPress: function () {
99
+ if (event.keyCode === ENTER_KEY_CODE) {
100
+ aalb_admin_object.gutenberg_editor_onkeypress(event, props);
101
+ }
102
+ },
103
+ onChange: onChangeContent,
104
+ value: searchKeyword,
105
+ disabled: isSearchDisabled,
106
+ }
107
+ ),
108
+
109
+ /**
110
+ * Search button.
111
+ */
112
+ el('a',
113
+ {
114
+ className: getSearchButtonClassName(),
115
+ onClick: onSearchClick
116
+ },
117
+ 'Search'
118
+ ),
119
+
120
+ /**
121
+ * Shortcode text.
122
+ */
123
+ el(RichText,
124
+ {
125
+ tagName: 'p',
126
+ value: shortCodeContent,
127
+ onChange: onChangeShortCodeContent
128
+ }
129
+ )
130
+ )
131
+ );
132
+ },
133
+ save: function (props) {
134
+ /**
135
+ * Server side rendering is handled, so returning null.
136
+ */
137
+ return null;
138
+ },
139
+
140
+ transforms: {
141
+ to: [
142
+ /**
143
+ * Transform to shortcode block.
144
+ */
145
+ {
146
+ type: 'block',
147
+ blocks: ['core/shortcode'],
148
+ transform: function (attributes) {
149
+ return wp.blocks.createBlock('core/shortcode', {
150
+ text: attributes.shortCodeContent,
151
+ });
152
+ },
153
+ },
154
+ ],
155
+ },
156
+ });
157
+
158
+ })(
159
+ window.wp.blocks,
160
+ window.wp.editor,
161
+ window.wp.element
162
+ );
plugin_config.php CHANGED
@@ -20,6 +20,9 @@ define( 'AALB_PLUGIN_MINIMUM_SUPPORTED_PHP_VERSION', '5.4.0' );
20
  define( 'AALB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
21
  define( 'AALB_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
22
 
 
 
 
23
  //Directories
24
  define( 'AALB_TEMPLATE_DIR', AALB_PLUGIN_DIR . 'template/' );
25
  define( 'AALB_ADMIN_DIR', AALB_PLUGIN_DIR . 'admin/' );
@@ -35,12 +38,14 @@ define( 'AALB_IO_DIR', AALB_PLUGIN_DIR . 'io/' );
35
  define( 'AALB_HELPER_DIR', AALB_PLUGIN_DIR . 'helper/' );
36
  define( 'AALB_CONFIGURATION_DIR', AALB_PLUGIN_DIR . 'configuration/' );
37
  define( 'AALB_RENDERING_DIR', AALB_PLUGIN_DIR . 'rendering/' );
 
38
  define( 'AALB_CACHE_DIR', AALB_PLUGIN_DIR . 'cache/' );
39
  define( 'AALB_VIEW_PARTIALS_DIR', AALB_PLUGIN_DIR . 'view/partials/' );
40
  define( 'AALB_VIEW_SIDEBAR_PARTIALS_DIR', AALB_PLUGIN_DIR . 'view/sidebar_partials/' );
41
  define( 'AALB_JS_DIR', AALB_PLUGIN_DIR . 'js/' );
42
  define( 'AALB_CSS_DIR', AALB_PLUGIN_DIR . 'css/' );
43
  define( 'AALB_CONSTANTS_DIR', AALB_PLUGIN_DIR . 'constants/' );
 
44
  define( 'AALB_TEMPLATE_UPLOADS_FOLDER', 'amazon-associates-link-builder/template/' );
45
 
46
  //Classes
@@ -70,6 +75,8 @@ define( 'AALB_SHA2_JS', AALB_PLUGIN_URL . 'lib/js/jssha2/sha2.js' );
70
  define( 'AALB_ADMIN_JS', AALB_PLUGIN_URL . 'js/aalb_admin.js' );
71
  define( 'AALB_TEMPLATE_JS', AALB_PLUGIN_URL . 'js/aalb_template.js' );
72
  define( 'AALB_CREDENTIALS_JS', AALB_PLUGIN_URL . 'js/aalb_credentials.js' );
 
 
73
 
74
  /**
75
  * Icons
@@ -100,8 +107,8 @@ define( 'AALB_GEOLITE_DB_MAX_ALLOWED_AGE', 60 * DAY_IN_SECONDS );
100
  //Note that the plugin uses a two tier cache. It caches the ASINs as well as the rendered templates.
101
  //At any given time the sum of ASIN cache TTL and Rendered AdUnit cache TTL should be less than or equal to one hour.
102
  //The below configuration is compliant with the License Agreement. Any modification may result in the violation of the license agreement.
103
- define( 'AALB_CACHE_FOR_ASIN_RAWINFO_TTL', 30 * MINUTE_IN_SECONDS );
104
  define( 'AALB_CACHE_FOR_ASIN_ADUNIT_TTL', 30 * MINUTE_IN_SECONDS );
 
105
 
106
  define( 'AALB_SETTINGS_PAGE_URL', admin_url( 'admin.php?page=associates-link-builder-settings' ) );
107
  define( 'TRUE', 'true' );
20
  define( 'AALB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
21
  define( 'AALB_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
22
 
23
+ //Library
24
+ define( 'AALB_MUSTACHE_AUTOLOADER_PHP', AALB_PLUGIN_DIR . 'lib/php/Mustache/Autoloader.php' );
25
+
26
  //Directories
27
  define( 'AALB_TEMPLATE_DIR', AALB_PLUGIN_DIR . 'template/' );
28
  define( 'AALB_ADMIN_DIR', AALB_PLUGIN_DIR . 'admin/' );
38
  define( 'AALB_HELPER_DIR', AALB_PLUGIN_DIR . 'helper/' );
39
  define( 'AALB_CONFIGURATION_DIR', AALB_PLUGIN_DIR . 'configuration/' );
40
  define( 'AALB_RENDERING_DIR', AALB_PLUGIN_DIR . 'rendering/' );
41
+ define( 'AALB_SQL_DIR', AALB_PLUGIN_DIR . 'sql/' );
42
  define( 'AALB_CACHE_DIR', AALB_PLUGIN_DIR . 'cache/' );
43
  define( 'AALB_VIEW_PARTIALS_DIR', AALB_PLUGIN_DIR . 'view/partials/' );
44
  define( 'AALB_VIEW_SIDEBAR_PARTIALS_DIR', AALB_PLUGIN_DIR . 'view/sidebar_partials/' );
45
  define( 'AALB_JS_DIR', AALB_PLUGIN_DIR . 'js/' );
46
  define( 'AALB_CSS_DIR', AALB_PLUGIN_DIR . 'css/' );
47
  define( 'AALB_CONSTANTS_DIR', AALB_PLUGIN_DIR . 'constants/' );
48
+ define( 'AALB_CRON_DIR', AALB_PLUGIN_DIR . 'cron/' );
49
  define( 'AALB_TEMPLATE_UPLOADS_FOLDER', 'amazon-associates-link-builder/template/' );
50
 
51
  //Classes
75
  define( 'AALB_ADMIN_JS', AALB_PLUGIN_URL . 'js/aalb_admin.js' );
76
  define( 'AALB_TEMPLATE_JS', AALB_PLUGIN_URL . 'js/aalb_template.js' );
77
  define( 'AALB_CREDENTIALS_JS', AALB_PLUGIN_URL . 'js/aalb_credentials.js' );
78
+ define( 'AALB_GB_BLOCK_JS_URL', AALB_PLUGIN_URL . 'js/aalb_gb_block.js');
79
+ define( 'AALB_GB_BLOCK_JS_FILE', AALB_PLUGIN_DIR . 'js/aalb_gb_block.js');
80
 
81
  /**
82
  * Icons
107
  //Note that the plugin uses a two tier cache. It caches the ASINs as well as the rendered templates.
108
  //At any given time the sum of ASIN cache TTL and Rendered AdUnit cache TTL should be less than or equal to one hour.
109
  //The below configuration is compliant with the License Agreement. Any modification may result in the violation of the license agreement.
 
110
  define( 'AALB_CACHE_FOR_ASIN_ADUNIT_TTL', 30 * MINUTE_IN_SECONDS );
111
+ define( 'AALB_CACHE_FOR_MARKETPLACE_CONFIG_TTL', 3 * DAY_IN_SECONDS );
112
 
113
  define( 'AALB_SETTINGS_PAGE_URL', admin_url( 'admin.php?page=associates-link-builder-settings' ) );
114
  define( 'TRUE', 'true' );
rendering/impression_generator.php CHANGED
@@ -61,16 +61,15 @@ class Impression_Generator {
61
  * @param String $store_id
62
  * @param String $link_code
63
  * @param Integer $org_unit_id
64
- * @param String $asin_group Group of different asins speated by ","
65
  *
66
  * @return String HTML for the pixel image of all asins in $asin_group
67
  *
68
  * @throws \InvalidArgumentException
69
  *
70
  */
71
- private function get_html_for_pixel_image_of_all_asins( $impression_recorder_service_endpoint, $store_id, $link_code, $org_unit_id, $asin_group ) {
72
  $pixel_image_for_all_asins = "";
73
- $asins_array = explode( ',', $asin_group );
74
  foreach ( $asins_array as $asin ) {
75
  $pixel_image_url = $this->get_url_with_query_params( $impression_recorder_service_endpoint, $store_id, $link_code, $org_unit_id, $asin );
76
  $pixel_image_for_all_asins .= $this->get_html_element_for_pixel_image( $pixel_image_url );
61
  * @param String $store_id
62
  * @param String $link_code
63
  * @param Integer $org_unit_id
64
+ * @param Array $asins_array Array of asins
65
  *
66
  * @return String HTML for the pixel image of all asins in $asin_group
67
  *
68
  * @throws \InvalidArgumentException
69
  *
70
  */
71
+ private function get_html_for_pixel_image_of_all_asins( $impression_recorder_service_endpoint, $store_id, $link_code, $org_unit_id, $asins_array ) {
72
  $pixel_image_for_all_asins = "";
 
73
  foreach ( $asins_array as $asin ) {
74
  $pixel_image_url = $this->get_url_with_query_params( $impression_recorder_service_endpoint, $store_id, $link_code, $org_unit_id, $asin );
75
  $pixel_image_for_all_asins .= $this->get_html_element_for_pixel_image( $pixel_image_url );
rendering/template_engine.php CHANGED
@@ -13,16 +13,8 @@ and limitations under the License.
13
  */
14
  namespace AmazonAssociatesLinkBuilder\rendering;
15
 
16
- use AmazonAssociatesLinkBuilder\configuration\Config_Helper;
17
- use AmazonAssociatesLinkBuilder\helper\Xml_Helper;
18
- use AmazonAssociatesLinkBuilder\cache\Cache_Loader;
19
- use AmazonAssociatesLinkBuilder\cache\Cache_Template_Loader;
20
- use AmazonAssociatesLinkBuilder\includes\Remote_Loader;
21
- use AmazonAssociatesLinkBuilder\rendering\Xml_Manipulator;
22
- use AmazonAssociatesLinkBuilder\rendering\Impression_Generator;
23
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
24
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
25
- use AmazonAssociatesLinkBuilder\exceptions\Invalid_Marketplace_Exception;
26
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
27
 
28
  /**
@@ -33,119 +25,13 @@ use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
33
  * @subpackage AmazonAssociatesLinkBuilder/rendering
34
  */
35
  class Template_Engine {
36
- protected $xml_loader;
37
- protected $cache_template_loader;
38
  protected $mustache;
39
- protected $xml_helper;
40
  protected $helper;
41
- protected $impression_generator;
42
- private $config_helper;
43
 
44
  public function __construct() {
45
- $this->xml_loader = new Cache_Loader( new Remote_Loader() );
46
  $this->helper = new Plugin_Helper();
47
- $this->cache_template_loader = new Cache_Template_Loader();
48
  $this->mustache = new \Mustache_Engine( array( 'loader' => new \Mustache_Loader_FilesystemLoader( AALB_TEMPLATE_DIR ) ) );
49
  $this->mustache_custom = new \Mustache_Engine( array( 'loader' => new \Mustache_Loader_FilesystemLoader( $this->helper->get_template_upload_directory() ) ) );
50
- $this->config_helper = new Config_Helper();
51
- $this->xml_manipulator = new Xml_Manipulator( new Xml_Helper( $this->config_helper ) );
52
- $this->impression_generator = new Impression_Generator( $this->config_helper );
53
- }
54
-
55
- /**
56
- * Render the products into the display unit.
57
- * If the display unit exists in the cache return the display unit.
58
- * Else get the xml and render the product.
59
- *
60
- * @since 1.0.0
61
- *
62
- * @param string $display_key Key of the display unit.
63
- * @param string $products_key Key of the combined products.
64
- * @param string $template Template to render the display unit.
65
- * @param string $url Url to get the product from if not present in cache.
66
- * @param string $marketplace Marketplace to which the product belongs.
67
- * @param string $link_code Link Code to be entered in URLS for attribution purposes.
68
- * @param string $store_id Store id of associate
69
- * @param string $asin_group Group of different asins speated by ","
70
- *
71
- * @return string HTML of the disply unit.
72
- */
73
- public function render( $display_key, $products_key, $template, $url, $marketplace, $link_code, $store_id, $asin_group ) {
74
- if ( false === ( $display_unit = $this->cache_template_loader->get_display_unit( $display_key ) ) ) {
75
- $products = $this->get_products( $products_key, $url, $link_code );
76
- $products = $this->unescape_numeric_character_references( $products );
77
-
78
- $custom_items = $this->xml_manipulator->get_customized_items_object( $products, $marketplace );
79
- $display_unit = $this->render_xml( $custom_items, $template );
80
- $display_unit = $this->add_html_for_impression_tracking( $display_unit, $marketplace, $link_code, $store_id, $asin_group );
81
-
82
- $this->cache_template_loader->save_display_unit( $display_key, $display_unit );
83
- }
84
-
85
- return $display_unit;
86
- }
87
-
88
- /**
89
- * Single Escape Numeric Character References(NCR) using regular expression replacement
90
- *
91
- * @since 1.7.0
92
- *
93
- * @param string $products Deserialized XML string with NCRs double escaped
94
- *
95
- * @return string Deserialized XML string with NCRS single escaped
96
- */
97
- private function unescape_numeric_character_references( $products ) {
98
- //Single Escape NCR represented as hex number
99
- $products = preg_replace( "/&amp;(#x[a-fA-F0-9]{4,6};)/", "&$1", $products );
100
-
101
- //Single Escape other special characters escaped by Product Advertising API like Σ(&#931;),Θ(&#920;)
102
- $products = preg_replace( "/&amp;(#[0-9]{1,7};)/", "&$1", $products );
103
-
104
- return $products;
105
- }
106
-
107
-
108
- /**
109
- * Adds pixel image HTML element to the display unit
110
- *
111
- * @since 1.6.0
112
- *
113
- * @param string $display_unit HTML of the display unit.
114
- * @param String $marketplace marketplace
115
- * @param String $store_id Store id of associate
116
- * @param String $link_code Link code used for tracking
117
- * @param String $asin_group Group of different asins speated by ","
118
- *
119
- * @return string $display_unit HTML of the display unit along with pixel image
120
- */
121
- private function add_html_for_impression_tracking( $display_unit, $marketplace, $link_code, $store_id, $asin_group ) {
122
- try {
123
- $impression = $this->impression_generator->get_impression( $marketplace, $link_code, $store_id, $asin_group );
124
- $display_unit = $impression . $display_unit;
125
- } catch ( Invalid_Marketplace_Exception $e ) {
126
- //Do Nothing as it is because of a new marketplace added and we are currently not racling impression for this new marketplace.
127
- } catch ( \InvalidArgumentException $e ) {
128
- error_log( "Aalb_Template_Engine::add_html_for_impression_tracking " . $e->getMessage() );
129
- } catch ( \Exception $e ) {
130
- error_log( "Aalb_Template_Engine::add_html_for_impression_tracking " . $e->getMessage() );
131
- }
132
-
133
- return $display_unit;
134
- }
135
-
136
- /**
137
- * Get the products information.
138
- *
139
- * @since 1.0.0
140
- *
141
- * @param string $key Unique identification of the product.
142
- * @param string $url Signed URL for the PAAPI request.
143
- * @param string $link_code Link Code to be entered in URLS for attribution purposes.
144
- *
145
- * @return string Xml response from PAAPI.
146
- */
147
- private function get_products( $key, $url, $link_code ) {
148
- return $this->xml_loader->load( $key, $url, $link_code );
149
  }
150
 
151
  /**
@@ -158,7 +44,7 @@ class Template_Engine {
158
  *
159
  * @return string HTML of the display unit.
160
  */
161
- private function render_xml( $items, $template ) {
162
  $aalb_default_templates = explode( ",", Plugin_Constants::AMAZON_TEMPLATE_NAMES );
163
  try {
164
  if ( in_array( $template, $aalb_default_templates ) ) {
@@ -174,4 +60,4 @@ class Template_Engine {
174
  }
175
  }
176
 
177
- ?>
13
  */
14
  namespace AmazonAssociatesLinkBuilder\rendering;
15
 
 
 
 
 
 
 
 
16
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
17
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
 
18
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
19
 
20
  /**
25
  * @subpackage AmazonAssociatesLinkBuilder/rendering
26
  */
27
  class Template_Engine {
 
 
28
  protected $mustache;
 
29
  protected $helper;
 
 
30
 
31
  public function __construct() {
 
32
  $this->helper = new Plugin_Helper();
 
33
  $this->mustache = new \Mustache_Engine( array( 'loader' => new \Mustache_Loader_FilesystemLoader( AALB_TEMPLATE_DIR ) ) );
34
  $this->mustache_custom = new \Mustache_Engine( array( 'loader' => new \Mustache_Loader_FilesystemLoader( $this->helper->get_template_upload_directory() ) ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
 
37
  /**
44
  *
45
  * @return string HTML of the display unit.
46
  */
47
+ public function render_xml( $items, $template ) {
48
  $aalb_default_templates = explode( ",", Plugin_Constants::AMAZON_TEMPLATE_NAMES );
49
  try {
50
  if ( in_array( $template, $aalb_default_templates ) ) {
60
  }
61
  }
62
 
63
+ ?>
rendering/xml_manipulator.php CHANGED
@@ -45,82 +45,67 @@ class Xml_Manipulator {
45
  */
46
  public function get_customized_items_object( $products_xml, $marketplace ) {
47
  $simple_xml_object = $this->parse( $products_xml );
48
- $this->validate( $simple_xml_object );
49
  $custom_items = $this->add_custom_nodes( $simple_xml_object->Items, $marketplace );
50
 
51
  return $custom_items;
52
  }
53
 
54
  /**
55
- * Convert the well-formed xml string into a\SimpleXMLElement object.
56
  *
57
  * @since 1.0.0
58
  *
59
  * @param string $xml_string Well-formed XML string
60
  *
 
 
61
  * @return \SimpleXMLElement Php xml object.
62
  */
63
- private function parse( $xml_string ) {
64
  libxml_use_internal_errors( true );
65
-
66
- return simplexml_load_string( $xml_string );
67
- }
68
-
69
- /**
70
- * Checks if SIMPLE XML element object is generated successfully and has no error code from PA-API
71
- *
72
- * @since 1.8.0
73
- *
74
- * @param \SimpleXMLElement $xml Well-formed XML string
75
- *
76
- * @throws \Exception if object is not generated successfully or has an error code from PA-API
77
- */
78
- private function validate( $xml ) {
79
  if ( $xml === false ) {
80
  //Don't translate as this is also dumped in error logs and will facilitate AALB team to debug
81
  throw new \Exception( 'Xml_Manipulator::validate::Failed Loading XML' );
82
- } else if ( ! $this->should_render_xml( $xml ) ) {
83
- throw new \Exception( 'Xml_Manipulator::validate::' . $xml->Items->Request->Errors->Error->Code );
84
  }
85
- }
86
 
87
- /**
88
- * Whether to allow xml to be rendered
89
- *
90
- * @since 1.4.7
91
- *
92
- * @param \SimpleXMLElement $xml Well-formed XML string
93
- *
94
- * @return boolean should_render_xml
95
- */
96
- private function should_render_xml( $xml ) {
97
- return ! isset( $xml->Items->Request->Errors->Error ) || $this->is_error_acceptable( $xml );
98
  }
99
 
100
  /**
101
- * Whether the error is acceptable. For now, It is acceptable for Invalid Parameter value with at least one item set.
102
- * This handles the case when an expired ASIN is present in a list of products and thus unblocks the ad rendering.
103
  *
104
  * @since 1.8.0
105
  *
106
  * @param \SimpleXMLElement $xml Well-formed XML string
 
107
  *
108
- * @return boolean is_error_acceptable
109
  */
110
- private function is_error_acceptable( $xml ) {
111
- return $xml->Items->Request->Errors->Error->Code == Paapi_Constants::INVALID_PARAMETER_VALUE_ERROR && isset( $xml->Items->Item );
 
 
 
 
 
 
112
  }
113
 
114
  /**
115
- * Add custom nodes to xml response
116
  *
117
- * @since 1.0.0
118
  *
119
  * @param \SimpleXMLElement $items Well-formed XML string
 
120
  *
121
  * @return \SimpleXMLElement $items XML String with custom nodes added
122
  */
123
- private function add_custom_nodes( $items, $marketplace ) {
 
 
 
124
  $common_marketplace_node_name = 'Marketplace' . $marketplace;
125
  $items->ID = "[[UNIQUE_ID]]";
126
  $basic_labels = $this->xml_helper->get_basic_labels( $marketplace );
@@ -130,13 +115,25 @@ class Xml_Manipulator {
130
  $aalb_header_node = $items->addChild( 'AalbHeader' );
131
  $aalb_header_node->$common_marketplace_node_name = 'true';
132
 
133
- foreach ( $items->Item as $item ) {
134
- $this->decorate_item( $item, $marketplace, $common_marketplace_node_name );
135
- }
136
-
137
  return $items;
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  /**
141
  * Add the Information for the Item(which is calculated based on business logic) to the Aalb node.
142
  *
@@ -186,4 +183,42 @@ class Xml_Manipulator {
186
  //Below is done as earlier we were maintaining current price value node even if value is null
187
  $aalb_node->CurrentPriceValue = $price_related_info[XML_Constants::CURRENT_PRICE_VALUE];
188
  }
189
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  */
46
  public function get_customized_items_object( $products_xml, $marketplace ) {
47
  $simple_xml_object = $this->parse( $products_xml );
 
48
  $custom_items = $this->add_custom_nodes( $simple_xml_object->Items, $marketplace );
49
 
50
  return $custom_items;
51
  }
52
 
53
  /**
54
+ * Convert the well-formed xml string into a SimpleXMLElement object and check if the object is formed successfully.
55
  *
56
  * @since 1.0.0
57
  *
58
  * @param string $xml_string Well-formed XML string
59
  *
60
+ * @throws \Exception if xml element object was nt formed successfully
61
+ *
62
  * @return \SimpleXMLElement Php xml object.
63
  */
64
+ public function parse( $xml_string ) {
65
  libxml_use_internal_errors( true );
66
+ $xml = simplexml_load_string( $xml_string );
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  if ( $xml === false ) {
68
  //Don't translate as this is also dumped in error logs and will facilitate AALB team to debug
69
  throw new \Exception( 'Xml_Manipulator::validate::Failed Loading XML' );
 
 
70
  }
 
71
 
72
+ return $xml;
 
 
 
 
 
 
 
 
 
 
73
  }
74
 
75
  /**
76
+ * Add custom nodes to xml response
 
77
  *
78
  * @since 1.8.0
79
  *
80
  * @param \SimpleXMLElement $xml Well-formed XML string
81
+ * @param string $marketplace Marketplace
82
  *
83
+ * @return \SimpleXMLElement $items XML String with custom nodes added
84
  */
85
+ private function add_custom_nodes( $items, $marketplace ) {
86
+ $common_marketplace_node_name = 'Marketplace' . $marketplace;
87
+
88
+ foreach ( $items->Item as $item ) {
89
+ $this->decorate_item( $item, $marketplace, $common_marketplace_node_name );
90
+ }
91
+
92
+ return $items;
93
  }
94
 
95
  /**
96
+ * Add common nodes to xml response
97
  *
98
+ * @since 1.8.0
99
  *
100
  * @param \SimpleXMLElement $items Well-formed XML string
101
+ * @param string $marketplace Marketplace
102
  *
103
  * @return \SimpleXMLElement $items XML String with custom nodes added
104
  */
105
+ private function add_common_nodes( $products_xml, $marketplace ) {
106
+ $xml_response = $this->parse( $products_xml );
107
+ $items = $xml_response->Items;
108
+
109
  $common_marketplace_node_name = 'Marketplace' . $marketplace;
110
  $items->ID = "[[UNIQUE_ID]]";
111
  $basic_labels = $this->xml_helper->get_basic_labels( $marketplace );
115
  $aalb_header_node = $items->addChild( 'AalbHeader' );
116
  $aalb_header_node->$common_marketplace_node_name = 'true';
117
 
 
 
 
 
118
  return $items;
119
  }
120
 
121
+ /**
122
+ * Get customized response which contains attributes common to all items
123
+ *
124
+ * @since 1.8.0
125
+ *
126
+ * @param string $items_xml String of final response
127
+ * @param string $store_id Store_id
128
+ * @param string $link_code Link code
129
+ * @param string $marketplace Marketplace
130
+ *
131
+ * @return \SimpleXMLElement
132
+ */
133
+ public function get_customized_response( $items_xml, $store_id, $link_code, $marketplace ){
134
+ return $this->add_common_nodes( $this->modify_xml( $items_xml, $store_id, $link_code ), $marketplace );
135
+ }
136
+
137
  /**
138
  * Add the Information for the Item(which is calculated based on business logic) to the Aalb node.
139
  *
183
  //Below is done as earlier we were maintaining current price value node even if value is null
184
  $aalb_node->CurrentPriceValue = $price_related_info[XML_Constants::CURRENT_PRICE_VALUE];
185
  }
186
+
187
+ /**
188
+ * Change the store_id before rendering the response.
189
+ *
190
+ * @since 1.8.0
191
+ *
192
+ * @param string $response Item lookup response stored in table which may have a different store_id.
193
+ * @param string $store_id The replacement for store_id in response.
194
+ *
195
+ * @return string Modified response.
196
+ */
197
+ public function modify_xml( $response, $store_id, $link_code ) {
198
+ //use wordpress linkcode
199
+ $response = preg_replace( "/linkCode(%3D|=)\w{1,3}/", "linkCode$1" . $link_code, $response );
200
+
201
+ //replace store id
202
+ return preg_replace( "((tag=)[^&]+(&))", "$1" . $store_id . "$3", $response );
203
+ }
204
+
205
+ /**
206
+ * Single Escape Numeric Character References(NCR) using regular expression replacement
207
+ *
208
+ * @since 1.8.0
209
+ *
210
+ * @param string $products Deserialized XML string with NCRs double escaped
211
+ *
212
+ * @return string Deserialized XML string with NCRS single escaped
213
+ */
214
+ public function unescape_numeric_character_references( $products ) {
215
+ //Single Escape NCR represented as hex number
216
+ $products = preg_replace( "/&amp;(#x[a-fA-F0-9]{4,6};)/", "&$1", $products );
217
+
218
+ //Single Escape other special characters escaped by Product Advertising API like Σ(&#931;),Θ(&#920;)
219
+ $products = preg_replace( "/&amp;(#[0-9]{1,7};)/", "&$1", $products );
220
+
221
+ return $products;
222
+ }
223
+
224
+ }
shortcode/shortcode_helper.php CHANGED
@@ -69,23 +69,6 @@ class Shortcode_Helper {
69
  return preg_replace( '/[ ,]+/', '-', trim( $asins ) );
70
  }
71
 
72
- /**
73
- * Get marketplace endpoint for marketplace abbreviation
74
- *
75
- * @since 1.0.0
76
- *
77
- * @param string $marketplace_abbr Marketplace Abbreviation from shortcode
78
- *
79
- * @return string $marketplace_endpoint Marketplace endpoint
80
- */
81
- public function get_marketplace_endpoint( $marketplace_abbr ) {
82
- $marketplace_endpoint = "";
83
- $aalb_marketplace_names = $this->config_loader->fetch_marketplaces();
84
- $marketplace_endpoint = array_search( $marketplace_abbr, $aalb_marketplace_names );
85
-
86
- return $marketplace_endpoint;
87
- }
88
-
89
  /**
90
  * Get validated link-id
91
  * Checks if the link id we got from the api is valid or not and returns
69
  return preg_replace( '/[ ,]+/', '-', trim( $asins ) );
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  /**
73
  * Get validated link-id
74
  * Checks if the link id we got from the api is valid or not and returns
shortcode/shortcode_manager.php CHANGED
@@ -14,16 +14,24 @@ and limitations under the License.
14
 
15
  namespace AmazonAssociatesLinkBuilder\shortcode;
16
 
 
 
 
17
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
 
 
 
18
  use AmazonAssociatesLinkBuilder\rendering\Template_Engine;
19
  use AmazonAssociatesLinkBuilder\ip2Country\Customer_Country;
20
- use AmazonAssociatesLinkBuilder\shortcode\Shortcode_Helper;
21
  use AmazonAssociatesLinkBuilder\helper\Paapi_Helper;
22
  use AmazonAssociatesLinkBuilder\ip2Country\Maxmind_Db_Manager;
23
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
24
  use AmazonAssociatesLinkBuilder\io\Curl_Request;
25
  use AmazonAssociatesLinkBuilder\io\File_System_Helper;
26
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
 
 
 
27
 
28
  /**
29
  *
@@ -34,11 +42,12 @@ use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
34
  * @subpackage AmazonAssociatesLinkBuilder/shortcode
35
  */
36
  class Shortcode_Manager {
37
- protected $paapi_helper;
38
  protected $template_engine;
 
39
  protected $helper;
40
  protected $shortcode_helper;
41
  protected $customer_country;
 
42
 
43
  public function __construct() {
44
  $this->template_engine = new Template_Engine();
@@ -46,6 +55,9 @@ class Shortcode_Manager {
46
  $this->helper = new Plugin_Helper();
47
  $this->shortcode_helper = new Shortcode_Helper();
48
  $this->customer_country = new Customer_Country();
 
 
 
49
  }
50
 
51
  /**
@@ -139,15 +151,12 @@ class Shortcode_Manager {
139
  $validated_store_id = $this->shortcode_helper->get_validated_store_id( $store_id );
140
  $link_text = $shortcode_attributes['text'];
141
 
142
- $marketplace_endpoint = $this->shortcode_helper->get_marketplace_endpoint( $validated_marketplace );
143
- $url = $this->paapi_helper->get_item_lookup_url( $validated_asins, $marketplace_endpoint, $validated_store_id );
144
  $formatted_asins = $this->shortcode_helper->format_asins( $validated_asins );
145
  $this->shortcode_helper->enqueue_template_styles( $validated_template );
146
 
147
- $products_key = $this->helper->build_products_cache_key( $formatted_asins, $validated_marketplace, $validated_store_id );
148
- $products_template_key = $this->helper->build_template_cache_key( $formatted_asins, $validated_marketplace, $validated_store_id, $validated_template );
149
  try {
150
- return str_replace( array( '[[UNIQUE_ID]]', '[[Amazon_Link_Text]]' ), array( str_replace( '.', '-', $products_template_key ), $link_text ), $this->template_engine->render( $products_template_key, $products_key, $validated_template, $url, $validated_marketplace, $link_code, $validated_store_id, $validated_asins ) );
151
  } catch ( \Exception $e ) {
152
  error_log( $this->paapi_helper->get_error_message( $e->getMessage() ) );
153
  }
@@ -182,7 +191,7 @@ class Shortcode_Manager {
182
  *
183
  * @since 1.5.0
184
  *
185
- * @param \Array $marketplace_list Array of marketplaces present in shortcode
186
  *
187
  * @return String Marketplace from which customer is coming. Empty in case marketplace not added by user or no e-commerce presence
188
  */
14
 
15
  namespace AmazonAssociatesLinkBuilder\shortcode;
16
 
17
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache;
18
+ use AmazonAssociatesLinkBuilder\cache\Item_Lookup_Response_Cache_Loader;
19
+ use AmazonAssociatesLinkBuilder\configuration\Config_Helper;
20
  use AmazonAssociatesLinkBuilder\constants\Db_Constants;
21
+ use AmazonAssociatesLinkBuilder\helper\Xml_Helper;
22
+ use AmazonAssociatesLinkBuilder\includes\Item_Lookup_Response_Manager;
23
+ use AmazonAssociatesLinkBuilder\rendering\Impression_Generator;
24
  use AmazonAssociatesLinkBuilder\rendering\Template_Engine;
25
  use AmazonAssociatesLinkBuilder\ip2Country\Customer_Country;
 
26
  use AmazonAssociatesLinkBuilder\helper\Paapi_Helper;
27
  use AmazonAssociatesLinkBuilder\ip2Country\Maxmind_Db_Manager;
28
  use AmazonAssociatesLinkBuilder\constants\Plugin_Constants;
29
  use AmazonAssociatesLinkBuilder\io\Curl_Request;
30
  use AmazonAssociatesLinkBuilder\io\File_System_Helper;
31
  use AmazonAssociatesLinkBuilder\helper\Plugin_Helper;
32
+ use AmazonAssociatesLinkBuilder\cache\Display_Unit_Cache_Loader;
33
+ use AmazonAssociatesLinkBuilder\rendering\Xml_Manipulator;
34
+ use AmazonAssociatesLinkBuilder\sql\Sql_Helper;
35
 
36
  /**
37
  *
42
  * @subpackage AmazonAssociatesLinkBuilder/shortcode
43
  */
44
  class Shortcode_Manager {
 
45
  protected $template_engine;
46
+ protected $paapi_helper;
47
  protected $helper;
48
  protected $shortcode_helper;
49
  protected $customer_country;
50
+ private $display_unit_cache_loader;
51
 
52
  public function __construct() {
53
  $this->template_engine = new Template_Engine();
55
  $this->helper = new Plugin_Helper();
56
  $this->shortcode_helper = new Shortcode_Helper();
57
  $this->customer_country = new Customer_Country();
58
+ $this->xml_manipulator = new Xml_Manipulator( new Xml_Helper( new Config_Helper() ) );
59
+ $this->sql_helper = new Sql_Helper( DB_NAME, Db_Constants::ITEM_LOOKUP_RESPONSE_TABLE_NAME );
60
+ $this->display_unit_cache_loader = new Display_Unit_Cache_Loader( $this->template_engine, new Item_Lookup_Response_Cache_Loader( $this->xml_manipulator, $this->paapi_helper, new Item_Lookup_Response_Manager( $this->xml_manipulator ), $this->sql_helper, new Item_Lookup_Response_Cache( $this->sql_helper ) ), new Impression_Generator( new Config_Helper() ) );
61
  }
62
 
63
  /**
151
  $validated_store_id = $this->shortcode_helper->get_validated_store_id( $store_id );
152
  $link_text = $shortcode_attributes['text'];
153
 
 
 
154
  $formatted_asins = $this->shortcode_helper->format_asins( $validated_asins );
155
  $this->shortcode_helper->enqueue_template_styles( $validated_template );
156
 
157
+ $display_unit_cache_key = $this->helper->build_display_unit_cache_key( $formatted_asins, $validated_marketplace, $validated_store_id, $validated_template );
 
158
  try {
159
+ return str_replace( array( '[[UNIQUE_ID]]', '[[Amazon_Link_Text]]' ), array( str_replace( '.', '-', $display_unit_cache_key ), $link_text ), $this->display_unit_cache_loader->get( $display_unit_cache_key, $validated_template, $validated_marketplace, $link_code, $validated_store_id, $validated_asins ) );
160
  } catch ( \Exception $e ) {
161
  error_log( $this->paapi_helper->get_error_message( $e->getMessage() ) );
162
  }
191
  *
192
  * @since 1.5.0
193
  *
194
+ * @param array $marketplace_list Array of marketplaces present in shortcode
195
  *
196
  * @return String Marketplace from which customer is coming. Empty in case marketplace not added by user or no e-commerce presence
197
  */
sql/sql_helper.php ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+
6
+ Licensed under the GNU General Public License as published by the Free Software Foundation,
7
+ Version 2.0 (the "License"). You may not use this file except in compliance with the License.
8
+ A copy of the License is located in the "license" file accompanying this file.
9
+
10
+ This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11
+ either express or implied. See the License for the specific language governing permissions
12
+ and limitations under the License.
13
+ */
14
+
15
+ namespace AmazonAssociatesLinkBuilder\sql;
16
+
17
+ use AmazonAssociatesLinkBuilder\constants\Cron_Constants;
18
+
19
+ /**
20
+ * Sql helper class to construct various sql queries, query the database and return the results.
21
+ *
22
+ * @since 1.8.0
23
+ * @package AmazonAssociatesLinkBuilder
24
+ * @subpackage AmazonAssociatesLinkBuilder/sql
25
+ */
26
+ class Sql_Helper {
27
+
28
+ private $wpdb;
29
+ private $table_name;
30
+ private $database_name;
31
+
32
+ public function __construct( $database_name, $table_name ) {
33
+ global $wpdb;
34
+ $this->wpdb = $wpdb;
35
+ $this->table_name = $wpdb->prefix . $table_name;
36
+ $this->database_name = $database_name;
37
+ }
38
+
39
+ /**
40
+ * Queries the database to add a table if it doesn't exist.
41
+ *
42
+ * @since 1.8.0
43
+ *
44
+ * @param array $columns Column names, data_types and attributes
45
+ * @param array $index Index required in table
46
+ * @param string $primary_key Primary key of the table
47
+ */
48
+ public function create_table( $columns, $index = array(), $primary_key = "" ) {
49
+ if ( $this->table_not_exists( $this->database_name, $this->table_name ) ) {
50
+ $columns_param = implode( ", ", $columns );
51
+ $index_param = ! empty( $index ) ? ", KEY " . implode( ", KEY ", $index ) : "";
52
+ $primary_key_param = ! empty( $primary_key ) ? ", PRIMARY KEY $primary_key" : "";
53
+
54
+ $parameters = $columns_param . $index_param . $primary_key_param;
55
+ $create_table_query = "CREATE TABLE {$this->table_name} ( $parameters )";
56
+
57
+ //To use dbDelta function
58
+ require_once( ABSPATH . "/wp-admin/includes/upgrade.php" );
59
+ dbDelta( $create_table_query );
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Truncates the table.
65
+ *
66
+ * @since 1.8.0
67
+ *
68
+ * @return bool Indicating if the operation succeeded.
69
+ */
70
+ public function truncate_table() {
71
+ return $this->wpdb->query( "TRUNCATE TABLE {$this->table_name}" );
72
+ }
73
+
74
+ /**
75
+ * Drop the table.
76
+ *
77
+ * @since 1.8.0
78
+ *
79
+ * @return bool Indicating if the operation succeeded.
80
+ */
81
+ public function drop_table() {
82
+ return $this->wpdb->query( "DROP TABLE {$this->table_name}" );
83
+ }
84
+
85
+ /**
86
+ * Queries the database for given asins and their marketplace.
87
+ *
88
+ * @since 1.8.0
89
+ *
90
+ * @param array $asins_array Array of asins
91
+ * @param string $marketplace Marketplace
92
+ *
93
+ * @return mixed Returns the array of rows containing fields: item lookup response, asin and boolean indicating if the entry is valid (was updated in the last 30 min) else returns an empty array (if no rows were found or a database error occurred).
94
+ */
95
+ public function lookup_asin_response_in_table( $asins_array, $marketplace ) {
96
+ $asins_param = implode( ",", array_map( function ( $asin ) {
97
+ return "'{$asin}'";
98
+ }, $asins_array ) );
99
+
100
+ $lookup_in_table_query = "SELECT `item_lookup_response`, `asin`, `last_updated_time` > DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 MINUTE ) AS `is_valid`
101
+ FROM {$this->table_name}
102
+ WHERE `asin` IN ( {$asins_param} ) AND `marketplace`='{$marketplace}'";
103
+
104
+ return $this->wpdb->get_results( $lookup_in_table_query );
105
+ }
106
+
107
+ /**
108
+ * Updates the last access time of entries of asins and their marketplace which were requested and were present in the table. (They may or may not have been valid (updated in the last 30 min) ).
109
+ *
110
+ * @since 1.8.0
111
+ *
112
+ * @param array $asins_array Array of asins
113
+ * @param string $marketplace Marketplace
114
+ */
115
+ public function update_last_access_time( $asins_array, $marketplace ) {
116
+ $asins_param = implode( ",", array_map( function ( $asin ) {
117
+ return "'{$asin}'";
118
+ }, $asins_array ) );
119
+
120
+ $update_last_access_query = "UPDATE {$this->table_name}
121
+ SET `last_access_time`=CURRENT_TIMESTAMP()
122
+ WHERE asin IN ({$asins_param}) AND marketplace='{$marketplace}'";
123
+
124
+ $update_last_access_result = $this->wpdb->query( $update_last_access_query );
125
+ if ( $update_last_access_result === false ) {
126
+ error_log( "There was a problem while updating the table" );
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Add rows in the table for given columns and values.
132
+ *
133
+ * @since 1.8.0
134
+ *
135
+ * @param array $columns Array of strings of column names
136
+ * @param array $values Array of rows to be added in the table
137
+ * @param array $on_duplicate_key_update_columns Array of columns to be updated when an entry with duplicate key exists
138
+ *
139
+ * @return bool Indicating if the operation succeeded.
140
+ */
141
+ public function add_rows_in_table( $columns, $values, $on_duplicate_key_update_columns = array() ) {
142
+ $on_duplicate_key_update_columns_clause = ! empty( $on_duplicate_key_update_columns ) ? $this->get_on_duplicate_key_update_columns_clause( $on_duplicate_key_update_columns ) : "";
143
+ $columns_param = implode( ", ", $columns );
144
+
145
+ $values_param = implode( ",", array_map( function ( $value ) {
146
+ return "(" . implode( ",", $value ) . ")";
147
+ }, $values ) );
148
+
149
+ $add_rows_query = "INSERT INTO {$this->table_name} (
150
+ {$columns_param})
151
+ VALUES {$values_param} {$on_duplicate_key_update_columns_clause}";
152
+
153
+ return $this->wpdb->query( $add_rows_query );
154
+ }
155
+
156
+ /**
157
+ * Get the clause in query for updating columns whenever an entry with duplicate key exists in the table.
158
+ *
159
+ * @since 1.8.0
160
+ *
161
+ * @param $on_duplicate_key_update_columns
162
+ *
163
+ * @return string
164
+ */
165
+ private function get_on_duplicate_key_update_columns_clause( $on_duplicate_key_update_columns ) {
166
+ $on_duplicate_key_update_columns_clause = "ON DUPLICATE KEY UPDATE " . implode( ", ", array_map( function ( $column ) {
167
+ return "{$column}=VALUES({$column})";
168
+ }, $on_duplicate_key_update_columns ) );
169
+
170
+ return $on_duplicate_key_update_columns_clause;
171
+ }
172
+
173
+ /* Delete entries from table which haven't been accessed in the last 24 hours
174
+ *
175
+ * @return bool Indicating if the operation succeeded.
176
+ */
177
+ public function delete_old_asins(){
178
+ $delete_asins_query = "DELETE FROM {$this->table_name}
179
+ WHERE `last_access_time` < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL " . Cron_Constants::CACHE_EVICT_AGE . ")";
180
+
181
+ return $this->wpdb->query($delete_asins_query);
182
+ }
183
+
184
+ /**
185
+ * Get asins which are about to expire.
186
+ *
187
+ * @return array Array of rows containing fields: asin and marketplace.
188
+ */
189
+ public function get_asins_to_update() {
190
+ $get_asins_to_update_query = "SELECT `asin`, `marketplace`
191
+ FROM {$this->table_name}
192
+ WHERE `last_updated_time` < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL " . Cron_Constants::CACHE_REFRESH_AGE . ")
193
+ ORDER BY `last_access_time` DESC";
194
+
195
+ return $this->wpdb->get_results( $get_asins_to_update_query );
196
+ }
197
+
198
+ /**
199
+ * Checks if the table exists.
200
+ *
201
+ * @since 1.8.0
202
+ *
203
+ * @param string $database_name Name of the database
204
+ * @param string $table_name Name of the table
205
+ *
206
+ * @return bool Indicating if table exists.
207
+ */
208
+ private function table_not_exists( $database_name, $table_name ) {
209
+ $is_table_exists_query = "SELECT COUNT(*) AS `number_of_tables`
210
+ FROM information_schema.TABLES
211
+ WHERE `table_schema` = '{$database_name}'
212
+ AND `table_name` = '{$table_name}'";
213
+
214
+ //get_results returns an array of objects and here, the first element of the array contains property number_of_tables
215
+ return ( $this->wpdb->get_results( $is_table_exists_query )[0]->number_of_tables ) == 0;
216
+ }
217
+
218
+ }
template/ProductCarousel.mustache CHANGED
@@ -139,7 +139,7 @@
139
  * Licensed MIT (https://github.com/ganeshmax/jcarousellite/blob/master/LICENSE)
140
  */
141
 
142
- !function(a){a.jCarouselLite={version:"1.1"},a.fn.jCarouselLite=function(b){return b=a.extend({},a.fn.jCarouselLite.options,b||{}),this.each(function(){function c(a){return n||(clearTimeout(A),z=a,b.beforeStart&&b.beforeStart.call(this,i()),b.circular?j(a):k(a),m({start:function(){n=!0},done:function(){b.afterEnd&&b.afterEnd.call(this,i()),b.auto&&h(),n=!1}}),b.circular||l()),!1}function d(){if(n=!1,o=b.vertical?"top":"left",p=b.vertical?"height":"width",q=B.find(">ul"),r=q.find(">li"),x=r.size(),w=x<b.visible?x:b.visible,b.circular){var c=r.slice(x-w).clone(),d=r.slice(0,w).clone();q.prepend(c).append(d),b.start+=w}s=a("li",q),y=s.size(),z=b.start}function e(){B.css("visibility","visible"),s.css({overflow:"hidden","float":b.vertical?"none":"left"}),q.css({margin:"0",padding:"0",position:"relative","list-style":"none","z-index":"1"}),B.css({overflow:"hidden",position:"relative","z-index":"2",left:"0px"}),!b.circular&&b.btnPrev&&0==b.start&&a(b.btnPrev).addClass("disabled")}function f(){t=b.vertical?s.outerHeight(!0):s.outerWidth(!0),u=t*y,v=t*w,s.css({width:s.width(),height:s.height()}),q.css(p,u+"px").css(o,-(z*t)),B.css(p,v+"px")}function g(){b.btnPrev&&a(b.btnPrev).click(function(){return c(z-b.scroll)}),b.btnNext&&a(b.btnNext).click(function(){return c(z+b.scroll)}),b.btnGo&&a.each(b.btnGo,function(d,e){a(e).click(function(){return c(b.circular?w+d:d)})}),b.mouseWheel&&B.mousewheel&&B.mousewheel(function(a,d){return c(d>0?z-b.scroll:z+b.scroll)}),b.auto&&h()}function h(){A=setTimeout(function(){c(z+b.scroll)},b.auto)}function i(){return s.slice(z).slice(0,w)}function j(a){var c;a<=b.start-w-1?(c=a+x+b.scroll,q.css(o,-(c*t)+"px"),z=c-b.scroll):a>=y-w+1&&(c=a-x-b.scroll,q.css(o,-(c*t)+"px"),z=c+b.scroll)}function k(a){0>a?z=0:a>y-w&&(z=y-w)}function l(){a(b.btnPrev+","+b.btnNext).removeClass("disabled"),a(z-b.scroll<0&&b.btnPrev||z+b.scroll>y-w&&b.btnNext||[]).addClass("disabled")}function m(c){n=!0,q.animate("left"==o?{left:-(z*t)}:{top:-(z*t)},a.extend({duration:b.speed,easing:b.easing},c))}var n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a(this);d(),e(),f(),g()})},a.fn.jCarouselLite.options={btnPrev:null,btnNext:null,btnGo:null,mouseWheel:!1,auto:null,speed:200,easing:null,vertical:!1,circular:!0,visible:3,start:0,scroll:1,beforeStart:null,afterEnd:null}}(jQuery);
143
 
144
 
145
  </script>
139
  * Licensed MIT (https://github.com/ganeshmax/jcarousellite/blob/master/LICENSE)
140
  */
141
 
142
+ !function(a){a.jCarouselLite={version:"1.1"},a.fn.jCarouselLite=function(b){return b=a.extend({},a.fn.jCarouselLite.options,b||{}),this.each(function(){function c(a){return n||(clearTimeout(A),z=a,b.beforeStart&&b.beforeStart.call(this,i()),b.circular?j(a):k(a),m({start:function(){n=!0},done:function(){b.afterEnd&&b.afterEnd.call(this,i()),b.auto&&h(),n=!1}}),b.circular||l()),!1}function d(){if(n=!1,o=b.vertical?"top":"left",p=b.vertical?"height":"width",q=B.find(">ul"),r=q.find(">li"),x=r.size(),w=lt(x,b.visible)?x:b.visible,b.circular){var c=r.slice(x-w).clone(),d=r.slice(0,w).clone();q.prepend(c).append(d),b.start+=w}s=a("li",q),y=s.size(),z=b.start}function e(){B.css("visibility","visible"),s.css({overflow:"hidden","float":b.vertical?"none":"left"}),q.css({margin:"0",padding:"0",position:"relative","list-style":"none","z-index":"1"}),B.css({overflow:"hidden",position:"relative","z-index":"2",left:"0px"}),!b.circular&&b.btnPrev&&0==b.start&&a(b.btnPrev).addClass("disabled")}function f(){t=b.vertical?s.outerHeight(!0):s.outerWidth(!0),u=t*y,v=t*w,s.css({width:s.width(),height:s.height()}),q.css(p,u+"px").css(o,-(z*t)),B.css(p,v+"px")}function g(){b.btnPrev&&a(b.btnPrev).click(function(){return c(z-b.scroll)}),b.btnNext&&a(b.btnNext).click(function(){return c(z+b.scroll)}),b.btnGo&&a.each(b.btnGo,function(d,e){a(e).click(function(){return c(b.circular?w+d:d)})}),b.mouseWheel&&B.mousewheel&&B.mousewheel(function(a,d){return c(d>0?z-b.scroll:z+b.scroll)}),b.auto&&h()}function h(){A=setTimeout(function(){c(z+b.scroll)},b.auto)} function lt(a,b){return a<b;} function gt(a, b) { return a>b;} function i(){return s.slice(z).slice(0,w)}function j(a){var c;a<=b.start-w-1?(c=a+x+b.scroll,q.css(o,-(c*t)+"px"),z=c-b.scroll):a>=y-w+1&&(c=a-x-b.scroll,q.css(o,-(c*t)+"px"),z=c+b.scroll)}function k(a){0>a?z=0:a>y-w&&(z=y-w)}function l(){a(b.btnPrev+","+b.btnNext).removeClass("disabled"),a(z-lt(b.scroll,0)&&b.btnPrev||z+gt(b.scroll, y)-w&&b.btnNext||[]).addClass("disabled")}function m(c){n=!0,q.animate("left"==o?{left:-(z*t)}:{top:-(z*t)},a.extend({duration:b.speed,easing:b.easing},c))}var n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a(this);d(),e(),f(),g()})},a.fn.jCarouselLite.options={btnPrev:null,btnNext:null,btnGo:null,mouseWheel:!1,auto:null,speed:200,easing:null,vertical:!1,circular:!0,visible:3,start:0,scroll:1,beforeStart:null,afterEnd:null}}(jQuery);
143
 
144
 
145
  </script>
vendor/a5hleyrich/wp-background-processing/README.md ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WP Background Processing
2
+
3
+ WP Background Processing can be used to fire off non-blocking asynchronous requests or as a background processing tool, allowing you to queue tasks. Check out the [example plugin](https://github.com/A5hleyRich/wp-background-processing-example) or read the [accompanying article](https://deliciousbrains.com/background-processing-wordpress/).
4
+
5
+ Inspired by [TechCrunch WP Asynchronous Tasks](https://github.com/techcrunch/wp-async-task).
6
+
7
+ __Requires PHP 5.2+__
8
+
9
+ ### Async Request
10
+
11
+ Async requests are useful for pushing slow one-off tasks such as sending emails to a background process. Once the request has been dispatched it will process in the background instantly.
12
+
13
+ Extend the `WP_Async_Request` class:
14
+
15
+ ```php
16
+ class WP_Example_Request extends WP_Async_Request {
17
+
18
+ /**
19
+ * @var string
20
+ */
21
+ protected $action = 'example_request';
22
+
23
+ /**
24
+ * Handle
25
+ *
26
+ * Override this method to perform any actions required
27
+ * during the async request.
28
+ */
29
+ protected function handle() {
30
+ // Actions to perform
31
+ }
32
+
33
+ }
34
+ ```
35
+
36
+ ##### `protected $action`
37
+
38
+ Should be set to a unique name.
39
+
40
+ ##### `protected function handle()`
41
+
42
+ Should contain any logic to perform during the non-blocking request. The data passed to the request will be accessible via `$_POST`.
43
+
44
+ ##### Dispatching Requests
45
+
46
+ Instantiate your request:
47
+
48
+ `$this->example_request = new WP_Example_Request();`
49
+
50
+ Add data to the request if required:
51
+
52
+ `$this->example_request->data( array( 'value1' => $value1, 'value2' => $value2 ) );`
53
+
54
+ Fire off the request:
55
+
56
+ `$this->example_request->dispatch();`
57
+
58
+ Chaining is also supported:
59
+
60
+ `$this->example_request->data( array( 'data' => $data ) )->dispatch();`
61
+
62
+ ### Background Process
63
+
64
+ Background processes work in a similar fashion to async requests but they allow you to queue tasks. Items pushed onto the queue will be processed in the background once the queue has been dispatched. Queues will also scale based on available server resources, so higher end servers will process more items per batch. Once a batch has completed the next batch will start instantly.
65
+
66
+ Health checks run by default every 5 minutes to ensure the queue is running when queued items exist. If the queue has failed it will be restarted.
67
+
68
+ Queues work on a first in first out basis, which allows additional items to be pushed to the queue even if it’s already processing.
69
+
70
+ Extend the `WP_Background_Process` class:
71
+
72
+ ```php
73
+ class WP_Example_Process extends WP_Background_Process {
74
+
75
+ /**
76
+ * @var string
77
+ */
78
+ protected $action = 'example_process';
79
+
80
+ /**
81
+ * Task
82
+ *
83
+ * Override this method to perform any actions required on each
84
+ * queue item. Return the modified item for further processing
85
+ * in the next pass through. Or, return false to remove the
86
+ * item from the queue.
87
+ *
88
+ * @param mixed $item Queue item to iterate over
89
+ *
90
+ * @return mixed
91
+ */
92
+ protected function task( $item ) {
93
+ // Actions to perform
94
+
95
+ return false;
96
+ }
97
+
98
+ /**
99
+ * Complete
100
+ *
101
+ * Override if applicable, but ensure that the below actions are
102
+ * performed, or, call parent::complete().
103
+ */
104
+ protected function complete() {
105
+ parent::complete();
106
+
107
+ // Show notice to user or perform some other arbitrary task...
108
+ }
109
+
110
+ }
111
+ ```
112
+
113
+ ##### `protected $action`
114
+
115
+ Should be set to a unique name.
116
+
117
+ ##### `protected function task( $item )`
118
+
119
+ Should contain any logic to perform on the queued item. Return `false` to remove the item from the queue or return `$item` to push it back onto the queue for further processing. If the item has been modified and is pushed back onto the queue the current state will be saved before the batch is exited.
120
+
121
+ ##### `protected function complete()`
122
+
123
+ Optionally contain any logic to perform once the queue has completed.
124
+
125
+ ##### Dispatching Processes
126
+
127
+ Instantiate your process:
128
+
129
+ `$this->example_process = new WP_Example_Process();`
130
+
131
+ Push items to the queue:
132
+
133
+ ```php
134
+ foreach ( $items as $item ) {
135
+ $this->example_process->push_to_queue( $item );
136
+ }
137
+ ```
138
+
139
+ Save and dispatch the queue:
140
+
141
+ `$this->example_process->save()->dispatch();`
142
+
143
+ ### BasicAuth
144
+
145
+ If your site is behind BasicAuth, both async requests and background processes will fail to complete. This is because WP Background Processing relies on the [WordPress HTTP API](http://codex.wordpress.org/HTTP_API), which requires you to attach your BasicAuth credentials to requests. The easiest way to do this is using the following filter:
146
+
147
+ ```php
148
+ function wpbp_http_request_args( $r, $url ) {
149
+ $r['headers']['Authorization'] = 'Basic ' . base64_encode( USERNAME . ':' . PASSWORD );
150
+
151
+ return $r;
152
+ }
153
+ add_filter( 'http_request_args', 'wpbp_http_request_args', 10, 2);
154
+ ```
155
+
156
+ ## License
157
+
158
+ [GPLv2+](http://www.gnu.org/licenses/gpl-2.0.html)
vendor/a5hleyrich/wp-background-processing/classes/wp-async-request.php ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP Async Request
4
+ *
5
+ * @package WP-Background-Processing
6
+ */
7
+
8
+ if ( ! class_exists( 'WP_Async_Request' ) ) {
9
+
10
+ /**
11
+ * Abstract WP_Async_Request class.
12
+ *
13
+ * @abstract
14
+ */
15
+ abstract class WP_Async_Request {
16
+
17
+ /**
18
+ * Prefix
19
+ *
20
+ * (default value: 'wp')
21
+ *
22
+ * @var string
23
+ * @access protected
24
+ */
25
+ protected $prefix = 'wp';
26
+
27
+ /**
28
+ * Action
29
+ *
30
+ * (default value: 'async_request')
31
+ *
32
+ * @var string
33
+ * @access protected
34
+ */
35
+ protected $action = 'async_request';
36
+
37
+ /**
38
+ * Identifier
39
+ *
40
+ * @var mixed
41
+ * @access protected
42
+ */
43
+ protected $identifier;
44
+
45
+ /**
46
+ * Data
47
+ *
48
+ * (default value: array())
49
+ *
50
+ * @var array
51
+ * @access protected
52
+ */
53
+ protected $data = array();
54
+
55
+ /**
56
+ * Initiate new async request
57
+ */
58
+ public function __construct() {
59
+ $this->identifier = $this->prefix . '_' . $this->action;
60
+
61
+ add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
62
+ add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
63
+ }
64
+
65
+ /**
66
+ * Set data used during the request
67
+ *
68
+ * @param array $data Data.
69
+ *
70
+ * @return $this
71
+ */
72
+ public function data( $data ) {
73
+ $this->data = $data;
74
+
75
+ return $this;
76
+ }
77
+
78
+ /**
79
+ * Dispatch the async request
80
+ *
81
+ * @return array|WP_Error
82
+ */
83
+ public function dispatch() {
84
+ $url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
85
+ $args = $this->get_post_args();
86
+
87
+ return wp_remote_post( esc_url_raw( $url ), $args );
88
+ }
89
+
90
+ /**
91
+ * Get query args
92
+ *
93
+ * @return array
94
+ */
95
+ protected function get_query_args() {
96
+ if ( property_exists( $this, 'query_args' ) ) {
97
+ return $this->query_args;
98
+ }
99
+
100
+ return array(
101
+ 'action' => $this->identifier,
102
+ 'nonce' => wp_create_nonce( $this->identifier ),
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Get query URL
108
+ *
109
+ * @return string
110
+ */
111
+ protected function get_query_url() {
112
+ if ( property_exists( $this, 'query_url' ) ) {
113
+ return $this->query_url;
114
+ }
115
+
116
+ return admin_url( 'admin-ajax.php' );
117
+ }
118
+
119
+ /**
120
+ * Get post args
121
+ *
122
+ * @return array
123
+ */
124
+ protected function get_post_args() {
125
+ if ( property_exists( $this, 'post_args' ) ) {
126
+ return $this->post_args;
127
+ }
128
+
129
+ return array(
130
+ 'timeout' => 0.01,
131
+ 'blocking' => false,
132
+ 'body' => $this->data,
133
+ 'cookies' => $_COOKIE,
134
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Maybe handle
140
+ *
141
+ * Check for correct nonce and pass to handler.
142
+ */
143
+ public function maybe_handle() {
144
+ // Don't lock up other requests while processing
145
+ session_write_close();
146
+
147
+ check_ajax_referer( $this->identifier, 'nonce' );
148
+
149
+ $this->handle();
150
+
151
+ wp_die();
152
+ }
153
+
154
+ /**
155
+ * Handle
156
+ *
157
+ * Override this method to perform any actions required
158
+ * during the async request.
159
+ */
160
+ abstract protected function handle();
161
+
162
+ }
163
+ }
vendor/a5hleyrich/wp-background-processing/classes/wp-background-process.php ADDED
@@ -0,0 +1,506 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP Background Process
4
+ *
5
+ * @package WP-Background-Processing
6
+ */
7
+
8
+ if ( ! class_exists( 'WP_Background_Process' ) ) {
9
+
10
+ /**
11
+ * Abstract WP_Background_Process class.
12
+ *
13
+ * @abstract
14
+ * @extends WP_Async_Request
15
+ */
16
+ abstract class WP_Background_Process extends WP_Async_Request {
17
+
18
+ /**
19
+ * Action
20
+ *
21
+ * (default value: 'background_process')
22
+ *
23
+ * @var string
24
+ * @access protected
25
+ */
26
+ protected $action = 'background_process';
27
+
28
+ /**
29
+ * Start time of current process.
30
+ *
31
+ * (default value: 0)
32
+ *
33
+ * @var int
34
+ * @access protected
35
+ */
36
+ protected $start_time = 0;
37
+
38
+ /**
39
+ * Cron_hook_identifier
40
+ *
41
+ * @var mixed
42
+ * @access protected
43
+ */
44
+ protected $cron_hook_identifier;
45
+
46
+ /**
47
+ * Cron_interval_identifier
48
+ *
49
+ * @var mixed
50
+ * @access protected
51
+ */
52
+ protected $cron_interval_identifier;
53
+
54
+ /**
55
+ * Initiate new background process
56
+ */
57
+ public function __construct() {
58
+ parent::__construct();
59
+
60
+ $this->cron_hook_identifier = $this->identifier . '_cron';
61
+ $this->cron_interval_identifier = $this->identifier . '_cron_interval';
62
+
63
+ add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
64
+ add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
65
+ }
66
+
67
+ /**
68
+ * Dispatch
69
+ *
70
+ * @access public
71
+ * @return void
72
+ */
73
+ public function dispatch() {
74
+ // Schedule the cron healthcheck.
75
+ $this->schedule_event();
76
+
77
+ // Perform remote post.
78
+ return parent::dispatch();
79
+ }
80
+
81
+ /**
82
+ * Push to queue
83
+ *
84
+ * @param mixed $data Data.
85
+ *
86
+ * @return $this
87
+ */
88
+ public function push_to_queue( $data ) {
89
+ $this->data[] = $data;
90
+
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * Save queue
96
+ *
97
+ * @return $this
98
+ */
99
+ public function save() {
100
+ $key = $this->generate_key();
101
+
102
+ if ( ! empty( $this->data ) ) {
103
+ update_site_option( $key, $this->data );
104
+ }
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Update queue
111
+ *
112
+ * @param string $key Key.
113
+ * @param array $data Data.
114
+ *
115
+ * @return $this
116
+ */
117
+ public function update( $key, $data ) {
118
+ if ( ! empty( $data ) ) {
119
+ update_site_option( $key, $data );
120
+ }
121
+
122
+ return $this;
123
+ }
124
+
125
+ /**
126
+ * Delete queue
127
+ *
128
+ * @param string $key Key.
129
+ *
130
+ * @return $this
131
+ */
132
+ public function delete( $key ) {
133
+ delete_site_option( $key );
134
+
135
+ return $this;
136
+ }
137
+
138
+ /**
139
+ * Generate key
140
+ *
141
+ * Generates a unique key based on microtime. Queue items are
142
+ * given a unique key so that they can be merged upon save.
143
+ *
144
+ * @param int $length Length.
145
+ *
146
+ * @return string
147
+ */
148
+ protected function generate_key( $length = 64 ) {
149
+ $unique = md5( microtime() . rand() );
150
+ $prepend = $this->identifier . '_batch_';
151
+
152
+ return substr( $prepend . $unique, 0, $length );
153
+ }
154
+
155
+ /**
156
+ * Maybe process queue
157
+ *
158
+ * Checks whether data exists within the queue and that
159
+ * the process is not already running.
160
+ */
161
+ public function maybe_handle() {
162
+ // Don't lock up other requests while processing
163
+ session_write_close();
164
+
165
+ if ( $this->is_process_running() ) {
166
+ // Background process already running.
167
+ wp_die();
168
+ }
169
+
170
+ if ( $this->is_queue_empty() ) {
171
+ // No data to process.
172
+ wp_die();
173
+ }
174
+
175
+ check_ajax_referer( $this->identifier, 'nonce' );
176
+
177
+ $this->handle();
178
+
179
+ wp_die();
180
+ }
181
+
182
+ /**
183
+ * Is queue empty
184
+ *
185
+ * @return bool
186
+ */
187
+ protected function is_queue_empty() {
188
+ global $wpdb;
189
+
190
+ $table = $wpdb->options;
191
+ $column = 'option_name';
192
+
193
+ if ( is_multisite() ) {
194
+ $table = $wpdb->sitemeta;
195
+ $column = 'meta_key';
196
+ }
197
+
198
+ $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
199
+
200
+ $count = $wpdb->get_var( $wpdb->prepare( "
201
+ SELECT COUNT(*)
202
+ FROM {$table}
203
+ WHERE {$column} LIKE %s
204
+ ", $key ) );
205
+
206
+ return ( $count > 0 ) ? false : true;
207
+ }
208
+
209
+ /**
210
+ * Is process running
211
+ *
212
+ * Check whether the current process is already running
213
+ * in a background process.
214
+ */
215
+ protected function is_process_running() {
216
+ if ( get_site_transient( $this->identifier . '_process_lock' ) ) {
217
+ // Process already running.
218
+ return true;
219
+ }
220
+
221
+ return false;
222
+ }
223
+
224
+ /**
225
+ * Lock process
226
+ *
227
+ * Lock the process so that multiple instances can't run simultaneously.
228
+ * Override if applicable, but the duration should be greater than that
229
+ * defined in the time_exceeded() method.
230
+ */
231
+ protected function lock_process() {
232
+ $this->start_time = time(); // Set start time of current process.
233
+
234
+ $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
235
+ $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
236
+
237
+ set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
238
+ }
239
+
240
+ /**
241
+ * Unlock process
242
+ *
243
+ * Unlock the process so that other instances can spawn.
244
+ *
245
+ * @return $this
246
+ */
247
+ protected function unlock_process() {
248
+ delete_site_transient( $this->identifier . '_process_lock' );
249
+
250
+ return $this;
251
+ }
252
+
253
+ /**
254
+ * Get batch
255
+ *
256
+ * @return stdClass Return the first batch from the queue
257
+ */
258
+ protected function get_batch() {
259
+ global $wpdb;
260
+
261
+ $table = $wpdb->options;
262
+ $column = 'option_name';
263
+ $key_column = 'option_id';
264
+ $value_column = 'option_value';
265
+
266
+ if ( is_multisite() ) {
267
+ $table = $wpdb->sitemeta;
268
+ $column = 'meta_key';
269
+ $key_column = 'meta_id';
270
+ $value_column = 'meta_value';
271
+ }
272
+
273
+ $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
274
+
275
+ $query = $wpdb->get_row( $wpdb->prepare( "
276
+ SELECT *
277
+ FROM {$table}
278
+ WHERE {$column} LIKE %s
279
+ ORDER BY {$key_column} ASC
280
+ LIMIT 1
281
+ ", $key ) );
282
+
283
+ $batch = new stdClass();
284
+ $batch->key = $query->$column;
285
+ $batch->data = maybe_unserialize( $query->$value_column );
286
+
287
+ return $batch;
288
+ }
289
+
290
+ /**
291
+ * Handle
292
+ *
293
+ * Pass each queue item to the task handler, while remaining
294
+ * within server memory and time limit constraints.
295
+ */
296
+ protected function handle() {
297
+ $this->lock_process();
298
+
299
+ do {
300
+ $batch = $this->get_batch();
301
+
302
+ foreach ( $batch->data as $key => $value ) {
303
+ $task = $this->task( $value );
304
+
305
+ if ( false !== $task ) {
306
+ $batch->data[ $key ] = $task;
307
+ } else {
308
+ unset( $batch->data[ $key ] );
309
+ }
310
+
311
+ if ( $this->time_exceeded() || $this->memory_exceeded() ) {
312
+ // Batch limits reached.
313
+ break;
314
+ }
315
+ }
316
+
317
+ // Update or delete current batch.
318
+ if ( ! empty( $batch->data ) ) {
319
+ $this->update( $batch->key, $batch->data );
320
+ } else {
321
+ $this->delete( $batch->key );
322
+ }
323
+ } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
324
+
325
+ $this->unlock_process();
326
+
327
+ // Start next batch or complete process.
328
+ if ( ! $this->is_queue_empty() ) {
329
+ $this->dispatch();
330
+ } else {
331
+ $this->complete();
332
+ }
333
+
334
+ wp_die();
335
+ }
336
+
337
+ /**
338
+ * Memory exceeded
339
+ *
340
+ * Ensures the batch process never exceeds 90%
341
+ * of the maximum WordPress memory.
342
+ *
343
+ * @return bool
344
+ */
345
+ protected function memory_exceeded() {
346
+ $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
347
+ $current_memory = memory_get_usage( true );
348
+ $return = false;
349
+
350
+ if ( $current_memory >= $memory_limit ) {
351
+ $return = true;
352
+ }
353
+
354
+ return apply_filters( $this->identifier . '_memory_exceeded', $return );
355
+ }
356
+
357
+ /**
358
+ * Get memory limit
359
+ *
360
+ * @return int
361
+ */
362
+ protected function get_memory_limit() {
363
+ if ( function_exists( 'ini_get' ) ) {
364
+ $memory_limit = ini_get( 'memory_limit' );
365
+ } else {
366
+ // Sensible default.
367
+ $memory_limit = '128M';
368
+ }
369
+
370
+ if ( ! $memory_limit || -1 === intval( $memory_limit ) ) {
371
+ // Unlimited, set to 32GB.
372
+ $memory_limit = '32000M';
373
+ }
374
+
375
+ return intval( $memory_limit ) * 1024 * 1024;
376
+ }
377
+
378
+ /**
379
+ * Time exceeded.
380
+ *
381
+ * Ensures the batch never exceeds a sensible time limit.
382
+ * A timeout limit of 30s is common on shared hosting.
383
+ *
384
+ * @return bool
385
+ */
386
+ protected function time_exceeded() {
387
+ $finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
388
+ $return = false;
389
+
390
+ if ( time() >= $finish ) {
391
+ $return = true;
392
+ }
393
+
394
+ return apply_filters( $this->identifier . '_time_exceeded', $return );
395
+ }
396
+
397
+ /**
398
+ * Complete.
399
+ *
400
+ * Override if applicable, but ensure that the below actions are
401
+ * performed, or, call parent::complete().
402
+ */
403
+ protected function complete() {
404
+ // Unschedule the cron healthcheck.
405
+ $this->clear_scheduled_event();
406
+ }
407
+
408
+ /**
409
+ * Schedule cron healthcheck
410
+ *
411
+ * @access public
412
+ * @param mixed $schedules Schedules.
413
+ * @return mixed
414
+ */
415
+ public function schedule_cron_healthcheck( $schedules ) {
416
+ $interval = apply_filters( $this->identifier . '_cron_interval', 5 );
417
+
418
+ if ( property_exists( $this, 'cron_interval' ) ) {
419
+ $interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval );
420
+ }
421
+
422
+ // Adds every 5 minutes to the existing schedules.
423
+ $schedules[ $this->identifier . '_cron_interval' ] = array(
424
+ 'interval' => MINUTE_IN_SECONDS * $interval,
425
+ 'display' => sprintf( __( 'Every %d Minutes' ), $interval ),
426
+ );
427
+
428
+ return $schedules;
429
+ }
430
+
431
+ /**
432
+ * Handle cron healthcheck
433
+ *
434
+ * Restart the background process if not already running
435
+ * and data exists in the queue.
436
+ */
437
+ public function handle_cron_healthcheck() {
438
+ if ( $this->is_process_running() ) {
439
+ // Background process already running.
440
+ exit;
441
+ }
442
+
443
+ if ( $this->is_queue_empty() ) {
444
+ // No data to process.
445
+ $this->clear_scheduled_event();
446
+ exit;
447
+ }
448
+
449
+ $this->handle();
450
+
451
+ exit;
452
+ }
453
+
454
+ /**
455
+ * Schedule event
456
+ */
457
+ protected function schedule_event() {
458
+ if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
459
+ wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier );
460
+ }
461
+ }
462
+
463
+ /**
464
+ * Clear scheduled event
465
+ */
466
+ protected function clear_scheduled_event() {
467
+ $timestamp = wp_next_scheduled( $this->cron_hook_identifier );
468
+
469
+ if ( $timestamp ) {
470
+ wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
471
+ }
472
+ }
473
+
474
+ /**
475
+ * Cancel Process
476
+ *
477
+ * Stop processing queue items, clear cronjob and delete batch.
478
+ *
479
+ */
480
+ public function cancel_process() {
481
+ if ( ! $this->is_queue_empty() ) {
482
+ $batch = $this->get_batch();
483
+
484
+ $this->delete( $batch->key );
485
+
486
+ wp_clear_scheduled_hook( $this->cron_hook_identifier );
487
+ }
488
+
489
+ }
490
+
491
+ /**
492
+ * Task
493
+ *
494
+ * Override this method to perform any actions required on each
495
+ * queue item. Return the modified item for further processing
496
+ * in the next pass through. Or, return false to remove the
497
+ * item from the queue.
498
+ *
499
+ * @param mixed $item Queue item to iterate over.
500
+ *
501
+ * @return mixed
502
+ */
503
+ abstract protected function task( $item );
504
+
505
+ }
506
+ }
vendor/a5hleyrich/wp-background-processing/license.txt ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
+ 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
6
+
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+ Preamble
11
+
12
+ The licenses for most software are designed to take away your
13
+ freedom to share and change it. By contrast, the GNU General Public
14
+ License is intended to guarantee your freedom to share and change free
15
+ software--to make sure the software is free for all its users. This
16
+ General Public License applies to most of the Free Software
17
+ Foundation's software and to any other program whose authors commit to
18
+ using it. (Some other Free Software Foundation software is covered by
19
+ the GNU Library General Public License instead.) You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ this service if you wish), that you receive source code or can get it
26
+ if you want it, that you can change the software or use pieces of it
27
+ in new free programs; and that you know you can do these things.
28
+
29
+ To protect your rights, we need to make restrictions that forbid
30
+ anyone to deny you these rights or to ask you to surrender the rights.
31
+ These restrictions translate to certain responsibilities for you if you
32
+ distribute copies of the software, or if you modify it.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must give the recipients all the rights that
36
+ you have. You must make sure that they, too, receive or can get the
37
+ source code. And you must show them these terms so they know their
38
+ rights.
39
+
40
+ We protect your rights with two steps: (1) copyright the software, and
41
+ (2) offer you this license which gives you legal permission to copy,
42
+ distribute and/or modify the software.
43
+
44
+ Also, for each author's protection and ours, we want to make certain
45
+ that everyone understands that there is no warranty for this free
46
+ software. If the software is modified by someone else and passed on, we
47
+ want its recipients to know that what they have is not the original, so
48
+ that any problems introduced by others will not reflect on the original
49
+ authors' reputations.
50
+
51
+ Finally, any free program is threatened constantly by software
52
+ patents. We wish to avoid the danger that redistributors of a free
53
+ program will individually obtain patent licenses, in effect making the
54
+ program proprietary. To prevent this, we have made it clear that any
55
+ patent must be licensed for everyone's free use or not licensed at all.
56
+
57
+ The precise terms and conditions for copying, distribution and
58
+ modification follow.
59
+
60
+ GNU GENERAL PUBLIC LICENSE
61
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
+
63
+ 0. This License applies to any program or other work which contains
64
+ a notice placed by the copyright holder saying it may be distributed
65
+ under the terms of this General Public License. The "Program", below,
66
+ refers to any such program or work, and a "work based on the Program"
67
+ means either the Program or any derivative work under copyright law:
68
+ that is to say, a work containing the Program or a portion of it,
69
+ either verbatim or with modifications and/or translated into another
70
+ language. (Hereinafter, translation is included without limitation in
71
+ the term "modification".) Each licensee is addressed as "you".
72
+
73
+ Activities other than copying, distribution and modification are not
74
+ covered by this License; they are outside its scope. The act of
75
+ running the Program is not restricted, and the output from the Program
76
+ is covered only if its contents constitute a work based on the
77
+ Program (independent of having been made by running the Program).
78
+ Whether that is true depends on what the Program does.
79
+
80
+ 1. You may copy and distribute verbatim copies of the Program's
81
+ source code as you receive it, in any medium, provided that you
82
+ conspicuously and appropriately publish on each copy an appropriate
83
+ copyright notice and disclaimer of warranty; keep intact all the
84
+ notices that refer to this License and to the absence of any warranty;
85
+ and give any other recipients of the Program a copy of this License
86
+ along with the Program.
87
+
88
+ You may charge a fee for the physical act of transferring a copy, and
89
+ you may at your option offer warranty protection in exchange for a fee.
90
+
91
+ 2. You may modify your copy or copies of the Program or any portion
92
+ of it, thus forming a work based on the Program, and copy and
93
+ distribute such modifications or work under the terms of Section 1
94
+ above, provided that you also meet all of these conditions:
95
+
96
+ a) You must cause the modified files to carry prominent notices
97
+ stating that you changed the files and the date of any change.
98
+
99
+ b) You must cause any work that you distribute or publish, that in
100
+ whole or in part contains or is derived from the Program or any
101
+ part thereof, to be licensed as a whole at no charge to all third
102
+ parties under the terms of this License.
103
+
104
+ c) If the modified program normally reads commands interactively
105
+ when run, you must cause it, when started running for such
106
+ interactive use in the most ordinary way, to print or display an
107
+ announcement including an appropriate copyright notice and a
108
+ notice that there is no warranty (or else, saying that you provide
109
+ a warranty) and that users may redistribute the program under
110
+ these conditions, and telling the user how to view a copy of this
111
+ License. (Exception: if the Program itself is interactive but
112
+ does not normally print such an announcement, your work based on
113
+ the Program is not required to print an announcement.)
114
+
115
+ These requirements apply to the modified work as a whole. If
116
+ identifiable sections of that work are not derived from the Program,
117
+ and can be reasonably considered independent and separate works in
118
+ themselves, then this License, and its terms, do not apply to those
119
+ sections when you distribute them as separate works. But when you
120
+ distribute the same sections as part of a whole which is a work based
121
+ on the Program, the distribution of the whole must be on the terms of
122
+ this License, whose permissions for other licensees extend to the
123
+ entire whole, and thus to each and every part regardless of who wrote it.
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
vendor/a5hleyrich/wp-background-processing/wp-background-processing.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP-Background Processing
4
+ *
5
+ * @package WP-Background-Processing
6
+ */
7
+
8
+ /*
9
+ Plugin Name: WP Background Processing
10
+ Plugin URI: https://github.com/A5hleyRich/wp-background-processing
11
+ Description: Asynchronous requests and background processing in WordPress.
12
+ Author: Delicious Brains Inc.
13
+ Version: 1.0
14
+ Author URI: https://deliciousbrains.com/
15
+ GitHub Plugin URI: https://github.com/A5hleyRich/wp-background-processing
16
+ GitHub Branch: master
17
+ */
18
+
19
+ require_once plugin_dir_path( __FILE__ ) . 'classes/wp-async-request.php';
20
+ require_once plugin_dir_path( __FILE__ ) . 'classes/wp-background-process.php';
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit40d46390c117e8cbe149ad058dd0a1b2::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit0109db78cca461b11b08bed8bbbfaabf::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -6,4 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
 
9
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'WP_Async_Request' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php',
10
+ 'WP_Background_Process' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php',
11
  );
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit40d46390c117e8cbe149ad058dd0a1b2
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit40d46390c117e8cbe149ad058dd0a1b2
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit40d46390c117e8cbe149ad058dd0a1b2', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit40d46390c117e8cbe149ad058dd0a1b2', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit40d46390c117e8cbe149ad058dd0a1b2::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit0109db78cca461b11b08bed8bbbfaabf
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit0109db78cca461b11b08bed8bbbfaabf', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit0109db78cca461b11b08bed8bbbfaabf', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit0109db78cca461b11b08bed8bbbfaabf::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit40d46390c117e8cbe149ad058dd0a1b2
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'M' =>
@@ -56,12 +56,18 @@ class ComposerStaticInit40d46390c117e8cbe149ad058dd0a1b2
56
  ),
57
  );
58
 
 
 
 
 
 
59
  public static function getInitializer(ClassLoader $loader)
60
  {
61
  return \Closure::bind(function () use ($loader) {
62
- $loader->prefixLengthsPsr4 = ComposerStaticInit40d46390c117e8cbe149ad058dd0a1b2::$prefixLengthsPsr4;
63
- $loader->prefixDirsPsr4 = ComposerStaticInit40d46390c117e8cbe149ad058dd0a1b2::$prefixDirsPsr4;
64
- $loader->prefixesPsr0 = ComposerStaticInit40d46390c117e8cbe149ad058dd0a1b2::$prefixesPsr0;
 
65
 
66
  }, null, ClassLoader::class);
67
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit0109db78cca461b11b08bed8bbbfaabf
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'M' =>
56
  ),
57
  );
58
 
59
+ public static $classMap = array (
60
+ 'WP_Async_Request' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php',
61
+ 'WP_Background_Process' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php',
62
+ );
63
+
64
  public static function getInitializer(ClassLoader $loader)
65
  {
66
  return \Closure::bind(function () use ($loader) {
67
+ $loader->prefixLengthsPsr4 = ComposerStaticInit0109db78cca461b11b08bed8bbbfaabf::$prefixLengthsPsr4;
68
+ $loader->prefixDirsPsr4 = ComposerStaticInit0109db78cca461b11b08bed8bbbfaabf::$prefixDirsPsr4;
69
+ $loader->prefixesPsr0 = ComposerStaticInit0109db78cca461b11b08bed8bbbfaabf::$prefixesPsr0;
70
+ $loader->classMap = ComposerStaticInit0109db78cca461b11b08bed8bbbfaabf::$classMap;
71
 
72
  }, null, ClassLoader::class);
73
  }
vendor/composer/installed.json CHANGED
@@ -1,4 +1,42 @@
1
  [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {
3
  "name": "composer/ca-bundle",
4
  "version": "1.1.1",
1
  [
2
+ {
3
+ "name": "a5hleyrich/wp-background-processing",
4
+ "version": "1.0.1",
5
+ "version_normalized": "1.0.1.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/A5hleyRich/wp-background-processing.git",
9
+ "reference": "1f070aab5058dbaf45d5435a343033ddd8a641b1"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/A5hleyRich/wp-background-processing/zipball/1f070aab5058dbaf45d5435a343033ddd8a641b1",
14
+ "reference": "1f070aab5058dbaf45d5435a343033ddd8a641b1",
15
+ "shasum": ""
16
+ },
17
+ "require": {
18
+ "php": ">=5.2"
19
+ },
20
+ "time": "2018-02-12T09:24:05+00:00",
21
+ "type": "library",
22
+ "installation-source": "dist",
23
+ "autoload": {
24
+ "classmap": [
25
+ "classes/"
26
+ ]
27
+ },
28
+ "notification-url": "https://packagist.org/downloads/",
29
+ "license": [
30
+ "GPL-2.0-only"
31
+ ],
32
+ "authors": [
33
+ {
34
+ "name": "Ashley Rich",
35
+ "email": "hello@ashleyrich.com"
36
+ }
37
+ ],
38
+ "description": "WP Background Processing can be used to fire off non-blocking asynchronous requests or as a background processing tool, allowing you to queue tasks."
39
+ },
40
  {
41
  "name": "composer/ca-bundle",
42
  "version": "1.1.1",