Completed
Push — master ( e2b75e...467e55 )
by Sébastien
02:30
created

WCSS_Shortcodes::force_is_subscription()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 2
Metric Value
c 3
b 0
f 2
dl 0
loc 15
rs 9.2
cc 4
eloc 5
nc 3
nop 3
1
<?php
2
/**
3
 * Subscription Shortcodes
4
 *
5
 * @class WCSS_Shortcodes
6
 * @since 1.0.0
7
 */
8
9
class WCSS_Shortcodes {
10
11
	/**
12
	 * Initialize the shortcodes.
13
	 */
14
	public static function init() {
15
		$shortcodes = array(
16
			'subscription_price'           => 'get_subscription_price',
17
			'subscription_price_meta'      => 'get_subscription_price_meta',
18
			'subscription_discount'        => 'get_subscription_discount',
19
			'subscription_period'          => 'get_subscription_period',
20
			'subscription_period_interval' => 'get_subscription_period_interval',
21
			'subscription_length'          => 'get_subscription_length',
22
			'subscription_sign_up_fee'     => 'get_subscription_sign_up_fee',
23
			'subscription_trial'           => 'get_subscription_trial_string',
24
			'subscription_trial_length'    => 'get_subscription_trial_length',
25
			'subscription_trial_period'    => 'get_subscription_trial_period',
26
			'subscription_first_payment'   => 'get_subscription_first_payment',
27
			'subscription_initial_payment' => 'get_subscription_initial',
28
		);
29
30
		foreach ( $shortcodes as $shortcode => $function ) {
31
			add_shortcode( apply_filters( "{$shortcode}_shortcode_tag", $shortcode ), array( __CLASS__, $function ) );
32
		} // END foreach()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
33
34
		// Adds support for product types that have subscription scheme options.
35
		add_filter( 'woocommerce_is_subscription', array( __CLASS__, 'force_is_subscription' ), 10, 3 );
36
37
		// Adds alternative subscription price from the WooCommerce extension "Subscribe to All the Things" and returns the lowest scheme price.
38
		add_action( 'woocommerce_subscriptions_shortcode_get_price', array( __CLASS__, 'get_satt_lowest_price' ), 10, 1 );
39
40
		// Adds the product types supported from the WooCommerce extension "Subscribe to All the Things".
41
		add_filter( 'wcss_product_types', array( __CLASS__, 'support_product_types_for_wc_satt' ), 10, 1 );
42
	} // END init()
43
44
	/**
45
	 * Get the supported product types.
46
	 * By default, this is only the subscription product types.
47
	 * However, it can be filtered to allow other product types should you need to.
48
	 *
49
	 * @return array
50
	 */
51
	public static function get_supported_product_types() {
52
		return apply_filters( 'wcss_product_types', array(
53
			'subscription', 
54
			'subscription-variation', 
55
		) );
56
	} // END get_supported_product_types()
57
58
	/**
59
	 * Adds support for product types that have subscription scheme options.
60
	 *
61
	 * @param  bool   $is_subscription
62
	 * @param  int    $product_id
63
	 * @param  object $product
64
	 * @return bool
65
	 */
66
	public static function force_is_subscription( $is_subscription, $product_id, $product ) {
67
		/*if ( is_object( $product ) ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
68
			$product = $product;
69
		} elseif ( is_numeric( $product_id ) ) {
70
			$product = wc_get_product( $product_id );
71
		}*/
72
73
		if ( in_array( $product->product_type, self::get_supported_product_types() ) ) {
74
			if ( class_exists( 'WCS_ATT_Schemes' ) && WCS_ATT_Schemes::get_product_subscription_schemes( $product ) ) {
75
				$is_subscription = true;
76
			}
77
		}
78
79
		return $is_subscription;
80
	} // END force_is_subscription()
81
82
	/**
83
	 * Returns the subscription price string.
84
	 *
85
	 * @param  WC_Product $product
86
	 * @return string
87
	 */
88
	public static function get_price( $product ) {
89
		if ( WC_Subscriptions_Product::get_price( $product->id ) > 0 ) {
90
91
			return ecs_html( WC_Subscriptions_Product::get_price( $product->id, array(
92
				'subscription_period' => false,
93
				'subscription_length' => false,
94
				'sign_up_fee'         => false,
95
				'trial_length'        => false,
96
			) ) );
97
98
		} else {
99
100
			/**
101
			 * This hook enables for other price possibilities.
102
			 *
103
			 * hooked: get_satt_lowest_price - 10
104
			 */
105
			do_action( 'woocommerce_subscriptions_shortcode_get_price', $product );
106
107
		}
108
	} // END get_price()
109
110
	/**
111
	 * Returns the lowest subscription scheme.
112
	 * Only works with WooCommerce Subscribe to All the Things v1.1.0+
113
	 *
114
	 * @param  WC_Product $product
115
	 * @return string
116
	 */
117
	public static function get_satt_lowest_scheme_data( $product ) {
118
		if ( class_exists( 'WCS_ATT_Schemes' ) && class_exists( 'WCS_ATT_Scheme_Prices' ) ) {
119
			$product_level_schemes = WCS_ATT_Schemes::get_product_subscription_schemes( $product );
120
121
			return WCS_ATT_Scheme_Prices::get_lowest_price_subscription_scheme_data( $product, $product_level_schemes );
122
		}
123
	} // END get_satt_lowest_scheme()
124
125
	/**
126
	 * Returns the lowest subscription scheme price string.
127
	 * Only works with WooCommerce Subscribe to All the Things v1.1.0+
128
	 *
129
	 * @param  WC_Product $product
130
	 * @return string
131
	 */
132
	public static function get_satt_lowest_price( $product ) {
133
		$scheme = self::get_satt_lowest_scheme_data( $product );
134
135
		if ( !empty( $scheme ) && is_array( $scheme ) ) {
136
			// Override price?
137
			$override = $scheme['scheme']['subscription_pricing_method'];
138
139
			// Discount?
140
			$discount = $scheme['scheme']['subscription_discount'];
141
142
			// Prices
143
			$prices = array(
144
				'price'                      => $scheme['price'],
145
				'regular_price'              => $scheme['regular_price'],
146
				'sale_price'                 => $scheme['sale_price'],
147
				'subscription_price'         => $scheme['scheme']['subscription_price'],
148
				'subscription_regular_price' => $scheme['scheme']['subscription_regular_price'],
149
				'subscription_sale_price'    => $scheme['scheme']['subscription_sale_price']
150
			);
151
152
			// Prepare the price
153
			$price = '';
154
155
			if ( 'inherit' == $override ) {
156
				$price = empty( $discount ) ? $price : ( empty( $prices[ 'regular_price' ] ) ? $prices[ 'regular_price' ] : round( ( double ) $prices[ 'regular_price' ] * ( 100 - $discount ) / 100, wc_get_price_decimals() ) );
157
			} else if ( 'override' == $override ) {
158
				$price = $prices['subscription_price'];
159
160
				if ( $prices[ 'subscription_price' ] < $prices[ 'subscription_regular_price' ] ) {
161
					$price = $prices[ 'subscription_sale_price' ];
162
				}
163
			}
164
165
			// If the price is returned as an array, return just the first.
166
			if ( is_array( $price ) ) {
167
				$price = $price[0];
168
			}
169
170
			return $price;
171
		}
172
	} // END get_price_satt()
173
174
	/**
175
	 * Displays the price of the subscription product and 
176
	 * returns only the price information you wish to return.
177
	 *
178
	 * @global $wpdb
179
	 * @global WP_Post $post
180
	 * @param  array   $atts
181
	 * @return string
182
	 */
183
	public static function get_subscription_price( $atts ) {
184
		global $wpdb, $post;
185
186
		$defaults = shortcode_atts( array(
187
			'id'           => '',
188
			'sku'          => '',
189
			'period'       => false,
190
			'length'       => false,
191
			'sign_up_fee'  => false,
192
			'trial_length' => false,
193
			'before_price' => '<span class="price subscription-price">',
194
			'after_price'  => '</span>',
195
		), $atts );
196
197
		$atts = wp_parse_args( $atts, $defaults );
198
199
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
200
			$product_data = wc_get_product( $atts['id'] );
201
		} elseif ( ! empty( $atts['sku'] ) ) {
202
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
203
			$product_data = get_post( $product_id );
204
		} else {
205
			$product_data = wc_get_product( $post->ID );
206
		}
207
208
		// Check that the product type is supported. Return blank if not supported.
209
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
210
			return '';
211
		}
