Algolia_Send_Products   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
eloc 71
c 8
b 0
f 0
dl 0
loc 180
rs 10
wmc 14

3 Methods

Rating   Name   Duplication   Size   Complexity  
B send_products_to_algolia() 0 121 9
A get_product_type_price() 0 13 3
A can_connect_to_algolia() 0 13 2
1
<?php
2
3
/**
4
 * Algolia Woo Indexer class for sending products
5
 * Called from main plugin file algolia-woo-indexer.php
6
 *
7
 * @package algolia-woo-indexer
8
 */
9
10
namespace Algowoo;
11
12
use Algowoo\Algolia_Check_Requirements;
13
14
/**
15
 * Abort if this file is called directly
16
 */
17
if ( ! defined( 'ABSPATH' ) ) {
18
	exit;
19
}
20
21
/**
22
 * Include plugin file if function is_plugin_active does not exist
23
 */
24
if ( ! function_exists( 'is_plugin_active' ) ) {
25
	require_once ABSPATH . '/wp-admin/includes/plugin.php';
26
}
27
28
/**
29
 * Define the plugin version and the database table name
30
 */
31
define( 'ALGOWOO_DB_OPTION', '_algolia_woo_indexer' );
32
define( 'ALGOWOO_CURRENT_DB_VERSION', '0.3' );
33
34
/**
35
 * Define application constants
36
 */
37
define( 'CHANGE_ME', 'change me' );
38
39
/**
40
 * Database table names
41
 */
