Issues (850)

Security Analysis    4 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (1)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection (2)
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (1)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/class-wpinv-item.php (9 issues)

1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Item Class
8
 *
9
 */
10
class WPInv_Item  extends GetPaid_Data {
11
12
    /**
13
	 * Which data store to load.
14
	 *
15
	 * @var string
16
	 */
17
    protected $data_store_name = 'item';
18
19
    /**
20
	 * This is the name of this object type.
21
	 *
22
	 * @var string
23
	 */
24
	protected $object_type = 'item';
25
26
    /**
27
	 * Item Data array. This is the core item data exposed in APIs.
28
	 *
29
	 * @since 1.0.19
30
	 * @var array
31
	 */
32
	protected $data = array(
33
		'parent_id'            => 0,
34
		'status'               => 'draft',
35
		'version'              => '',
36
		'date_created'         => null,
37
        'date_modified'        => null,
38
        'name'                 => '',
39
        'description'          => '',
40
        'author'               => 1,
41
        'price'                => 0,
42
        'vat_rule'             => 'digital',
43
        'vat_class'            => '_standard',
44
        'type'                 => 'custom',
45
        'custom_id'            => null,
46
        'custom_name'          => null,
47
        'custom_singular_name' => null,
48
        'is_editable'          => 1,
49
        'is_dynamic_pricing'   => null,
50
        'minimum_price'        => null,
51
        'is_recurring'         => null,
52
        'recurring_period'     => null,
53
        'recurring_interval'   => null,
54
        'recurring_limit'      => null,
55
        'is_free_trial'        => null,
56
        'trial_period'         => null,
57
        'trial_interval'       => null,
58
    );
59
60
    /**
61
	 * Stores meta in cache for future reads.
62
	 *
63
	 * A group must be set to to enable caching.
64
	 *
65
	 * @var string
66
	 */
67
	protected $cache_group = 'getpaid_items';
68
69
    /**
70
     * Stores a reference to the original WP_Post object
71
     *
72
     * @var WP_Post
73
     */
74
    protected $post = null;
75
76
    /**
77
	 * Get the item if ID is passed, otherwise the item is new and empty.
78
	 *
79
	 * @param  int|object|WPInv_Item|WP_Post $item Item to read.
80
	 */
81
	public function __construct( $item = 0 ) {
82
		parent::__construct( $item );
83
84
		if ( ! empty( $item ) && is_numeric( $item ) && 'wpi_item' == get_post_type( $item ) ) {
85
			$this->set_id( $item );
86
		} elseif ( $item instanceof self ) {
87
			$this->set_id( $item->get_id() );
88
		} elseif ( ! empty( $item->ID ) ) {
89
			$this->set_id( $item->ID );
90
		} elseif ( is_scalar( $item ) && $item_id = self::get_item_id_by_field( $item, 'custom_id' ) ) {
91
			$this->set_id( $item_id );
92
		} elseif ( is_scalar( $item ) && $item_id = self::get_item_id_by_field( $item, 'name' ) ) {
93
			$this->set_id( $item_id );
94
		} else {
95
			$this->set_object_read( true );
96
		}
97
98
        // Load the datastore.
99
		$this->data_store = GetPaid_Data_Store::load( $this->data_store_name );
100
101
		if ( $this->get_id() > 0 ) {
102
            $this->post = get_post( $this->get_id() );
0 ignored issues
show
Documentation Bug introduced by
It seems like get_post($this->get_id()) can also be of type array. However, the property $post is declared as type WP_Post. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
103
            $this->ID   = $this->get_id();
0 ignored issues
show
Bug Best Practice introduced by
The property ID does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
104
			$this->data_store->read( $this );
105
        }
106
107
	}
108
109
    /*
110
	|--------------------------------------------------------------------------
111
	| CRUD methods
112
	|--------------------------------------------------------------------------
113
	|
114
	| Methods which create, read, update and delete items from the database.
115
	|
116
    */
117
118
    /*
119
	|--------------------------------------------------------------------------
120
	| Getters
121
	|--------------------------------------------------------------------------
122
    */
123
124
    /**
125
	 * Get parent item ID.
126
	 *
127
	 * @since 1.0.19
128
	 * @param  string $context View or edit context.
129
	 * @return int
130
	 */
131
	public function get_parent_id( $context = 'view' ) {
132
		return (int) $this->get_prop( 'parent_id', $context );
133
    }
134
135
    /**
136
	 * Get item status.
137
	 *
138
	 * @since 1.0.19
139
	 * @param  string $context View or edit context.
140
	 * @return string
141
	 */
142
	public function get_status( $context = 'view' ) {
143
		return $this->get_prop( 'status', $context );
144
    }
145
146
    /**
147
	 * Get plugin version when the item was created.
148
	 *
149
	 * @since 1.0.19
150
	 * @param  string $context View or edit context.
151
	 * @return string
152
	 */
153
	public function get_version( $context = 'view' ) {
154
		return $this->get_prop( 'version', $context );
155
    }
156
157
    /**
158
	 * Get date when the item was created.
159
	 *
160
	 * @since 1.0.19
161
	 * @param  string $context View or edit context.
162
	 * @return string
163
	 */
164
	public function get_date_created( $context = 'view' ) {
165
		return $this->get_prop( 'date_created', $context );
166
    }
167
168
    /**
169
	 * Get GMT date when the item was created.
170
	 *
171
	 * @since 1.0.19
172
	 * @param  string $context View or edit context.
173
	 * @return string
174
	 */
175
	public function get_date_created_gmt( $context = 'view' ) {
176
        $date = $this->get_date_created( $context );
177
178
        if ( $date ) {
179
            $date = get_gmt_from_date( $date );
180
        }
181
		return $date;
182
    }
183
184
    /**
185
	 * Get date when the item was last modified.
186
	 *
187
	 * @since 1.0.19
188
	 * @param  string $context View or edit context.
189
	 * @return string
190
	 */
191
	public function get_date_modified( $context = 'view' ) {
192
		return $this->get_prop( 'date_modified', $context );
193
    }
194
195
    /**
196
	 * Get GMT date when the item was last modified.
197
	 *
198
	 * @since 1.0.19
199
	 * @param  string $context View or edit context.
200
	 * @return string
201
	 */
202
	public function get_date_modified_gmt( $context = 'view' ) {
203
        $date = $this->get_date_modified( $context );
204
205
        if ( $date ) {
206
            $date = get_gmt_from_date( $date );
207
        }
208
		return $date;
209
    }
210
211
    /**
212
	 * Get the item name.
213
	 *
214
	 * @since 1.0.19
215
	 * @param  string $context View or edit context.
216
	 * @return string
217
	 */
218
	public function get_name( $context = 'view' ) {
219
		return $this->get_prop( 'name', $context );
220
    }
221
222
    /**
223
	 * Alias of self::get_name().
224
	 *
225
	 * @since 1.0.19
226
	 * @param  string $context View or edit context.
227
	 * @return string
228
	 */
229
	public function get_title( $context = 'view' ) {
230
		return $this->get_name( $context );
231
    }
232
233
    /**
234
	 * Get the item description.
235
	 *
236
	 * @since 1.0.19
237
	 * @param  string $context View or edit context.
238
	 * @return string
239
	 */
240
	public function get_description( $context = 'view' ) {
241
		return $this->get_prop( 'description', $context );
242
    }
243
244
    /**
245
	 * Alias of self::get_description().
246
	 *
247
	 * @since 1.0.19
248
	 * @param  string $context View or edit context.
249
	 * @return string
250
	 */
251
	public function get_excerpt( $context = 'view' ) {
252
		return $this->get_description( $context );
253
    }
254
255
    /**
256
	 * Alias of self::get_description().
257
	 *
258
	 * @since 1.0.19
259
	 * @param  string $context View or edit context.
260
	 * @return string
261
	 */
262
	public function get_summary( $context = 'view' ) {
263
		return $this->get_description( $context );
264
    }
265
266
    /**
267
	 * Get the owner of the item.
268
	 *
269
	 * @since 1.0.19
270
	 * @param  string $context View or edit context.
271
	 * @return int
272
	 */
273
	public function get_author( $context = 'view' ) {
274
		return (int) $this->get_prop( 'author', $context );
275
	}
276
277
	/**
278
	 * Alias of self::get_author().
279
	 *
280
	 * @since 1.0.19
281
	 * @param  string $context View or edit context.
282
	 * @return int
283
	 */
284
	public function get_owner( $context = 'view' ) {
285
		return $this->get_author( $context );
286
    }
287
288
    /**
289
	 * Get the price of the item.
290
	 *
291
	 * @since 1.0.19
292
	 * @param  string $context View or edit context.
293
	 * @return float
294
	 */
295
	public function get_price( $context = 'view' ) {
296
        return wpinv_sanitize_amount( $this->get_prop( 'price', $context ) );
297
	}
298
299
	/**
300
	 * Get the inital price of the item.
301
	 *
302
	 * @since 1.0.19
303
	 * @param  string $context View or edit context.
304
	 * @return float
305
	 */
306
	public function get_initial_price( $context = 'view' ) {
307
308
		$price = (float) $this->get_price( $context );
309
310
		if ( $this->has_free_trial() ) {
311
			$price = 0;
312
		}
313
314
        return wpinv_sanitize_amount( apply_filters( 'wpinv_get_initial_item_price', $price, $this ) );
315
    }
316
317
    /**
318
	 * Returns a formated price.
319
	 *
320
	 * @since 1.0.19
321
	 * @param  string $context View or edit context.
322
	 * @return string
323
	 */
324
    public function get_the_price() {
325
        return wpinv_price( $this->get_price() );
326
	}
327
328
	/**
329
	 * Returns the formated initial price.
330
	 *
331
	 * @since 1.0.19
332
	 * @param  string $context View or edit context.
333
	 * @return string
334
	 */
335
    public function get_the_initial_price() {
336
        return wpinv_price( $this->get_initial_price() );
337
    }
338
339
    /**
340
	 * Get the VAT rule of the item.
341
	 *
342
	 * @since 1.0.19
343
	 * @param  string $context View or edit context.
344
	 * @return string
345
	 */
346
	public function get_vat_rule( $context = 'view' ) {
347
        return $this->get_prop( 'vat_rule', $context );
348
    }
349
350
    /**
351
	 * Get the VAT class of the item.
352
	 *
353
	 * @since 1.0.19
354
	 * @param  string $context View or edit context.
355
	 * @return string
356
	 */
357
	public function get_vat_class( $context = 'view' ) {
358
        return $this->get_prop( 'vat_class', $context );
359
    }
360
361
    /**
362
	 * Get the type of the item.
363
	 *
364
	 * @since 1.0.19
365
	 * @param  string $context View or edit context.
366
	 * @return string
367
	 */
368
	public function get_type( $context = 'view' ) {
369
        return $this->get_prop( 'type', $context );
370
    }
371
372
    /**
373
	 * Get the custom id of the item.
374
	 *
375
	 * @since 1.0.19
376
	 * @param  string $context View or edit context.
377
	 * @return string
378
	 */
379
	public function get_custom_id( $context = 'view' ) {
380
        return $this->get_prop( 'custom_id', $context );
381
    }
382
383
    /**
384
	 * Get the custom name of the item.
385
	 *
386
	 * @since 1.0.19
387
	 * @param  string $context View or edit context.
388
	 * @return string
389
	 */
390
	public function get_custom_name( $context = 'view' ) {
391
        return $this->get_prop( 'custom_name', $context );
392
    }
393
394
    /**
395
	 * Get the custom singular name of the item.
396
	 *
397
	 * @since 1.0.19
398
	 * @param  string $context View or edit context.
399
	 * @return string
400
	 */
401
	public function get_custom_singular_name( $context = 'view' ) {
402
        return $this->get_prop( 'custom_singular_name', $context );
403
    }
404
405
    /**
406
	 * Checks if an item is editable..
407
	 *
408
	 * @since 1.0.19
409
	 * @param  string $context View or edit context.
410
	 * @return int
411
	 */
412
	public function get_is_editable( $context = 'view' ) {
413
        return (int) $this->get_prop( 'is_editable', $context );
414
    }
415
416
    /**
417
	 * Alias of self::get_is_editable().
418
	 *
419
	 * @since 1.0.19
420
	 * @param  string $context View or edit context.
421
	 * @return int
422
	 */
423
	public function get_editable( $context = 'view' ) {
424
		return $this->get_is_editable( $context );
425
    }
426
427
    /**
428
	 * Checks if dynamic pricing is enabled.
429
	 *
430
	 * @since 1.0.19
431
	 * @param  string $context View or edit context.
432
	 * @return int
433
	 */
434
	public function get_is_dynamic_pricing( $context = 'view' ) {
435
        return (int) $this->get_prop( 'is_dynamic_pricing', $context );
436
    }
437
438
    /**
439
	 * Returns the minimum price if dynamic pricing is enabled.
440
	 *
441
	 * @since 1.0.19
442
	 * @param  string $context View or edit context.
443
	 * @return float
444
	 */
445
	public function get_minimum_price( $context = 'view' ) {
446
        return wpinv_sanitize_amount( $this->get_prop( 'minimum_price', $context ) );
447
    }
448
449
    /**
450
	 * Checks if this is a recurring item.
451
	 *
452
	 * @since 1.0.19
453
	 * @param  string $context View or edit context.
454
	 * @return int
455
	 */
456
	public function get_is_recurring( $context = 'view' ) {
457
        return (int) $this->get_prop( 'is_recurring', $context );
458
	}
459
460
	/**
461
	 * Get the recurring price of the item.
462
	 *
463
	 * @since 1.0.19
464
	 * @param  string $context View or edit context.
465
	 * @return float
466
	 */
467
	public function get_recurring_price( $context = 'view' ) {
468
		$price = $this->get_price( $context );
469
        return wpinv_sanitize_amount( apply_filters( 'wpinv_get_recurring_item_price', $price, $this->ID ) );
470
	}
471
472
	/**
473
	 * Get the formatted recurring price of the item.
474
	 *
475
	 * @since 1.0.19
476
	 * @param  string $context View or edit context.
477
	 * @return string
478
	 */
479
    public function get_the_recurring_price() {
480
        return wpinv_price( $this->get_recurring_price() );
481
	}
482
483
	/**
484
	 * Get the first renewal date (in timestamps) of the item.
485
	 *
486
	 * @since 1.0.19
487
	 * @return int
488
	 */
489
	public function get_first_renewal_date() {
490
491
		$periods = array(
492
			'D' => 'days',
493
			'W' => 'weeks',
494
			'M' => 'months',
495
			'Y' => 'years',
496
		);
497
498
		$period   = $this->get_recurring_period();
499
		$interval = $this->get_recurring_interval();
500
501
		if ( $this->has_free_trial() ) {
502
			$period   = $this->get_trial_period();
503
			$interval = $this->get_trial_interval();
504
		}
505
506
		$period       = $periods[ $period ];
507
		$interval     = empty( $interval ) ? 1 : $interval;
508
		$next_renewal = strtotime( "+$interval $period", current_time( 'timestamp' ) );
509
        return apply_filters( 'wpinv_get_first_renewal_date', $next_renewal, $this );
510
    }
511
512
    /**
513
	 * Get the recurring period.
514
	 *
515
	 * @since 1.0.19
516
	 * @param  bool $full Return abbreviation or in full.
517
	 * @return string
518
	 */
519
	public function get_recurring_period( $full = false ) {
520
        $period = $this->get_prop( 'recurring_period', 'view' );
521
522
        if ( $full && ! is_bool( $full ) ) {
0 ignored issues
show
The condition is_bool($full) is always true.
Loading history...
523
            $full = false;
524
        }
525
526
        return getpaid_sanitize_recurring_period( $period, $full );
527
    }
528
529
    /**
530
	 * Get the recurring interval.
531
	 *
532
	 * @since 1.0.19
533
	 * @param  string $context View or edit context.
534
	 * @return int
535
	 */
536
	public function get_recurring_interval( $context = 'view' ) {
537
		$interval = absint( $this->get_prop( 'recurring_interval', $context ) );
538
		return max( 1, $interval );
539
    }
540
541
    /**
542
	 * Get the recurring limit.
543
	 *
544
	 * @since 1.0.19
545
	 * @param  string $context View or edit context.
546
	 * @return int
547
	 */
548
	public function get_recurring_limit( $context = 'view' ) {
549
        return (int) $this->get_prop( 'recurring_limit', $context );
550
    }
551
552
    /**
553
	 * Checks if we have a free trial.
554
	 *
555
	 * @since 1.0.19
556
	 * @param  string $context View or edit context.
557
	 * @return int
558
	 */
559
	public function get_is_free_trial( $context = 'view' ) {
560
        return (int) $this->get_prop( 'is_free_trial', $context );
561
    }
562
563
    /**
564
	 * Alias for self::get_is_free_trial().
565
	 *
566
	 * @since 1.0.19
567
	 * @param  string $context View or edit context.
568
	 * @return int
569
	 */
570
	public function get_free_trial( $context = 'view' ) {
571
        return $this->get_is_free_trial( $context );
572
    }
573
574
    /**
575
	 * Get the trial period.
576
	 *
577
	 * @since 1.0.19
578
	 * @param  bool $full Return abbreviation or in full.
579
	 * @return string
580
	 */
581
	public function get_trial_period( $full = false ) {
582
        $period = $this->get_prop( 'trial_period', 'view' );
583
584
        if ( $full && ! is_bool( $full ) ) {
0 ignored issues
show
The condition is_bool($full) is always true.
Loading history...
585
            $full = false;
586
        }
587
588
        return getpaid_sanitize_recurring_period( $period, $full );
589
    }
590
591
    /**
592
	 * Get the trial interval.
593
	 *
594
	 * @since 1.0.19
595
	 * @param  string $context View or edit context.
596
	 * @return int
597
	 */
598
	public function get_trial_interval( $context = 'view' ) {
599
        return (int) $this->get_prop( 'trial_interval', $context );
600
	}
601
602
	/**
603
	 * Get the item's edit url.
604
	 *
605
	 * @since 1.0.19
606
	 * @return string
607
	 */
608
	public function get_edit_url() {
609
        return get_edit_post_link( $this->get_id(), 'edit' );
610
	}
611
612
	/**
613
	 * Given an item's name/custom id, it returns its id.
614
	 *
615
	 *
616
	 * @static
617
	 * @param string $value The item name or custom id.
618
	 * @param string $field Either name or custom_id.
619
	 * @param string $type in case you need to search for a given type.
620
	 * @since 1.0.15
621
	 * @return int
622
	 */
623
	public static function get_item_id_by_field( $value, $field = 'custom_id', $type = '' ) {
624
625
		// Trim the value.
626
		$value = sanitize_text_field( $value );
627
		if ( empty( $value ) ) {
628
			return 0;
629
		}
630
631
        // Valid fields.
632
        $fields = array( 'custom_id', 'name', 'slug' );
633
634
		// Ensure a field has been passed.
635
		if ( empty( $field ) || ! in_array( $field, $fields ) ) {
636
			return 0;
637
		}
638
639
		if ( $field == 'name' ) {
640
			$field = 'slug';
641
		}
642
643
		// Maybe retrieve from the cache.
644
		$item_id = wp_cache_get( $value, "getpaid_{$type}_item_{$field}s_to_item_ids" );
645
		if ( ! empty( $item_id ) ) {
646
			return $item_id;
647
		}
648
649
		// Fetch from the db.
650
		$items = array();
651
		if ( $field == 'slug' ) {
652
			$items = get_posts(
653
				array(
654
					'post_type'      => 'wpi_item',
655
					'name'           => $value,
656
					'posts_per_page' => 1,
657
					'post_status'    => 'any',
658
				)
659
			);
660
		}
661
662
		if ( $field == 'custom_id' ) {
663
			$items = get_posts(
664
				array(
665
					'post_type'      => 'wpi_item',
666
					'posts_per_page' => 1,
667
					'post_status'    => 'any',
668
					'meta_query'     => array(
669
						array(
670
							'key'   => '_wpinv_type',
671
                			'value' => $type,
672
						),
673
						array(
674
							'key'   => '_wpinv_custom_id',
675
                			'value' => $value,
676
						),
677
					),
678
				)
679
			);
680
		}
681
682
		if ( empty( $items ) ) {
683
			return 0;
684
		}
685
686
		// Update the cache with our data
687
		wp_cache_set( $value, $items[0]->ID, "getpaid_{$type}_item_{$field}s_to_item_ids" );
688
689
		return $items[0]->ID;
690
    }
691
692
    /**
693
     * Margic method for retrieving a property.
694
     */
695
    public function __get( $key ) {
696
697
        // Check if we have a helper method for that.
698
        if ( method_exists( $this, 'get_' . $key ) ) {
699
            return call_user_func( array( $this, 'get_' . $key ) );
700
        }
701
702
        // Check if the key is in the associated $post object.
703
        if ( ! empty( $this->post ) && isset( $this->post->$key ) ) {
704
            return $this->post->$key;
705
        }
706
707
        return $this->get_prop( $key );
708
709
    }
710
711
    /*
712
	|--------------------------------------------------------------------------
713
	| Setters
714
	|--------------------------------------------------------------------------
715
	|
716
	| Functions for setting item data. These should not update anything in the
717
	| database itself and should only change what is stored in the class
718
	| object.
719
    */
720
721
    /**
722
	 * Set parent order ID.
723
	 *
724
	 * @since 1.0.19
725
	 */
726
	public function set_parent_id( $value ) {
727
		if ( $value && ( $value === $this->get_id() || ! get_post( $value ) ) ) {
728
			return;
729
		}
730
		$this->set_prop( 'parent_id', absint( $value ) );
731
	}
732
733
    /**
734
	 * Sets item status.
735
	 *
736
	 * @since 1.0.19
737
	 * @param  string $status New status.
738
	 * @return array details of change.
739
	 */
740
	public function set_status( $status ) {
741
        $old_status = $this->get_status();
742
743
        $this->set_prop( 'status', $status );
744
745
		return array(
746
			'from' => $old_status,
747
			'to'   => $status,
748
		);
749
    }
750
751
    /**
752
	 * Set plugin version when the item was created.
753
	 *
754
	 * @since 1.0.19
755
	 */
756
	public function set_version( $value ) {
757
		$this->set_prop( 'version', $value );
758
    }
759
760
    /**
761
	 * Set date when the item was created.
762
	 *
763
	 * @since 1.0.19
764
	 * @param string $value Value to set.
765
     * @return bool Whether or not the date was set.
766
	 */
767
	public function set_date_created( $value ) {
768
        $date = strtotime( $value );
769
770
        if ( $date ) {
771
            $this->set_prop( 'date_created', date( 'Y-m-d H:i:s', $date ) );
772
            return true;
773
        }
774
775
        return false;
776
777
    }
778
779
    /**
780
	 * Set date when the item was last modified.
781
	 *
782
	 * @since 1.0.19
783
	 * @param string $value Value to set.
784
     * @return bool Whether or not the date was set.
785
	 */
786
	public function set_date_modified( $value ) {
787
        $date = strtotime( $value );
788
789
        if ( $date ) {
790
            $this->set_prop( 'date_modified', date( 'Y-m-d H:i:s', $date ) );
791
            return true;
792
        }
793
794
        return false;
795
796
    }
797
798
    /**
799
	 * Set the item name.
800
	 *
801
	 * @since 1.0.19
802
	 * @param  string $value New name.
803
	 */
804
	public function set_name( $value ) {
805
        $name = sanitize_text_field( $value );
806
		$this->set_prop( 'name', $name );
807
    }
808
809
    /**
810
	 * Alias of self::set_name().
811
	 *
812
	 * @since 1.0.19
813
	 * @param  string $value New name.
814
	 */
815
	public function set_title( $value ) {
816
		$this->set_name( $value );
817
    }
818
819
    /**
820
	 * Set the item description.
821
	 *
822
	 * @since 1.0.19
823
	 * @param  string $value New description.
824
	 */
825
	public function set_description( $value ) {
826
		$description = wp_kses_post( wp_unslash( $value ) );
0 ignored issues
show
It seems like wp_unslash($value) can also be of type array; however, parameter $data of wp_kses_post() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

826
		$description = wp_kses_post( /** @scrutinizer ignore-type */ wp_unslash( $value ) );
Loading history...
827
		return $this->set_prop( 'description', $description );
0 ignored issues
show
Are you sure the usage of $this->set_prop('description', $description) targeting GetPaid_Data::set_prop() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
828
    }
829
830
    /**
831
	 * Alias of self::set_description().
832
	 *
833
	 * @since 1.0.19
834
	 * @param  string $value New description.
835
	 */
836
	public function set_excerpt( $value ) {
837
		$this->set_description( $value );
838
    }
839
840
    /**
841
	 * Alias of self::set_description().
842
	 *
843
	 * @since 1.0.19
844
	 * @param  string $value New description.
845
	 */
846
	public function set_summary( $value ) {
847
		$this->set_description( $value );
848
    }
849
850
    /**
851
	 * Set the owner of the item.
852
	 *
853
	 * @since 1.0.19
854
	 * @param  int $value New author.
855
	 */
856
	public function set_author( $value ) {
857
		$this->set_prop( 'author', (int) $value );
858
	}
859
860
	/**
861
	 * Alias of self::set_author().
862
	 *
863
	 * @since 1.0.19
864
	 * @param  int $value New author.
865
	 */
866
	public function set_owner( $value ) {
867
		$this->set_author( $value );
868
    }
869
870
    /**
871
	 * Set the price of the item.
872
	 *
873
	 * @since 1.0.19
874
	 * @param  float $value New price.
875
	 */
876
	public function set_price( $value ) {
877
        $this->set_prop( 'price', (float) wpinv_sanitize_amount( $value ) );
878
    }
879
880
    /**
881
	 * Set the VAT rule of the item.
882
	 *
883
	 * @since 1.0.19
884
	 * @param  string $value new rule.
885
	 */
886
	public function set_vat_rule( $value ) {
887
        $this->set_prop( 'vat_rule', $value );
888
    }
889
890
    /**
891
	 * Set the VAT class of the item.
892
	 *
893
	 * @since 1.0.19
894
	 * @param  string $value new class.
895
	 */
896
	public function set_vat_class( $value ) {
897
        $this->set_prop( 'vat_class', $value );
898
    }
899
900
    /**
901
	 * Set the type of the item.
902
	 *
903
	 * @since 1.0.19
904
	 * @param  string $value new item type.
905
	 * @return string
906
	 */
907
	public function set_type( $value ) {
908
909
        if ( empty( $value ) ) {
910
            $value = 'custom';
911
        }
912
913
        $this->set_prop( 'type', $value );
914
    }
915
916
    /**
917
	 * Set the custom id of the item.
918
	 *
919
	 * @since 1.0.19
920
	 * @param  string $value new custom id.
921
	 */
922
	public function set_custom_id( $value ) {
923
        $this->set_prop( 'custom_id', $value );
924
    }
925
926
    /**
927
	 * Set the custom name of the item.
928
	 *
929
	 * @since 1.0.19
930
	 * @param  string $value new custom name.
931
	 */
932
	public function set_custom_name( $value ) {
933
        $this->set_prop( 'custom_name', $value );
934
    }
935
936
    /**
937
	 * Set the custom singular name of the item.
938
	 *
939
	 * @since 1.0.19
940
	 * @param  string $value new custom singular name.
941
	 */
942
	public function set_custom_singular_name( $value ) {
943
        $this->set_prop( 'custom_singular_name', $value );
944
    }
945
946
    /**
947
	 * Sets if an item is editable..
948
	 *
949
	 * @since 1.0.19
950
	 * @param  int|bool $value whether or not the item is editable.
951
	 */
952
	public function set_is_editable( $value ) {
953
		$this->set_prop( 'is_editable', (int) $value );
954
    }
955
956
    /**
957
	 * Sets if dynamic pricing is enabled.
958
	 *
959
	 * @since 1.0.19
960
	 * @param  int|bool $value whether or not dynamic pricing is allowed.
961
	 */
962
	public function set_is_dynamic_pricing( $value ) {
963
        $this->set_prop( 'is_dynamic_pricing', (int) $value );
964
    }
965
966
    /**
967
	 * Sets the minimum price if dynamic pricing is enabled.
968
	 *
969
	 * @since 1.0.19
970
	 * @param  float $value minimum price.
971
	 */
972
	public function set_minimum_price( $value ) {
973
        $this->set_prop( 'minimum_price', (float) wpinv_sanitize_amount( $value ) );
974
    }
975
976
    /**
977
	 * Sets if this is a recurring item.
978
	 *
979
	 * @since 1.0.19
980
	 * @param  int|bool $value whether or not dynamic pricing is allowed.
981
	 */
982
	public function set_is_recurring( $value ) {
983
        $this->set_prop( 'is_recurring', (int) $value );
984
    }
985
986
    /**
987
	 * Set the recurring period.
988
	 *
989
	 * @since 1.0.19
990
	 * @param  string $value new period.
991
	 */
992
	public function set_recurring_period( $value ) {
993
        $this->set_prop( 'recurring_period', $value );
994
    }
995
996
    /**
997
	 * Set the recurring interval.
998
	 *
999
	 * @since 1.0.19
1000
	 * @param  int $value recurring interval.
1001
	 */
1002
	public function set_recurring_interval( $value ) {
1003
        return $this->set_prop( 'recurring_interval', (int) $value );
0 ignored issues
show
Are you sure the usage of $this->set_prop('recurri...interval', (int)$value) targeting GetPaid_Data::set_prop() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1004
    }
1005
1006
    /**
1007
	 * Get the recurring limit.
1008
	 * @since 1.0.19
1009
	 * @param  int $value The recurring limit.
1010
	 * @return int
1011
	 */
1012
	public function set_recurring_limit( $value ) {
1013
        $this->set_prop( 'recurring_limit', (int) $value );
1014
    }
1015
1016
    /**
1017
	 * Checks if we have a free trial.
1018
	 *
1019
	 * @since 1.0.19
1020
	 * @param  int|bool $value whether or not it has a free trial.
1021
	 */
1022
	public function set_is_free_trial( $value ) {
1023
        $this->set_prop( 'is_free_trial', (int) $value );
1024
    }
1025
1026
    /**
1027
	 * Set the trial period.
1028
	 *
1029
	 * @since 1.0.19
1030
	 * @param  string $value trial period.
1031
	 */
1032
	public function set_trial_period( $value ) {
1033
        $this->set_prop( 'trial_period', $value );
1034
    }
1035
1036
    /**
1037
	 * Set the trial interval.
1038
	 *
1039
	 * @since 1.0.19
1040
	 * @param  int $value trial interval.
1041
	 */
1042
	public function set_trial_interval( $value ) {
1043
        $this->set_prop( 'trial_interval', $value );
1044
    }
1045
1046
    /**
1047
     * Create an item. For backwards compatibilty.
1048
     *
1049
     * @deprecated
1050
	 * @return int item id
1051
     */
1052
    public function create( $data = array() ) {
1053
1054
		// Set the properties.
1055
		if ( is_array( $data ) ) {
1056
			$this->set_props( $data );
1057
		}
1058
1059
		// Save the item.
1060
		return $this->save();
1061
1062
    }
1063
1064
    /**
1065
     * Updates an item. For backwards compatibilty.
1066
     *
1067
     * @deprecated
1068
	 * @return int item id
1069
     */
1070
    public function update( $data = array() ) {
1071
        return $this->create( $data );
0 ignored issues
show
Deprecated Code introduced by
The function WPInv_Item::create() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1071
        return /** @scrutinizer ignore-deprecated */ $this->create( $data );
Loading history...
1072
    }
1073
1074
    /*
1075
	|--------------------------------------------------------------------------
1076
	| Conditionals
1077
	|--------------------------------------------------------------------------
1078
	|
1079
	| Checks if a condition is true or false.
1080
	|
1081
	*/
1082
1083
    /**
1084
	 * Checks whether the item has enabled dynamic pricing.
1085
	 *
1086
	 * @since 1.0.19
1087
	 * @return bool
1088
	 */
1089
	public function user_can_set_their_price() {
1090
        return (bool) $this->get_is_dynamic_pricing();
1091
	}
1092
1093
	/**
1094
	 * Checks whether the item is recurring.
1095
	 *
1096
	 * @since 1.0.19
1097
	 * @return bool
1098
	 */
1099
	public function is_recurring() {
1100
        return (bool) $this->get_is_recurring();
1101
    }
1102
1103
    /**
1104
	 * Checks whether the item has a free trial.
1105
	 *
1106
	 * @since 1.0.19
1107
	 * @return bool
1108
	 */
1109
    public function has_free_trial() {
1110
        $has_trial = $this->is_recurring() && (bool) $this->get_free_trial() ? true : false;
1111
        return (bool) apply_filters( 'wpinv_item_has_free_trial', $has_trial, $this->ID, $this );
1112
    }
1113
1114
    /**
1115
	 * Checks whether the item is free.
1116
	 *
1117
	 * @since 1.0.19
1118
	 * @return bool
1119
	 */
1120
    public function is_free() {
1121
        $is_free   = $this->get_price() == 0;
1122
        return (bool) apply_filters( 'wpinv_is_free_item', $is_free, $this->ID, $this );
1123
    }
1124
1125
    /**
1126
	 * Checks the item status against a passed in status.
1127
	 *
1128
	 * @param array|string $status Status to check.
1129
	 * @return bool
1130
	 */
1131
	public function has_status( $status ) {
1132
		$has_status = ( is_array( $status ) && in_array( $this->get_status(), $status, true ) ) || $this->get_status() === $status;
1133
		return (bool) apply_filters( 'getpaid_item_has_status', $has_status, $this, $status );
1134
    }
1135
1136
    /**
1137
	 * Checks the item type against a passed in types.
1138
	 *
1139
	 * @param array|string $type Type to check.
1140
	 * @return bool
1141
	 */
1142
	public function is_type( $type ) {
1143
		$is_type = ( is_array( $type ) && in_array( $this->get_type(), $type, true ) ) || $this->get_type() === $type;
1144
		return (bool) apply_filters( 'getpaid_item_is_type', $is_type, $this, $type );
1145
	}
1146
1147
    /**
1148
	 * Checks whether the item is editable.
1149
	 *
1150
	 * @since 1.0.19
1151
	 * @return bool
1152
	 */
1153
    public function is_editable() {
1154
        $is_editable = $this->get_is_editable();
1155
        return (bool) apply_filters( 'wpinv_item_is_editable', $is_editable, $this->ID, $this );
1156
	}
1157
1158
	/**
1159
	 * Returns an array of cart fees.
1160
	 */
1161
	public function get_fees() {
1162
        return array();
1163
    }
1164
1165
    /**
1166
	 * Checks whether the item is purchasable.
1167
	 *
1168
	 * @since 1.0.19
1169
	 * @return bool
1170
	 */
1171
    public function can_purchase() {
1172
        $can_purchase = $this->exists();
1173
1174
        if ( ! current_user_can( 'edit_post', $this->ID ) && $this->post_status != 'publish' ) {
0 ignored issues
show
Bug Best Practice introduced by
The property post_status does not exist on WPInv_Item. Since you implemented __get, consider adding a @property annotation.
Loading history...
1175
            $can_purchase = false;
1176
        }
1177
1178
        return (bool) apply_filters( 'wpinv_can_purchase_item', $can_purchase, $this );
1179
    }
1180
1181
    /**
1182
	 * Checks whether the item supports dynamic pricing.
1183
	 *
1184
	 * @since 1.0.19
1185
	 * @return bool
1186
	 */
1187
    public function supports_dynamic_pricing() {
1188
        return (bool) apply_filters( 'wpinv_item_supports_dynamic_pricing', true, $this );
1189
    }
1190
}
1191