212
213
		ob_start();
214
215
		$price_html = WC_Subscriptions_Product::get_price_string( $product_data->id, array(
216
			'price'               => self::get_price( $product_data ),
217
			'subscription_period' => isset( $atts['period'] ) ? $atts['period'] : true,
218
			'subscription_length' => isset( $atts['length'] ) ? $atts['length'] : true,
219
			'sign_up_fee'         => isset( $atts['sign_up_fee'] ) ? $atts['sign_up_fee'] : true,
220
			'trial_length'        => isset( $atts['trial_length'] ) ? $atts['trial_length'] : true,
221
		) );
222
223
		// Clean the subscription price wrapper.
224
		$price_html = str_replace('<span class="subscription-details">', '', $price_html);
225
		$price_html = str_replace('</span">', '', $price_html);
226
227
		// Trim the whitespace.
228
		$price_html = trim( $price_html );
229
230
		// Convert to Price Tag.
231
		$price_html = wc_price( $price_html );
232
233
		$price_html = sprintf( __( '%s%s%s', WCSS::TEXT_DOMAIN ), $atts['before_price'], $price_html, $atts['after_price'] );
234
235
		echo html_entity_decode( $price_html );
236
237
		return ob_get_clean();
238
	} // END get_subscription_price()
239
240
	/**
241
	 * Displays the price meta of the subscription product.
242
	 *
243
	 * @global $wpdb
244
	 * @global WP_Post $post
245
	 * @param  array   $atts
246
	 * @return string
247
	 */
