Completed
Push — master ( 9e710c...874700 )
by Sébastien
02:12
created

wc-satt-stt.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * Plugin Name: WooCommerce Subscribe to All the Things - Sign up and Trial Addon
4
 * Plugin URI:  https://sebastiendumont.com
5
 * Version:     1.0.0 Alpha
6
 * Description: Add a sign up fee and free trial for each subscription scheme. Requires WooCommerce Subscribe to All the Things extension v1.1.1+.
7
 * Author:      Sebastien Dumont
8
 * Author URI:  https://sebastiendumont.com
9
 *
10
 * Text Domain: wc-satt-stt
11
 * Domain Path: /languages/
12
 *
13
 * Requires at least: 4.1
14
 * Tested up to: 4.5.2
15
 *
16
 * Copyright: © 2016 Sebastien Dumont
17
 * License: GNU General Public License v3.0
18
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
19
 */
20
if ( ! defined('ABSPATH') ) exit; // Exit if accessed directly.
21
22
if ( ! class_exists( 'WCSATT_STT' ) ) {
23
	class WCSATT_STT {
24
25
		/* Plugin version. */
26
		const VERSION = '1.0.0';
27
28
		/* Required WC version. */
29
		const REQ_WC_VERSION = '2.3.0';
30
31
		/* Required WCSATT version */
32
		const REQ_WCSATT_VERSION = '1.1.1';
33
34
		/* Text domain. */
35
		const TEXT_DOMAIN = 'wc-satt-stt';
36
37
		/**
38
		 * @var WCSATT_STT - the single instance of the class.
39
		 *
40
		 * @since 1.0.0
41
		 */
42
		protected static $_instance = null;
43
44
		/**
45
		 * Main WCSATT_STT Instance.
46
		 *
47
		 * Ensures only one instance of WCSATT_STT is loaded or can be loaded.
48
		 *
49
		 * @static
50
		 * @see WCSATT_STT()
51
		 * @return WCSATT_STT - Main instance
52
		 * @since 1.0.0
53
		 */
54
		public static function instance() {
55
			if ( is_null( self::$_instance ) ) {
56
				self::$_instance = new self();
57
			}
58
			return self::$_instance;
59
		}
60
61
		/**
62
		 * Cloning is forbidden.
63
		 *
64
		 * @since 1.0.0
65
		 */
66
		public function __clone() {
67
			_doing_it_wrong( __FUNCTION__, __( 'Foul!' ), '1.0.0' );
68
		}
69
70
		/**
71
		 * Unserializing instances of this class is forbidden.
72
		 *
73
		 * @since 1.0.0
74
		 */
75
		public function __wakeup() {
76
			_doing_it_wrong( __FUNCTION__, __( 'Foul!' ), '1.0.0' );
77
		}
78
79
		/**
80
		 * Load the plugin.
81
		 */
82
		public function __construct() {
83
			add_action( 'plugins_loaded', array( $this, 'load_plugin' ) );
84
			add_action( 'init', array( $this, 'init_plugin' ) );
85
			add_action( 'admin_init', array( $this, 'admin_wcsatt_stt_product_meta' ) );
86
			add_filter( 'plugin_row_meta', array( $this, 'plugin_meta_links' ), 10, 4 );
87
		}
88
89
		public function plugin_path() {
90
			return untrailingslashit( plugin_dir_path( __FILE__ ) );
91
		} // END plugin_path()
92
93
		/*
94
		 * Check requirements on activation.
95
		 */
96
		public function load_plugin() {
97
			global $woocommerce;
98
99
			// Check that the required WooCommerce is running.
100
			if ( version_compare( $woocommerce->version, self::REQ_WC_VERSION ) < 0 ) {
101
				add_action( 'admin_notices', array( $this, 'wcsatt_stt_wc_admin_notice' ) );
102
				return false;
103
			}
104
105
			// Checks that WooCommerce Subscribe All the Things is running or is less than the required version.
106
			if ( ! class_exists( 'WCS_ATT' ) || version_compare( WCS_ATT::VERSION, self::REQ_WCSATT_VERSION ) < '1.1.1' ) {
107
				add_action( 'admin_notices', array( $this, 'wcsatt_stt_admin_notice' ) );
108
				return false;
109
			}
110
		} // END load_plugin()
111
112
		/**
113
		 * Display a warning message if minimum version of WooCommerce check fails.
114
		 *
115
		 * @return void
116
		 */
117
		public function wcsatt_stt_wc_admin_notice() {
118
			echo '<div class="error"><p>' . sprintf( __( '%1$s requires at least %2$s v%3$s in order to function. Please upgrade %2$s.', 'wc-satt-stt' ), 'Sign up and Trial Options for WCSATT', 'WooCommerce', self::REQ_WC_VERSION ) . '</p></div>';
119
		} // END wcsatt_stt_wc_admin_notice()
120
121
		/**
122
		 * Display a warning message if minimum version of WooCommerce Subscribe to All the Things check fails.
123
		 *
124
		 * @return void
125
		 */
126
		public function wcsatt_stt_admin_notice() {
127
			echo '<div class="error"><p>' . sprintf( __( '%1$s requires at least %2$s v%3$s in order to function. Please upgrade %2$s.', 'wc-satt-stt' ), 'Sign up and Trial Options Addon', 'WooCommerce Subscribe to All the Things', self::REQ_WCSATT_VERSION ) . '</p></div>';
128
		} // END wcsatt_stt_admin_notice()
129
130
		/**
131
		 * Initialize the plugin if ready.
132
		 *
133
		 * @return void
134
		 */
135
		public function init_plugin() {
136
			// Load text domain.
137
			load_plugin_textdomain( 'wc-satt-stt', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
138
139
			// Adds the sign up fee and trial data to the price html on the 'wcsatt_overridden_subscription_prices_product' filter.
140
			add_filter( 'wcsatt_overridden_subscription_prices_product', array( $this, 'add_sub_scheme_data_price_html' ), 10, 3 );
141
142
			// Filters the suffix price html on the 'wcsatt_suffix_price_html' filter.
143
			add_filter( 'wcsatt_suffix_price_html', array( $this, 'filter_suffix_price_html' ), 10, 1 );
144
145
			// Overrides the price of the subscription for sign up fee and/or trial on the 'woocommerce_add_cart_item' filter.
146
			add_filter( 'woocommerce_add_cart_item', array( $this, 'add_cart_item' ), 15, 1 );
147
		} // END init_plugin()
148
149
		/**
150
		 * Register the product meta data fields.
151
		 *
152
		 * @return void
153
		 */
154
		public function admin_wcsatt_stt_product_meta() {
155
			// Subscription scheme options displayed on the 'wcsatt_subscription_scheme_content' action.
156
			//add_action( 'wcsatt_subscription_scheme_content', array( $this, 'wcsatt_stt_fields' ), 15, 3 );
157
158
			// Subscription scheme options displayed on the 'wcsatt_subscription_scheme_product_content' action.
159
			add_action( 'wcsatt_subscription_scheme_product_content', array( $this, 'wcsatt_stt_fields' ), 15, 3 );
160
161
			// Filter the subscription scheme data to process the sign up and trial options on the ''wcsatt_subscription_scheme_process_scheme_data' filter.
162
			add_filter( 'wcsatt_subscription_scheme_process_scheme_data', array( $this, 'wcsatt_stt_process_scheme_data' ), 10, 2 );
163
		} // END admin_wcsatt_stt_product_meta()
164
165
		/**
166
		 * Show row meta on the plugin screen.
167
		 *
168
		 * @param mixed $links Plugin Row Meta
169
		 * @param mixed $file  Plugin Base file
170
		 * @return array
171
		 */
172
		public function plugin_meta_links( $links, $file, $data, $status ) {
173
			if ( $file == plugin_basename( __FILE__ ) ) {
174
				$author1 = '<a href="' . $data[ 'AuthorURI' ] . '">' . $data[ 'Author' ] . '</a>';
175
				$links[ 1 ] = sprintf( __( 'By %s', WCSATT_STT::TEXT_DOMAIN ), $author1 );
176
			}
177
178
			return $links;
179
		} // END plugin_meta_links()
180
181
		/**
182
		 * Subscriptions schemes admin metaboxes.
183
		 *
184
		 * @param  array $defaults
185
		 * @return void
186
		 */
187
		public static function add_default_subscription_schemes_content( $defaults ) {
188
			$new_defaults = array(
189
				'subscription_sign_up_fee' => '',
190
				'subscription_trial_length' => 0,
191
				'subscription_trial_period' => ''
192
			);
193
194
			return array_merge( $new_defaults, $defaults );
195
		} // END add_default_subscription_schemes_content()
196
197
		/**
198
		 * Adds the trial and sign up fields under the subscription section.
199
		 *
200
		 * @param  int   $index
201
		 * @param  array $scheme_data
202
		 * @param  int   $post_id
203
		 * @return void
204
		 */
205
		public function wcsatt_stt_fields( $index, $scheme_data, $post_id ) {
206
			if ( ! empty( $scheme_data ) ) {
207
				$subscription_sign_up_fee = ! empty( $scheme_data[ 'subscription_sign_up_fee' ] ) ? $scheme_data[ 'subscription_sign_up_fee' ] : 'inherit';
208
				$subscription_trial_length = isset( $scheme_data[ 'subscription_trial_length' ] ) ? $scheme_data[ 'subscription_trial_length' ] : '';
209
				$subscription_trial_period = isset( $scheme_data[ 'subscription_trial_period' ] ) ? $scheme_data[ 'subscription_trial_period' ] : '';
210
			} else {
211
				$subscription_sign_up_fee = '';
212
				$subscription_trial_length = 0;
213
				$subscription_trial_period = '';
214
			}
215
216
			// Sign-up Fee
217
			woocommerce_wp_text_input( array(
218
				'id'          => '_subscription_sign_up_fee',
219
				'class'       => 'wc_input_subscription_intial_price',
220
				// translators: %s is a currency symbol / code
221
				'label'       => sprintf( __( 'Sign-up Fee (%s)', WCSATT_STT::TEXT_DOMAIN ), get_woocommerce_currency_symbol() ),
222
				'placeholder' => _x( 'e.g. 9.90', 'example price', WCSATT_STT::TEXT_DOMAIN ),
223
				'description' => __( 'Optionally include an amount to be charged at the outset of the subscription. The sign-up fee will be charged immediately, even if the product has a free trial or the payment dates are synced.', WCSATT_STT::TEXT_DOMAIN ),
224
				'desc_tip'    => true,
225
				'type'        => 'text',
226
				'custom_attributes' => array(
227
					'step' => 'any',
228
					'min'  => '0',
229
				),
230
				'name'        => 'wcsatt_schemes[' . $index . '][subscription_sign_up_fee]',
231
				'value'       => $subscription_sign_up_fee
232
			) );
233
234
			// Trial Length
235
			woocommerce_wp_text_input( array(
236
				'id'          => '_subscription_trial_length',
237
				'class'       => 'wc_input_subscription_trial_length',
238
				'label'       => __( 'Free Trial', WCSATT_STT::TEXT_DOMAIN ),
239
				'name'        => 'wcsatt_schemes[' . $index . '][subscription_trial_length]',
240
				'value'       => $subscription_trial_length
241
			) );
242
243
			// Trial Period
244
			woocommerce_wp_select( array(
245
				'id'          => '_subscription_trial_period',
246
				'class'       => 'wc_input_subscription_trial_period',
247
				'label'       => __( 'Subscription Trial Period', WCSATT_STT::TEXT_DOMAIN ),
248
				'options'     => wcs_get_available_time_periods(),
249
				// translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks")
250
				'description' => sprintf( _x( 'An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s', 'Trial period dropdown\'s description in pricing fields', WCSATT_STT::TEXT_DOMAIN ), WC_Subscriptions_Admin::get_trial_period_validation_message() ),
251
				'desc_tip'    => true,
252
				'value'       => WC_Subscriptions_Product::get_trial_period( $post_id ), // Explicitly set value in to ensure backward compatibility
253
				'name'        => 'wcsatt_schemes[' . $index . '][subscription_trial_period]',
254
				'value'       => $subscription_trial_period
255
		) );
256
		} // END wcsatt_stt_fields()
257
258
		/**
259
		 * Filters the subscription scheme data to pass the 
260
		 * sign up and trial options when saving.
261
		 *
262
		 * @param  ini $posted_scheme
263
		 * @param  string $product_type
264
		 * @return void
265
		 */
266
		public function wcsatt_stt_process_scheme_data( $posted_scheme, $product_type ) {
267
			// Copy variable type fields.
268
			if ( 'variable' == $product_type ) {
269
				if ( isset( $posted_scheme[ 'subscription_sign_up_fee_variable' ] ) ) {
270
					$posted_scheme[ 'subscription_sign_up_fee' ] = $posted_scheme[ 'subscription_sign_up_fee_variable' ];
271
				}
272
				if ( isset( $posted_scheme[ 'subscription_trial_length_variable' ] ) ) {
273
					$posted_scheme[ 'subscription_trial_length' ] = $posted_scheme[ 'subscription_trial_length_variable' ];
274
				}
275
				if ( isset( $posted_scheme[ 'subscription_trial_period_variable' ] ) ) {
276
					$posted_scheme[ 'subscription_trial_period' ] = $posted_scheme[ 'subscription_trial_period_variable'];
277
				}
278
			}
279
280
			// Format subscription sign up fee.
281 View Code Duplication
			if ( isset( $posted_scheme[ 'subscription_sign_up_fee' ] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282
				$posted_scheme[ 'subscription_sign_up_fee' ] = ( $posted_scheme[ 'subscription_sign_up_fee' ] === '' ) ? '' : wc_format_decimal( $posted_scheme[ 'subscription_sign_up_fee' ] );
283
			}
284
285
			// Format subscription trial length.
286 View Code Duplication
			if ( isset( $posted_scheme[ 'subscription_trial_length' ] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
287
				$posted_scheme[ 'subscription_trial_length' ] = ( $posted_scheme[ 'subscription_trial_length' ] === '' ) ? '' : wc_format_decimal( $posted_scheme[ 'subscription_trial_length' ] );
288
			}
289
290
			// Format subscription trial period.
291
			$trial_periods = apply_filters( 'wcsatt_stt_trial_periods', array( 'day', 'week', 'month', 'year' ) );
292
			if ( isset( $posted_scheme[ 'subscription_trial_period' ] ) && in_array( $posted_scheme[ 'subscription_trial_period' ], $trial_periods ) ) {
293
				$posted_scheme[ 'subscription_trial_period' ] = $posted_scheme[ 'subscription_trial_period' ];
294
			}
295
296
			return $posted_scheme;
297
		} // END wcsatt_stt_process_scheme_data()
298
299
		/**
300
		 * Adds the additional subscription scheme data for products with attached subscription schemes.
301
		 *
302
		 * @param  object     $_product
303
		 * @param  array      $subscription_scheme
304
		 * @param  WC_Product $product
305
		 * @return string
306
		 */
307
		public function add_sub_scheme_data_price_html( $_product, $subscription_scheme, $product ) {
308
			if ( isset( $subscription_scheme[ 'subscription_sign_up_fee' ] ) ) {
309
				$_product->subscription_sign_up_fee = $subscription_scheme[ 'subscription_sign_up_fee' ];
310
			}
311
312
			if ( isset( $subscription_scheme[ 'subscription_trial_length' ] ) ) {
313
				$_product->subscription_trial_length = $subscription_scheme[ 'subscription_trial_length' ];
314
			}
315
316
			if ( isset( $subscription_scheme[ 'subscription_trial_period' ] ) ) {
317
				$_product->subscription_trial_period = $subscription_scheme[ 'subscription_trial_period' ];
318
			}
319
320
			return $_product;
321
		}
322
323
		/**
324
		 * Filter the suffix price string.
325
		 *
326
		 * @param object     $_product
327
		 * @param array      $subscription_scheme
328
		 * @param WC_Product $product
329
		 * @return string
330
		 */
331
		public function filter_suffix_price_html( $_product, $subscription_scheme, $product ) {
332
			$subscription_string = '';
333
334
			if ( isset( $_product->subscription_trial_length ) && 0 != $_product->subscription_trial_length ) {
335
				$trial_string = wcs_get_subscription_trial_period_strings( $_product->subscription_trial_length, $_product->subscription_trial_period );
336
				// translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years"), 2$: trial length (e.g.: "with 4 months free trial")
337
				$subscription_string = sprintf( __( '%1$s with %2$s free trial', WCSATT_STT::TEXT_DOMAIN ), $subscription_string, $trial_string );
338
			}
339
340
			$sign_up_fee = $_product->subscription_sign_up_fee;
341
342
			if ( is_numeric( $sign_up_fee ) ) {
343
				$sign_up_fee = wc_price( $sign_up_fee );
344
			}
345
346
			if ( isset( $_product->subscription_sign_up_fee ) && $_product->subscription_sign_up_fee > 0 ) {
347
				// translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a $30 sign-up fee")
348
				$subscription_string = sprintf( __( '%1$s and a %2$s sign-up fee', WCSATT_STT::TEXT_DOMAIN ), $subscription_string, $sign_up_fee );
349
			}
350
351
			return $subscription_string;
352
		}
353
354
		/**
355
		 * Converts a cart item if it's a subscription with 
356
		 * a trial subscription or/and has a sign-up fee.
357
		 *
358
		 * @param  array $cart_item
359
		 * @return array
360
		 */
361
		public function add_cart_item( $cart_item ) {
362
			$active_scheme = WCS_ATT_Schemes::get_active_subscription_scheme( $cart_item );
363
364
			if ( $active_scheme && $cart_item['data']->is_converted_to_sub == 'yes' ) {
365
366
				$sign_up_fee  = $this->get_item_signup_fee( $cart_item[ 'product_id' ], $active_scheme );
367
				$trial_length = $this->get_item_trial_length( $cart_item[ 'product_id' ], $active_scheme );
368
				$trial_period = $this->get_item_trial_period( $cart_item[ 'product_id' ], $active_scheme );
369
370
				// Subscription Price
371
				$price = $cart_item['data']->subscription_price;
372
373
				// Is there a sign up fee?
374
				$sign_up_fee = ! empty( $sign_up_fee ) ? $sign_up_fee : '';
375
376
				// If a trial length is more than zero then re-adjust the price.
377
				if ( $trial_length > 0 ) {
378
					$cart_item['data']->price = $sign_up_fee;
379
					$cart_item['data']->subscription_price = $sign_up_fee;
380
					$cart_item['data']->sale_price = $sign_up_fee;
381
					$cart_item['data']->regular_price = $sign_up_fee;
382
					$cart_item['data']->initial_amount = $sign_up_fee;
383
					$cart_item['data']->subscription_sign_up_fee = $sign_up_fee;
384
					$cart_item['data']->subscription_trial_length = $trial_length;
385
					$cart_item['data']->subscription_trial_period = $trial_period;
386
				} else {
387
					$cart_item['data']->price = $price + $sign_up_fee;
388
					$cart_item['data']->subscription_price = $price + $sign_up_fee;
389
					$cart_item['data']->sale_price = $price + $sign_up_fee;
390
					$cart_item['data']->regular_price = $price + $sign_up_fee;
391
					$cart_item['data']->initial_amount = $price + $sign_up_fee;
392
					$cart_item['data']->subscription_sign_up_fee = $sign_up_fee;
393
					$cart_item['data']->subscription_trial_length = 0;
394
					$cart_item['data']->subscription_trial_period = '';
395
				}
396
397
			}
398
399
			return $cart_item;
400
		} // END add_cart_item()
401
402
		/**
403
		 * Get the item signup fee from the subscription scheme.
404
		 *
405
		 * @param int  $product_id
406
		 * @param int  $scheme_id
407
		 * @return int
408
		 */
409
		public function get_item_signup_fee( $product_id, $scheme_id ) {
410
			$product_schemes = get_post_meta( $product_id, '_wcsatt_schemes', true );
411
			$thescheme = $product_schemes[$scheme_id];
412
413
			return $thescheme['subscription_sign_up_fee'];
414
		} // END get_item_signup_fee()
415
416
		/**
417
		 * Get the item trial length from the subscription scheme.
418
		 *
419
		 * @param int  $product_id
420
		 * @param int  $scheme_id
421
		 * @return int
422
		 */
423
		public function get_item_trial_length( $product_id, $scheme_id ) {
424
			$product_schemes = get_post_meta( $product_id, '_wcsatt_schemes', true );
425
			$thescheme = $product_schemes[$scheme_id];
426
427
			return $thescheme['subscription_trial_length'];
428
		} // END get_item_trial_length()
429
430
		/**
431
		 * Get the item trial period from the subscription scheme.
432
		 *
433
		 * @param  int    $product_id
434
		 * @param  int    $scheme_id
435
		 * @return string
436
		 */
437
		public function get_item_trial_period( $product_id, $scheme_id ) {
438
			$product_schemes = get_post_meta( $product_id, '_wcsatt_schemes', true );
439
			$thescheme = $product_schemes[$scheme_id];
440
441
			return $thescheme['subscription_trial_period'];
442
		} // END get_item_trial_period()
443
444
	} // END class
445
446
} // END if class exists
447
448
return WCSATT_STT::instance();