42
define( 'INDEX_NAME', '_index_name' );
43
define( 'AUTOMATICALLY_SEND_NEW_PRODUCTS', '_automatically_send_new_products' );
44
define( 'ALGOLIA_APP_ID', '_application_id' );
45
define( 'ALGOLIA_API_KEY', '_admin_api_key' );
46
47
if ( ! class_exists( 'Algolia_Send_Products' ) ) {
48
	/**
49
	 * Algolia WooIndexer main class
50
	 */
51
52
	// TODO Rename class "Algolia_Send_Products" to match the regular expression ^[A-Z][a-zA-Z0-9]*$.
53
	class Algolia_Send_Products {
54
55
		const PLUGIN_NAME      = 'Algolia Woo Indexer';
56
		const PLUGIN_TRANSIENT = 'algowoo-plugin-notice';
57
58
		/**
59
		 * The Algolia instance
60
		 *
61
		 * @var \Algolia\AlgoliaSearch\SearchClient
62
		 */
63
		private static $algolia = null;
64
65
		/**
66
		 * Check if we can connect to Algolia, if not, handle the exception, display an error and then return
67
		 */
68
		public static function can_connect_to_algolia() {
69
			try {
70
				self::$algolia->listApiKeys();
71
			} catch ( \Algolia\AlgoliaSearch\Exceptions\UnreachableException $error ) {
72
				add_action(
73
					'admin_notices',
74
					function () {
75
						echo '<div class="error notice">
76
							  <p>' . esc_html__( 'An error has been encountered. Please check your application ID and API key. ', 'algolia-woo-indexer' ) . '</p>
77
							</div>';
78
					}
79
				);
80
				return;
81
			}
82
		}
83
84
		/**
85
		 * Get sale price or regular price based on product type
86
		 *
87
		 * @param  mixed $product Product to check
88
		 * @return array ['sale_price' => $sale_price,'regular_price' => $regular_price] Array with regular price and sale price
89
		 */
90
		public static function get_product_type_price( $product ) {
91
			$sale_price    = 0;
92
			$regular_price = 0;
93
			if ( $product->is_type( 'simple' ) ) {
94
				$sale_price    = $product->get_sale_price();
95
				$regular_price = $product->get_regular_price();
96
			} elseif ( $product->is_type( 'variable' ) ) {
97
				$sale_price    = $product->get_variation_sale_price( 'min', true );
98
				$regular_price = $product->get_variation_regular_price( 'max', true );
99
			}
100
			return array(
101
				'sale_price'    => $sale_price,
102
				'regular_price' => $regular_price,
103
			);
104
		}
105
106
		/**
107
		 * Send WooCommerce products to Algolia
108
		 *
109
		 * @param Int $id Product to send to Algolia if we send only a single product
110
		 * @return void
111
		 */
112
		public static function send_products_to_algolia( $id = '' ) {
113
			/**
114
			 * Remove classes from plugin URL and autoload Algolia with Composer
115
			 */
116
117
			$base_plugin_directory = str_replace( 'classes', '', __DIR__ );
118
			require_once $base_plugin_directory . '/vendor/autoload.php';
119
120
			/**
121
			 * Fetch the required variables from the Settings API
122
			 */
123
124
			$algolia_application_id = get_option( ALGOWOO_DB_OPTION . ALGOLIA_APP_ID );
125
			$algolia_application_id = is_string( $algolia_application_id ) ? $algolia_application_id : CHANGE_ME;
126
127
			$algolia_api_key = get_option( ALGOWOO_DB_OPTION . ALGOLIA_API_KEY );
128
			$algolia_api_key = is_string( $algolia_api_key ) ? $algolia_api_key : CHANGE_ME;
129
130
			$algolia_index_name = get_option( ALGOWOO_DB_OPTION . INDEX_NAME );
131
			$algolia_index_name = is_string( $algolia_index_name ) ? $algolia_index_name : CHANGE_ME;
132
133
			/**
134
			 * Display admin notice and return if not all values have been set
135
			 */
136
137
			Algolia_Check_Requirements::check_algolia_input_values( $algolia_application_id, $algolia_api_key, $algolia_index_name );
138
139
			/**
140
			 * Initiate the Algolia client
141
			 */
142
			self::$algolia = \Algolia\AlgoliaSearch\SearchClient::create( $algolia_application_id, $algolia_api_key );
143
144
			/**
145
			 * Check if we can connect, if not, handle the exception, display an error and then return
146
			 */
147
			self::can_connect_to_algolia();
148
149
			/**
150
			 * Initialize the search index and set the name to the option from the database
151
			 */
152
			$index = self::$algolia->initIndex( $algolia_index_name );
153
154
			/**
155
			 * Setup arguments for sending all products to Algolia
156
			 *
157
			 * Limit => -1 means we send all products
158
			 */
159
			$arguments = array(
160
				'status'   => 'publish',
161
				'limit'    => -1,
162
				'paginate' => false,
163
			);
164
165
			/**
166
			 * Setup arguments for sending only a single product
167
			 */
168
			if ( isset( $id ) && '' !== $id ) {
169
				$arguments = array(
170
					'status'   => 'publish',
171
					'include'  => array( $id ),
172
					'paginate' => false,
173
				);
174
			}
175
176
			/**
177
			 * Fetch all products from WooCommerce
178
			 *
179
			 * @see https://docs.woocommerce.com/wc-apidocs/function-wc_get_products.html
180
			 */
181
			$products =
182
				/** @scrutinizer ignore-call */
183
				wc_get_products( $arguments );
184
185
			if ( empty( $products ) ) {
186
				return;
187
			}
188
			$records = array();
189
			$record  = array();
190
191
			foreach ( $products as $product ) {
192
				/**
193
				 * Set sale price or regular price based on product type
194
				 */
195
				$product_type_price = self::get_product_type_price( $product );
196
				$sale_price         = $product_type_price['sale_price'];
197
				$regular_price      = $product_type_price['regular_price'];
198
199
				/**
200
				 * Extract image from $product->get_image()
201
				 */
202
				preg_match( '/<img(.*)src(.*)=(.*)"(.*)"/U', $product->get_image(), $result );
203
				$product_image = array_pop( $result );
204
				/**
205
				 * Build the record array using the information from the WooCommerce product
206
				 */
207
				$record['objectID']          = $product->get_id();
208
				$record['product_name']      = $product->get_name();
209
				$record['product_image']     = $product_image;
210
				$record['short_description'] = $product->get_short_description();
211
				$record['regular_price']     = $regular_price;
212
				$record['sale_price']        = $sale_price;
213
				$record['on_sale']           = $product->is_on_sale();
214
				$records[]                   = $record;
215
			}
216
			wp_reset_postdata();
217
218
			/**
219
			 * Send the information to Algolia and save the result
220
			 * If result is NullResponse, print an error message
221
			 */
222
			$result = $index->saveObjects( $records );
223
224
			if ( 'Algolia\AlgoliaSearch\Response\NullResponse' === get_class( $result ) ) {
225
				wp_die( esc_html__( 'No response from the server. Please check your settings and try again', 'algolia_woo_indexer_settings' ) );
226
			}
227
228
			/**
229
			 * Display success message
230
			 */
231
			echo '<div class="notice notice-success is-dismissible">
232
					 	<p>' . esc_html__( 'Product(s) sent to Algolia.', 'algolia-woo-indexer' ) . '</p>
233
				  		</div>';
234
		}
235
	}
236
}
237