248
	public static function get_subscription_price_meta( $atts ) {
249
		global $wpdb, $post;
250
251
		$defaults = shortcode_atts( array(
252
			'id'           => '',
253
			'sku'          => '',
254
			'meta'         => 'both',
255
			'before_price' => '',
256
			'after_price'  => '',
257
		), $atts );
258
259
		$atts = wp_parse_args( $atts, $defaults );
260
261
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
262
			$product_data = wc_get_product( $atts['id'] );
263
		} elseif ( ! empty( $atts['sku'] ) ) {
264
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
265
			$product_data = get_post( $product_id );
266
		} else {
267
			$product_data = wc_get_product( $post->ID );
268
		}
269
270
		// Check that the product type is supported. Return blank if not supported.
271
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
272
			return '';
273
		}
274
275
		ob_start();
276
277
		$price = WC_Subscriptions_Product::get_price( $product_data->id );
278
279
		// Remove the subscription price wrapper.
280
		$price_html = str_replace('<span class="subscription-details">', '', $price);
281
		$price = str_replace('</span">', '', $price_html);
282
283
		// If the subscription product has no price, then look for alternative.
284
		if ( empty( $price ) ) {
285
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
286
287
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
288
289
				$prices = array(
290
					'price'                      => $scheme['price'],
291
					'regular_price'              => $scheme['regular_price'],
292
					'sale_price'                 => $scheme['sale_price'],
293
					'method'                     => $scheme['scheme']['subscription_pricing_method'],
294
					'subscription_price'         => $scheme['scheme']['subscription_price'],
295
					'subscription_regular_price' => $scheme['scheme']['subscription_regular_price'],
296
					'subscription_sale_price'    => $scheme['scheme']['subscription_sale_price']
297
				);
298
299
				// Return the subscription price based on the pricing method.
300
				switch( $prices['method'] ) {
301
					case 'override':
302
						$price         = $prices['subscription_price'];
303
						$regular_price = $prices['subscription_regular_price'];
304
						$sale_price    = $prices['subscription_sale_price'];
305
						break;
306
					case 'inherit':
307
						$discount      = $scheme['scheme']['subscription_discount'];
308
						$price         = $prices['price'];
309
						$regular_price = $prices['regular_price'];
310
						$sale_price    = $prices['sale_price'];
311
312
						if ( !empty( $discount ) && $discount > 0 ) {
313
							$sale_price = round( ( double ) $regular_price * ( 100 - $discount ) / 100, wc_get_price_decimals() );
314
						}
315
316
						break;
317
				}
318
319
				// Display both the regular price striked out and the sale price 
320
				// should the active price be less than the regular price.
321
				if ( $atts['meta'] != 'active' && !empty( $sale_price ) && $price < $regular_price ) {
322
					$price = '<del>' . ( ( is_numeric( $regular_price ) ) ? wc_price( $regular_price ) : $regular_price ) . '</del> <ins>' . ( ( is_numeric( $sale_price ) ) ? wc_price( $sale_price ) : $sale_price ) . '</ins>';
0 ignored issues
show
Bug introduced by
The variable $regular_price does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
323
324
					// Trim the whitespace.
325
					$price = trim( $price );
326
				}
327
328
				// Override the value should only one value be returned.
329
				if ( $atts['meta'] != 'both' ) {
330
					if ( $atts['meta'] == 'active' ) {
331
						$price = $price;
0 ignored issues
show
Bug introduced by
Why assign $price to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
332
					}
333
334
					if ( $atts['meta'] == 'regular' ) {
335
						$price = $regular_price;
336
					}
337
338
					if ( $atts['meta'] == 'sale' ) {
339
						$price = $sale_price;
0 ignored issues
show
Bug introduced by
The variable $sale_price does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
340
					}
341
				}
342
343
				if ( is_numeric( $price ) ) {
344
					$price = wc_price( $price );
345
				}
346
347
			}
348
349
		}
350
351
		$price_html = sprintf( __( '%s%s%s', WCSS::TEXT_DOMAIN ), $atts['before_price'], $price, $atts['after_price'] );
352
353
		echo html_entity_decode( $price_html );
354
355
		return ob_get_clean();
356
	} // END get_subscription_price_meta()
357
358
	/**
359
	 * Displays the subscription discount of the subscription product.
360
	 * This shortcode only work with products using the mini-extension
361
	 * "WooCommerce Subscribe to All the Things".
362
	 *
363
	 * @param  array $atts
364
	 * @return string
365
	 */
366
	public static function get_subscription_discount( $atts ) {
367
		global $wpdb, $post;
368
369
		$defaults = shortcode_atts( array(
370
			'id'  => '',
371
			'sku' => '',
372
		), $atts );
373
374
		$atts = wp_parse_args( $atts, $defaults );
375
376
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
377
			$product_data = wc_get_product( $atts['id'] );
378
		} elseif ( ! empty( $atts['sku'] ) ) {
379
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
380
			$product_data = get_post( $product_id );
381
		} else {
382
			$product_data = wc_get_product( $post->ID );
383
		}
384
385
		// Check that the product type is supported. Return blank if not supported.
386
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
387
			return '';
388
		}
389
390
		ob_start();
391
392
		$discount = ''; // Returns empty by default.
393
394
		// Get Subscription Discount - Only available with the WooCommerce extension "Subscribe to All the Things".
395
		$scheme = self::get_satt_lowest_scheme_data( $product_data );
396
397 View Code Duplication
		if ( !empty( $scheme ) && is_array( $scheme ) ) {
1 ignored issue
show
Duplication introduced by
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...
398
			// Override price?
399
			$override = $scheme['scheme']['subscription_pricing_method'];
400
401
			// Discount ?
402
			$discount = $scheme['scheme']['subscription_discount'];
403
		}
404
405
		if ( ! empty( $discount ) && is_numeric( $discount ) && $override == 'inherit' ) {
0 ignored issues
show
Bug introduced by
The variable $override does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
406
			$discount = sprintf( __( '%s%s %s', WCSS::TEXT_DOMAIN ), $discount, '%', apply_filters( 'wcs_shortcodes_sub_discount_string', __( 'discount', WCSS::TEXT_DOMAIN ) ) );
407
		}
408
409
		echo $discount;
410
411
		return ob_get_clean();
412
	} // END get_subscription_discount()
413
414
	/**
415
	 * Displays the subscription period of the subscription product.
416
	 *
417
	 * @param  array $atts
418
	 * @return string
419
	 */
420
	public static function get_subscription_period( $atts ) {
421
		global $wpdb, $post;
422
423
		$defaults = shortcode_atts( array(
424
			'id'  => '',
425
			'sku' => '',
426
			'raw' => false
427
		), $atts );
428
429
		$atts = wp_parse_args( $atts, $defaults );
430
431
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
432
			$product_data = wc_get_product( $atts['id'] );
433
		} elseif ( ! empty( $atts['sku'] ) ) {
434
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
435
			$product_data = get_post( $product_id );
436
		} else {
437
			$product_data = wc_get_product( $post->ID );
438
		}
439
440
		// Check that the product type is supported. Return blank if not supported.
441
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
442
			return '';
443
		}
444
445
		ob_start();
446
447
		// Get Subscription Period
448
		$period = WC_Subscriptions_Product::get_period( $product_data );
449
450
		// If the period is empty, look for alternative.
451
		if ( empty( $period ) ) {
452
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
453
454
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
455
				$period = $scheme['scheme']['subscription_period'];
456
			}
457
		}
458
459
		if ( ! $atts['raw'] ) {
460
			$period = sprintf( __( 'Per %s', WCSS::TEXT_DOMAIN ), $period );
461
			$period = ucwords($period);
462
		}
463
464
		echo $period;
465
466
		return ob_get_clean();
467
	} // END get_subscription_period()
468
469
	/**
470
	 * Displays the subscription period interval of the subscription product.
471
	 *
472
	 * @param  array $atts
473
	 * @return string
474
	 */
475 View Code Duplication
	public static function get_subscription_period_interval( $atts ) {
476
		global $wpdb, $post;
477
478
		$defaults = shortcode_atts( array(
479
			'id'  => '',
480
			'sku' => '',
481
		), $atts );
482
483
		$atts = wp_parse_args( $atts, $defaults );
484
485
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
486
			$product_data = wc_get_product( $atts['id'] );
487
		} elseif ( ! empty( $atts['sku'] ) ) {
488
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
489
			$product_data = get_post( $product_id );
490
		} else {
491
			$product_data = wc_get_product( $post->ID );
492
		}
493
494
		// Check that the product type is supported. Return blank if not supported.
495
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
496
			return '';
497
		}
498
499
		ob_start();
500
501
		// Get Subscription Period Interval
502
		$period_interval = WC_Subscriptions_Product::get_interval( $product_data );
503
504
		// If the period is empty, look for alternative.
505
		if ( empty( $period_interval ) ) {
506
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
507
508
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
509
				$period_interval = $scheme['scheme']['subscription_period_interval'];
510
			}
511
		}
512
513
		echo $period_interval;
514
515
		return ob_get_clean();
516
	} // END get_subscription_period_interval()
517
518
	/**
519
	 * Displays the subscription length of the subscription product.
520
	 *
521
	 * @param  array $atts
522
	 * @return string
523
	 */
524
	public static function get_subscription_length( $atts ) {
525
		global $wpdb, $post;
526
527
		$defaults = shortcode_atts( array(
528
			'id'  => '',
529
			'sku' => '',
530
			'raw' => false,
531
		), $atts );
532
533
		$atts = wp_parse_args( $atts, $defaults );
534
535
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
536
			$product_data = wc_get_product( $atts['id'] );
537
		} elseif ( ! empty( $atts['sku'] ) ) {
538
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
539
			$product_data = get_post( $product_id );
540
		} else {
541
			$product_data = wc_get_product( $post->ID );
542
		}
543
544
		// Check that the product type is supported. Return blank if not supported.
545
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
546
			return '';
547
		}
548
549
		ob_start();
550
551
		// Get Subscription Length
552
		$length = WC_Subscriptions_Product::get_length( $product_data );
553
554
		// If the length is empty, look for alternative.
555
		if ( empty( $length ) ) {
556
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
557
558
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
559
560
				$period = self::get_subscription_period( array( 'id' => $product_data->id, 'raw' => true ) );
561
				$length = $scheme['scheme']['subscription_length'];
562
563
				// If we are not returning raw data then making it readable for humans.
564
				if ( ! $atts['raw'] ) {
565
566
					if ( $length > 0 ) {
567
						$length = sprintf( '%s %s', $length, $period );
568
					} else {
569
						$length = sprintf( __( 'Every %s', WCSS::TEXT_DOMAIN ), $period );
570
					}
571
572
					$length = ucfirst($length);
573
574
				}
575
576
			}
577
578
		}
579
580
		echo $length;
581
582
		return ob_get_clean();
583
	} // END get_subscription_length()
584
585
	/**
586
	 * Displays the subscription sign-up fee of the subscription product.
587
	 *
588
	 * @param  array $atts
589
	 * @return string
590
	 */
591
	public static function get_subscription_sign_up_fee( $atts ) {
592
		global $wpdb, $post;
593
594
		$defaults = shortcode_atts( array(
595
			'id'           => '',
596
			'sku'          => '',
597
			'before_price' => '',
598
			'after_price'  => '',
599
		), $atts );
600
601
		$atts = wp_parse_args( $atts, $defaults );
602
603
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
604
			$product_data = wc_get_product( $atts['id'] );
605
		} elseif ( ! empty( $atts['sku'] ) ) {
606
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
607
			$product_data = get_post( $product_id );
608
		} else {
609
			$product_data = wc_get_product( $post->ID );
610
		}
611
612
		// Check that the product type is supported. Return blank if not supported.
613
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
614
			return '';
615
		}
616
617
		ob_start();
618
619
		// Get Subscription Sign Up Fee
620
		$sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee( $product_data );
621
622
		// If the sign up fee is empty, look for alternative.
623
		if ( empty( $sign_up_fee ) ) {
624
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
625
626
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
627
				$sign_up_fee = $scheme['scheme']['subscription_sign_up_fee'];
628
			}
629
		}
630
631
		// Convert number into a price tag.
632
		if ( is_numeric( $sign_up_fee ) ) {
633
			$sign_up_fee = wc_price( $sign_up_fee );
634
		}
635
636
		$price_html = sprintf( __( '%s%s%s', WCSS::TEXT_DOMAIN ), $atts['before_price'], $sign_up_fee, $atts['after_price'] );
637
638
		echo html_entity_decode( $price_html );
639
640
		return ob_get_clean();
641
	} // END get_subscription_sign_up_fee()
642
643
	/**
644
	 * Displays the subscription trial details of the subscription product.
645
	 *
646
	 * @param  array $atts
647
	 * @return string
648
	 */
649
	public static function get_subscription_trial_string( $atts ) {
650
		global $wpdb, $post;
651
652
		$defaults = shortcode_atts( array(
653
			'id'  => '',
654
			'sku' => '',
655
		), $atts );
656
657
		$atts = wp_parse_args( $atts, $defaults );
658
659
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
660
			$product_data = wc_get_product( $atts['id'] );
661
		} elseif ( ! empty( $atts['sku'] ) ) {
662
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
663
			$product_data = get_post( $product_id );
664
		} else {
665
			$product_data = wc_get_product( $post->ID );
666
		}
667
668
		// Check that the product type is supported. Return blank if not supported.
669
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
670
			return '';
671
		}
672
673
		ob_start();
674
675
		// Get Subscription Trial Length
676
		$trial_length = self::get_subscription_trial_length( array( 'id' => $product_data->id ) );
677
678
		// Get Subscription Trial Period
679
		$trial_period = self::get_subscription_trial_period( array( 'id' => $product_data->id, 'raw' => true ) );
680
681
		if ( ! empty( $trial_length ) && $trial_length > 0 ) {
682
683
			switch ( $trial_period ) {
684
				case 'day':
685
					echo sprintf( _n( '%s day', '%s days', $trial_length, WCSS::TEXT_DOMAIN ), $trial_length );
686
					break;
687
688
				case 'week':
689
					echo sprintf( _n( '%s week', '%s weeks', $trial_length, WCSS::TEXT_DOMAIN ), $trial_length );
690
					break;
691
692
				case 'month':
693
					echo sprintf( _n( '%s month', '%s months', $trial_length, WCSS::TEXT_DOMAIN ), $trial_length );
694
					break;
695
696
				case 'year':
697
					echo sprintf( _n( '%s year', '%s years', $trial_length, WCSS::TEXT_DOMAIN ), $trial_length );
698
					break;
699
			}
700
701
		}
702
703
		return ob_get_clean();
704
	} // END get_subscription_trial_string()
705
706
	/**
707
	 * Displays the subscription trial length of the subscription product.
708
	 *
709
	 * @param  array $atts
710
	 * @return string
711
	 */
712 View Code Duplication
	public static function get_subscription_trial_length( $atts ) {
713
		global $wpdb, $post;
714
715
		$defaults = shortcode_atts( array(
716
			'id'  => '',
717
			'sku' => '',
718
		), $atts );
719
720
		$atts = wp_parse_args( $atts, $defaults );
721
722
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
723
			$product_data = wc_get_product( $atts['id'] );
724
		} elseif ( ! empty( $atts['sku'] ) ) {
725
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
726
			$product_data = get_post( $product_id );
727
		} else {
728
			$product_data = wc_get_product( $post->ID );
729
		}
730
731
		// Check that the product type is supported. Return blank if not supported.
732
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
733
			return '';
734
		}
735
736
		ob_start();
737
738
		// Get Subscription Trial Length
739
		$trial_length = WC_Subscriptions_Product::get_trial_length( $product_data );
740
741
		// If the trial length is empty, look for alternative.
742
		if ( empty( $trial_length ) ) {
743
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
744
745
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
746
				$trial_length = $scheme['scheme']['subscription_trial_length'];
747
			}
748
		}
749
750
		echo $trial_length;
751
752
		return ob_get_clean();
753
	} // END get_subscription_trial_length()
754
755
	/**
756
	 * Displays the subscription trial period of the subscription product.
757
	 *
758
	 * @param  array $atts
759
	 * @return string
760
	 */
761
	public static function get_subscription_trial_period( $atts ) {
762
		global $wpdb, $post;
763
764
		$defaults = shortcode_atts( array(
765
			'id'  => '',
766
			'sku' => '',
767
			'raw' => false,
768
		), $atts );
769
770
		$atts = wp_parse_args( $atts, $defaults );
771
772
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
773
			$product_data = wc_get_product( $atts['id'] );
774
		} elseif ( ! empty( $atts['sku'] ) ) {
775
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
776
			$product_data = get_post( $product_id );
777
		} else {
778
			$product_data = wc_get_product( $post->ID );
779
		}
780
781
		// Check that the product type is supported. Return blank if not supported.
782
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
783
			return '';
784
		}
785
786
		ob_start();
787
788
		// Get Subscription Trial Length
789
		$trial_length = self::get_subscription_trial_length( array( 'id' => $product_data->id ) );
790
791
		// Get Subscription Trial Period
792
		$trial_period = WC_Subscriptions_Product::get_trial_period( $product_data );
793
794
		// If the trial length is empty or is not zero, look for alternative.
795
		if ( empty( $trial_length ) || $trial_length != 0 ) {
796
			$scheme = self::get_satt_lowest_scheme_data( $product_data );
797
798 View Code Duplication
			if ( !empty( $scheme ) && is_array( $scheme ) ) {
1 ignored issue
show
Duplication introduced by
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...
799
				$trial_length = $scheme['scheme']['subscription_trial_length'];
800
				$trial_period = $scheme['scheme']['subscription_trial_period'];
801
			}
802
		}
803
804
		if ( ! empty( $trial_length ) && $trial_length > 0 ) {
805
806
			if ( ! $atts['raw'] ) {
807
				$trial_period = ucfirst($trial_period);
808
			}
809
810
		}
811
812
		echo $trial_period;
813
814
		return ob_get_clean();
815
	} // END get_subscription_trial_period()
816
817
	/**
818
	 * Displays the date and/or time of the first payment of the subscription.
819
	 *
820
	 * @param  array $atts
821
	 * @return string
822
	 */
823
	public static function get_subscription_first_payment( $atts ) {
824
		global $wpdb, $post;
825
826
		$defaults = shortcode_atts( array(
827
			'id'        => '',
828
			'sku'       => '',
829
			'show_time' => false,
830
			'from_date' => '',
831
			'timezone'  => 'gmt',
832
			'format'    => 'timestamp'
833
		), $atts );
834
835
		$atts = wp_parse_args( $atts, $defaults );
836
837
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
838
			$product_data = wc_get_product( $atts['id'] );
839
		} elseif ( ! empty( $atts['sku'] ) ) {
840
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
841
			$product_data = get_post( $product_id );
842
		} else {
843
			$product_data = wc_get_product( $post->ID );
844
		}
845
846
		// Check that the product type is supported. Return blank if not supported.
847
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
848
			return '';
849
		}
850
851
		ob_start();
852
853
		$billing_interval = self::get_subscription_period_interval( array( 'id' => $product_data->id ) );
854
		$billing_length   = self::get_subscription_length( array( 'id' => $product_data->id, 'raw' => true ) );
855
		$trial_length     = self::get_subscription_trial_length( array( 'id' => $product_data->id ) );
856
857
		$from_date = $atts['from_date'];
858
859
		if ( $billing_interval != $billing_length || $trial_length > 0 ) {
860
			if ( empty( $from_date ) ) {
861
				$from_date = gmdate( 'Y-m-d H:i:s' );
862
			}
863
864
			// If the subscription has a free trial period, the first renewal is the same as the expiration of the free trial
865
			if ( $trial_length > 0 ) {
866
				$first_renewal_timestamp = strtotime( WC_Subscriptions_Product::get_trial_expiration_date( $product_data->id, $from_date ) );
867
			} else {
868
				$from_timestamp = strtotime( $from_date );
869
				$billing_period = self::get_subscription_period( array( 'id' => $product_data->id, 'raw' => true ) );
870
871
				if ( 'month' == $billing_period ) {
872
					$first_renewal_timestamp = wcs_add_months( $from_timestamp, $billing_interval );
873
				} else {
874
					$first_renewal_timestamp = strtotime( "+ $billing_interval {$billing_period}s", $from_timestamp );
875
				}
876
877
				if ( 'site' == $atts['timezone'] ) {
878
					$first_renewal_timestamp += ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
879
				}
880
			}
881
		} else {
882
			$first_renewal_timestamp = 0;
883
		}
884
885
		if ( $first_renewal_timestamp > 0 ) {
886
			if ( $atts['show_time'] ) {
887 View Code Duplication
				if ( 'timestamp' == $atts['format'] ) {
1 ignored issue
show
Duplication introduced by
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...
888
					$date_format = 'Y-m-d H:i:s';
889
				} else if ( 'string' == $atts['format'] ) {
890
					$date_format = 'D jS M Y H:i A';
891
				}
892 View Code Duplication
			} else {
1 ignored issue
show
Duplication introduced by
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...
893
				if ( 'timestamp' == $atts['format'] ) {
894
					$date_format = 'Y-m-d';
895
				} else if ( 'string' == $atts['format'] ) {
896
					$date_format = 'D jS M Y';
897
				}
898
			}
899
900
			$first_payment = date( $date_format, $first_renewal_timestamp );
0 ignored issues
show
Bug introduced by
The variable $date_format does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
901
		} else {
902
			$first_payment = '';
903
		}
904
905
		echo $first_payment;
906
907
		return ob_get_clean();
908
	} // END get_subscription_first_payment()
909
910
	/**
911
	 * Displays the price of the initial payment of the subscription.
912
	 *
913
	 * @param  array $atts
914
	 * @return string
915
	 */
916
	public static function get_subscription_initial( $atts ) {
917
		global $wpdb, $post;
918
919
		$defaults = shortcode_atts( array(
920
			'id'        => '',
921
			'sku'       => '',
922
		), $atts );
923
924
		$atts = wp_parse_args( $atts, $defaults );
925
926
		if ( ! empty( $atts['id'] ) && $atts['id'] > 0 ) {
927
			$product_data = wc_get_product( $atts['id'] );
928
		} elseif ( ! empty( $atts['sku'] ) ) {
929
			$product_id   = wc_get_product_id_by_sku( $atts['sku'] );
930
			$product_data = get_post( $product_id );
931
		} else {
932
			$product_data = wc_get_product( $post->ID );
933
		}
934
935
		// Check that the product type is supported. Return blank if not supported.
936
		if ( ! is_object( $product_data ) || ! in_array( $product_data->product_type, self::get_supported_product_types() ) ) {
937
			return '';
938
		}
939
940
		ob_start();
941
942
		// Subscription Active Price
943
		$initial_payment = self::get_subscription_price_meta( array( 'id' => $product_data->id, 'meta' => 'active' ) );
944
945
		// Free Trial ?
946
		$trial_length = self::get_subscription_trial_length( array( 'id' => $product_data->id ) );
947
948
		// If there is a free trial then the initial payment is Zero.
949
		if ( $trial_length > 0 ) {
950
			$initial_payment = self::get_subscription_trial_string( array( 'id' => $product_data->id ) );
951
		}
952
953
		// Sign up fee ?
954
		$sign_up_fee = self::get_subscription_sign_up_fee( array( 'id' => $product_data->id ) );
955
956
		// Apply the sign up fee if it exists.
957
		if ( !empty( $sign_up_fee ) && $sign_up_fee > 0 ) {
958
			$initial_payment = sprintf( __( '%s with a %s', WCSS::TEXT_DOMAIN ), $initial_payment, $sign_up_fee );
959
		}
960
961
		echo $initial_payment;
962
963
		return ob_get_clean();
964
	} // END get_subscription_initial()
965
966
	/**
967
	 * Adds the product types supported from the WooCommerce extension "Subscribe to All the Things".
968
	 *
969
	 * @param  $product_types
970
	 * @return array
971
	 */
972
	public static function support_product_types_for_wc_satt( $product_types ) {
973
		// Only add the product types from the WooCommerce extension "Subscribe to All the Things" if it is active.
974
		if ( class_exists( 'WCS_ATT' ) ) {
975
			$satt_product_types = WCS_ATT()->get_supported_product_types();
976
			$product_types = array_merge( $satt_product_types, $product_types );
977
		}
978
979
		return $product_types;
980
	} // support_product_types_for_wc_satt()
981
982
} // END WCSS_Shortcodes
983
984
WCSS_Shortcodes::init();