Passed
Push — master ( 6086f2...9dee83 )
by Kiran
09:50 queued 20s
created
templates/invoice/line-items.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -33,12 +33,12 @@
 block discarded – undo
33 33
 
34 34
             // Display the item totals.
35 35
             foreach ( $invoice->get_items() as $item ) {
36
-			wpinv_get_template( 'invoice/line-item.php', compact( 'invoice', 'item', 'columns' ) );
36
+            wpinv_get_template( 'invoice/line-item.php', compact( 'invoice', 'item', 'columns' ) );
37 37
             }
38 38
 
39 39
             // Display the fee totals.
40 40
             foreach ( $invoice->get_fees() as $fee ) {
41
-			wpinv_get_template( 'invoice/fee-item.php', compact( 'invoice', 'fee', 'columns' ) );
41
+            wpinv_get_template( 'invoice/fee-item.php', compact( 'invoice', 'fee', 'columns' ) );
42 42
             }
43 43
 
44 44
             // Display the cart totals.
Please login to merge, or discard this patch.
templates/wpinv-invalid-access.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -40,19 +40,19 @@
 block discarded – undo
40 40
         <?php
41 41
 
42 42
             if ( ! $invoice->exists() || $invoice->is_draft() ) {
43
-			$error = __( 'This invoice was deleted or is not visible.', 'invoicing' );
43
+            $error = __( 'This invoice was deleted or is not visible.', 'invoicing' );
44 44
             } else {
45 45
 
46
-			$user_id = get_current_user_id();
47
-			if ( wpinv_require_login_to_checkout() && empty( $user_id ) ) {
48
-				$error  = __( 'You must be logged in to view this invoice.', 'invoicing' );
49
-				$error .= sprintf(
50
-					' <a href="%s">%s</a>',
51
-					wp_login_url( $invoice->get_view_url() ),
52
-					__( 'Login.', 'invoicing' )
53
-				);
54
-			} else {
55
-				$error = __( 'This invoice is only viewable by clicking on the invoice link that was sent to you via email.', 'invoicing' );
46
+            $user_id = get_current_user_id();
47
+            if ( wpinv_require_login_to_checkout() && empty( $user_id ) ) {
48
+                $error  = __( 'You must be logged in to view this invoice.', 'invoicing' );
49
+                $error .= sprintf(
50
+                    ' <a href="%s">%s</a>',
51
+                    wp_login_url( $invoice->get_view_url() ),
52
+                    __( 'Login.', 'invoicing' )
53
+                );
54
+            } else {
55
+                $error = __( 'This invoice is only viewable by clicking on the invoice link that was sent to you via email.', 'invoicing' );
56 56
                 }
57 57
 }
58 58
 
Please login to merge, or discard this patch.
templates/payment-forms/cart.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -44,7 +44,7 @@
 block discarded – undo
44 44
 
45 45
             // Display the item totals.
46 46
             foreach ( $form->get_items() as $item ) {
47
-			wpinv_get_template( 'payment-forms/cart-item.php', compact( 'form', 'item', 'columns' ) );
47
+            wpinv_get_template( 'payment-forms/cart-item.php', compact( 'form', 'item', 'columns' ) );
48 48
             }
49 49
 
50 50
             // Display the cart totals.
Please login to merge, or discard this patch.
templates/emails/invoice-items.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -44,12 +44,12 @@
 block discarded – undo
44 44
 
45 45
                 // Display the item totals.
46 46
                 foreach ( $invoice->get_items() as $item ) {
47
-				wpinv_get_template( 'emails/invoice-item.php', compact( 'invoice', 'item', 'columns' ) );
47
+                wpinv_get_template( 'emails/invoice-item.php', compact( 'invoice', 'item', 'columns' ) );
48 48
                 }
49 49
 
50 50
                 // Display the fee totals.
51 51
                 foreach ( $invoice->get_fees() as $fee ) {
52
-				wpinv_get_template( 'emails/fee-item.php', compact( 'invoice', 'fee', 'columns' ) );
52
+                wpinv_get_template( 'emails/fee-item.php', compact( 'invoice', 'fee', 'columns' ) );
53 53
                 }
54 54
 
55 55
             ?>
Please login to merge, or discard this patch.
templates/emails/wpinv-email-billing-details.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -20,7 +20,7 @@
 block discarded – undo
20 20
 <a href="<?php echo esc_url( add_query_arg( 'user_id', $invoice->get_user_id(), self_admin_url( 'user-edit.php' ) ) ); ?>"><?php echo esc_html( $invoice->get_user_full_name() ); ?></a>
21 21
                     <?php
22 22
 } else {
23
-					echo esc_html( $invoice->get_user_full_name() ); }
23
+                    echo esc_html( $invoice->get_user_full_name() ); }
24 24
 ?>
25 25
 </td>
26 26
             </tr>
Please login to merge, or discard this patch.
includes/data-stores/class-getpaid-payment-form-data-store.php 1 patch
Indentation   +169 added lines, -169 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
  *
5 5
  */
6 6
 if ( ! defined( 'ABSPATH' ) ) {
7
-	exit;
7
+    exit;
8 8
 }
9 9
 
10 10
 /**
@@ -14,179 +14,179 @@  discard block
 block discarded – undo
14 14
  */
15 15
 class GetPaid_Payment_Form_Data_Store extends GetPaid_Data_Store_WP {
16 16
 
17
-	/**
18
-	 * Data stored in meta keys, but not considered "meta" for a form.
19
-	 *
20
-	 * @since 1.0.19
21
-	 * @var array
22
-	 */
23
-	protected $internal_meta_keys = array(
24
-		'wpinv_form_elements',
25
-		'wpinv_form_items',
26
-		'wpinv_form_earned',
27
-		'wpinv_form_refunded',
28
-		'wpinv_form_cancelled',
29
-		'wpinv_form_failed',
30
-	);
31
-
32
-	/**
33
-	 * A map of meta keys to data props.
34
-	 *
35
-	 * @since 1.0.19
36
-	 *
37
-	 * @var array
38
-	 */
39
-	protected $meta_key_to_props = array(
40
-		'wpinv_form_elements'  => 'elements',
41
-		'wpinv_form_items'     => 'items',
42
-		'wpinv_form_earned'    => 'earned',
43
-		'wpinv_form_refunded'  => 'refunded',
44
-		'wpinv_form_cancelled' => 'cancelled',
45
-		'wpinv_form_failed'    => 'failed',
46
-	);
47
-
48
-	/*
17
+    /**
18
+     * Data stored in meta keys, but not considered "meta" for a form.
19
+     *
20
+     * @since 1.0.19
21
+     * @var array
22
+     */
23
+    protected $internal_meta_keys = array(
24
+        'wpinv_form_elements',
25
+        'wpinv_form_items',
26
+        'wpinv_form_earned',
27
+        'wpinv_form_refunded',
28
+        'wpinv_form_cancelled',
29
+        'wpinv_form_failed',
30
+    );
31
+
32
+    /**
33
+     * A map of meta keys to data props.
34
+     *
35
+     * @since 1.0.19
36
+     *
37
+     * @var array
38
+     */
39
+    protected $meta_key_to_props = array(
40
+        'wpinv_form_elements'  => 'elements',
41
+        'wpinv_form_items'     => 'items',
42
+        'wpinv_form_earned'    => 'earned',
43
+        'wpinv_form_refunded'  => 'refunded',
44
+        'wpinv_form_cancelled' => 'cancelled',
45
+        'wpinv_form_failed'    => 'failed',
46
+    );
47
+
48
+    /*
49 49
 	|--------------------------------------------------------------------------
50 50
 	| CRUD Methods
51 51
 	|--------------------------------------------------------------------------
52 52
 	*/
53 53
 
54
-	/**
55
-	 * Method to create a new form in the database.
56
-	 *
57
-	 * @param GetPaid_Payment_Form $form Form object.
58
-	 */
59
-	public function create( &$form ) {
60
-		$form->set_version( WPINV_VERSION );
61
-		$form->set_date_created( current_time( 'mysql' ) );
62
-
63
-		// Create a new post.
64
-		$id = wp_insert_post(
65
-			apply_filters(
66
-				'getpaid_new_payment_form_data',
67
-				array(
68
-					'post_date'   => $form->get_date_created( 'edit' ),
69
-					'post_type'   => 'wpi_payment_form',
70
-					'post_status' => $this->get_post_status( $form ),
71
-					'ping_status' => 'closed',
72
-					'post_author' => $form->get_author( 'edit' ),
73
-					'post_title'  => $form->get_name( 'edit' ),
74
-				)
75
-			),
76
-			true
77
-		);
78
-
79
-		if ( $id && ! is_wp_error( $id ) ) {
80
-			$form->set_id( $id );
81
-			$this->update_post_meta( $form );
82
-			$form->save_meta_data();
83
-			$form->apply_changes();
84
-			$this->clear_caches( $form );
85
-			do_action( 'getpaid_create_payment_form', $form );
86
-			return true;
87
-		}
88
-
89
-		if ( is_wp_error( $id ) ) {
90
-			$form->last_error = $id->get_error_message();
91
-		}
92
-
93
-		return false;
94
-	}
95
-
96
-	/**
97
-	 * Method to read a form from the database.
98
-	 *
99
-	 * @param GetPaid_Payment_Form $form Form object.
100
-	 *
101
-	 */
102
-	public function read( &$form ) {
103
-
104
-		$form->set_defaults();
105
-		$form_object = get_post( $form->get_id() );
106
-
107
-		if ( ! $form->get_id() || ! $form_object || $form_object->post_type != 'wpi_payment_form' ) {
108
-			$form->last_error = __( 'Invalid form.', 'invoicing' );
109
-			$form->set_id( 0 );
110
-			return false;
111
-		}
112
-
113
-		$form->set_props(
114
-			array(
115
-				'date_created'  => 0 < $form_object->post_date ? $form_object->post_date : null,
116
-				'date_modified' => 0 < $form_object->post_modified ? $form_object->post_modified : null,
117
-				'status'        => $form_object->post_status,
118
-				'name'          => $form_object->post_title,
119
-				'author'        => $form_object->post_author,
120
-			)
121
-		);
122
-
123
-		$this->read_object_data( $form, $form_object );
124
-		$form->read_meta_data();
125
-		$form->set_object_read( true );
126
-		do_action( 'getpaid_read_payment_form', $form );
127
-
128
-	}
129
-
130
-	/**
131
-	 * Method to update a form in the database.
132
-	 *
133
-	 * @param GetPaid_Payment_Form $form Form object.
134
-	 */
135
-	public function update( &$form ) {
136
-		$form->save_meta_data();
137
-		$form->set_version( WPINV_VERSION );
138
-
139
-		if ( null === $form->get_date_created( 'edit' ) ) {
140
-			$form->set_date_created( current_time( 'mysql' ) );
141
-		}
142
-
143
-		// Grab the current status so we can compare.
144
-		$previous_status = get_post_status( $form->get_id() );
145
-
146
-		$changes = $form->get_changes();
147
-
148
-		// Only update the post when the post data changes.
149
-		if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'name', 'author' ), array_keys( $changes ) ) ) {
150
-			$post_data = array(
151
-				'post_date'     => $form->get_date_created( 'edit' ),
152
-				'post_status'   => $form->get_status( 'edit' ),
153
-				'post_title'    => $form->get_name( 'edit' ),
154
-				'post_author'   => $form->get_author( 'edit' ),
155
-				'post_modified' => $form->get_date_modified( 'edit' ),
156
-			);
157
-
158
-			/**
159
-			 * When updating this object, to prevent infinite loops, use $wpdb
160
-			 * to update data, since wp_update_post spawns more calls to the
161
-			 * save_post action.
162
-			 *
163
-			 * This ensures hooks are fired by either WP itself (admin screen save),
164
-			 * or an update purely from CRUD.
165
-			 */
166
-			if ( doing_action( 'save_post' ) ) {
167
-				$GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $form->get_id() ) );
168
-				clean_post_cache( $form->get_id() );
169
-			} else {
170
-				wp_update_post( array_merge( array( 'ID' => $form->get_id() ), $post_data ) );
171
-			}
172
-			$form->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
173
-		}
174
-		$this->update_post_meta( $form );
175
-		$form->apply_changes();
176
-		$this->clear_caches( $form );
177
-
178
-		// Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
179
-		$new_status = $form->get_status( 'edit' );
180
-
181
-		if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
182
-			do_action( 'getpaid_new_payment_form', $form );
183
-		} else {
184
-			do_action( 'getpaid_update_payment_form', $form );
185
-		}
186
-
187
-	}
188
-
189
-	/*
54
+    /**
55
+     * Method to create a new form in the database.
56
+     *
57
+     * @param GetPaid_Payment_Form $form Form object.
58
+     */
59
+    public function create( &$form ) {
60
+        $form->set_version( WPINV_VERSION );
61
+        $form->set_date_created( current_time( 'mysql' ) );
62
+
63
+        // Create a new post.
64
+        $id = wp_insert_post(
65
+            apply_filters(
66
+                'getpaid_new_payment_form_data',
67
+                array(
68
+                    'post_date'   => $form->get_date_created( 'edit' ),
69
+                    'post_type'   => 'wpi_payment_form',
70
+                    'post_status' => $this->get_post_status( $form ),
71
+                    'ping_status' => 'closed',
72
+                    'post_author' => $form->get_author( 'edit' ),
73
+                    'post_title'  => $form->get_name( 'edit' ),
74
+                )
75
+            ),
76
+            true
77
+        );
78
+
79
+        if ( $id && ! is_wp_error( $id ) ) {
80
+            $form->set_id( $id );
81
+            $this->update_post_meta( $form );
82
+            $form->save_meta_data();
83
+            $form->apply_changes();
84
+            $this->clear_caches( $form );
85
+            do_action( 'getpaid_create_payment_form', $form );
86
+            return true;
87
+        }
88
+
89
+        if ( is_wp_error( $id ) ) {
90
+            $form->last_error = $id->get_error_message();
91
+        }
92
+
93
+        return false;
94
+    }
95
+
96
+    /**
97
+     * Method to read a form from the database.
98
+     *
99
+     * @param GetPaid_Payment_Form $form Form object.
100
+     *
101
+     */
102
+    public function read( &$form ) {
103
+
104
+        $form->set_defaults();
105
+        $form_object = get_post( $form->get_id() );
106
+
107
+        if ( ! $form->get_id() || ! $form_object || $form_object->post_type != 'wpi_payment_form' ) {
108
+            $form->last_error = __( 'Invalid form.', 'invoicing' );
109
+            $form->set_id( 0 );
110
+            return false;
111
+        }
112
+
113
+        $form->set_props(
114
+            array(
115
+                'date_created'  => 0 < $form_object->post_date ? $form_object->post_date : null,
116
+                'date_modified' => 0 < $form_object->post_modified ? $form_object->post_modified : null,
117
+                'status'        => $form_object->post_status,
118
+                'name'          => $form_object->post_title,
119
+                'author'        => $form_object->post_author,
120
+            )
121
+        );
122
+
123
+        $this->read_object_data( $form, $form_object );
124
+        $form->read_meta_data();
125
+        $form->set_object_read( true );
126
+        do_action( 'getpaid_read_payment_form', $form );
127
+
128
+    }
129
+
130
+    /**
131
+     * Method to update a form in the database.
132
+     *
133
+     * @param GetPaid_Payment_Form $form Form object.
134
+     */
135
+    public function update( &$form ) {
136
+        $form->save_meta_data();
137
+        $form->set_version( WPINV_VERSION );
138
+
139
+        if ( null === $form->get_date_created( 'edit' ) ) {
140
+            $form->set_date_created( current_time( 'mysql' ) );
141
+        }
142
+
143
+        // Grab the current status so we can compare.
144
+        $previous_status = get_post_status( $form->get_id() );
145
+
146
+        $changes = $form->get_changes();
147
+
148
+        // Only update the post when the post data changes.
149
+        if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'name', 'author' ), array_keys( $changes ) ) ) {
150
+            $post_data = array(
151
+                'post_date'     => $form->get_date_created( 'edit' ),
152
+                'post_status'   => $form->get_status( 'edit' ),
153
+                'post_title'    => $form->get_name( 'edit' ),
154
+                'post_author'   => $form->get_author( 'edit' ),
155
+                'post_modified' => $form->get_date_modified( 'edit' ),
156
+            );
157
+
158
+            /**
159
+             * When updating this object, to prevent infinite loops, use $wpdb
160
+             * to update data, since wp_update_post spawns more calls to the
161
+             * save_post action.
162
+             *
163
+             * This ensures hooks are fired by either WP itself (admin screen save),
164
+             * or an update purely from CRUD.
165
+             */
166
+            if ( doing_action( 'save_post' ) ) {
167
+                $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $form->get_id() ) );
168
+                clean_post_cache( $form->get_id() );
169
+            } else {
170
+                wp_update_post( array_merge( array( 'ID' => $form->get_id() ), $post_data ) );
171
+            }
172
+            $form->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
173
+        }
174
+        $this->update_post_meta( $form );
175
+        $form->apply_changes();
176
+        $this->clear_caches( $form );
177
+
178
+        // Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
179
+        $new_status = $form->get_status( 'edit' );
180
+
181
+        if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
182
+            do_action( 'getpaid_new_payment_form', $form );
183
+        } else {
184
+            do_action( 'getpaid_update_payment_form', $form );
185
+        }
186
+
187
+    }
188
+
189
+    /*
190 190
 	|--------------------------------------------------------------------------
191 191
 	| Additional Methods
192 192
 	|--------------------------------------------------------------------------
Please login to merge, or discard this patch.
includes/data-stores/class-getpaid-data.php 1 patch
Indentation   +857 added lines, -857 removed lines patch added patch discarded remove patch
@@ -9,7 +9,7 @@  discard block
 block discarded – undo
9 9
  */
10 10
 
11 11
 if ( ! defined( 'ABSPATH' ) ) {
12
-	exit;
12
+    exit;
13 13
 }
14 14
 
15 15
 /**
@@ -21,356 +21,356 @@  discard block
 block discarded – undo
21 21
  */
22 22
 abstract class GetPaid_Data {
23 23
 
24
-	/**
25
-	 * ID for this object.
26
-	 *
27
-	 * @since 1.0.19
28
-	 * @var int
29
-	 */
30
-	protected $id = 0;
31
-
32
-	/**
33
-	 * Core data for this object. Name value pairs (name + default value).
34
-	 *
35
-	 * @since 1.0.19
36
-	 * @var array
37
-	 */
38
-	protected $data = array();
39
-
40
-	/**
41
-	 * Core data changes for this object.
42
-	 *
43
-	 * @since 1.0.19
44
-	 * @var array
45
-	 */
46
-	protected $changes = array();
47
-
48
-	/**
49
-	 * This is false until the object is read from the DB.
50
-	 *
51
-	 * @since 1.0.19
52
-	 * @var bool
53
-	 */
54
-	protected $object_read = false;
55
-
56
-	/**
57
-	 * This is the name of this object type.
58
-	 *
59
-	 * @since 1.0.19
60
-	 * @var string
61
-	 */
62
-	protected $object_type = 'data';
63
-
64
-	/**
65
-	 * Extra data for this object. Name value pairs (name + default value).
66
-	 * Used as a standard way for sub classes (like item types) to add
67
-	 * additional information to an inherited class.
68
-	 *
69
-	 * @since 1.0.19
70
-	 * @var array
71
-	 */
72
-	protected $extra_data = array();
73
-
74
-	/**
75
-	 * Set to _data on construct so we can track and reset data if needed.
76
-	 *
77
-	 * @since 1.0.19
78
-	 * @var array
79
-	 */
80
-	protected $default_data = array();
81
-
82
-	/**
83
-	 * Contains a reference to the data store for this class.
84
-	 *
85
-	 * @since 1.0.19
86
-	 * @var GetPaid_Data_Store
87
-	 */
88
-	protected $data_store;
89
-
90
-	/**
91
-	 * Stores meta in cache for future reads.
92
-	 * A group must be set to to enable caching.
93
-	 *
94
-	 * @since 1.0.19
95
-	 * @var string
96
-	 */
97
-	protected $cache_group = '';
98
-
99
-	/**
100
-	 * Stores the last error.
101
-	 *
102
-	 * @since 1.0.19
103
-	 * @var string
104
-	 */
105
-	public $last_error = '';
106
-
107
-	/**
108
-	 * Stores additional meta data.
109
-	 *
110
-	 * @since 1.0.19
111
-	 * @var array
112
-	 */
113
-	protected $meta_data = null;
114
-
115
-	/**
116
-	 * Default constructor.
117
-	 *
118
-	 * @param int|object|array|string $read ID to load from the DB (optional) or already queried data.
119
-	 */
120
-	public function __construct( $read = 0 ) {
121
-		$this->data         = array_merge( $this->data, $this->extra_data );
122
-		$this->default_data = $this->data;
123
-	}
124
-
125
-	/**
126
-	 * Only store the object ID to avoid serializing the data object instance.
127
-	 *
128
-	 * @return array
129
-	 */
130
-	public function __sleep() {
131
-		return array( 'id' );
132
-	}
133
-
134
-	/**
135
-	 * Re-run the constructor with the object ID.
136
-	 *
137
-	 * If the object no longer exists, remove the ID.
138
-	 */
139
-	public function __wakeup() {
140
-		$this->__construct( absint( $this->id ) );
141
-
142
-		if ( ! empty( $this->last_error ) ) {
143
-			$this->set_id( 0 );
144
-		}
145
-
146
-	}
147
-
148
-	/**
149
-	 * When the object is cloned, make sure meta is duplicated correctly.
150
-	 *
151
-	 * @since 1.0.19
152
-	 */
153
-	public function __clone() {
154
-		$this->maybe_read_meta_data();
155
-		if ( ! empty( $this->meta_data ) ) {
156
-			foreach ( $this->meta_data as $array_key => $meta ) {
157
-				$this->meta_data[ $array_key ] = clone $meta;
158
-				if ( ! empty( $meta->id ) ) {
159
-					$this->meta_data[ $array_key ]->id = null;
160
-				}
161
-			}
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * Get the data store.
167
-	 *
168
-	 * @since  1.0.19
169
-	 * @return object
170
-	 */
171
-	public function get_data_store() {
172
-		return $this->data_store;
173
-	}
174
-
175
-	/**
176
-	 * Get the object type.
177
-	 *
178
-	 * @since  1.0.19
179
-	 * @return string
180
-	 */
181
-	public function get_object_type() {
182
-		return $this->object_type;
183
-	}
184
-
185
-	/**
186
-	 * Returns the unique ID for this object.
187
-	 *
188
-	 * @since  1.0.19
189
-	 * @return int
190
-	 */
191
-	public function get_id() {
192
-		return $this->id;
193
-	}
194
-
195
-	/**
196
-	 * Get form status.
197
-	 *
198
-	 * @since 1.0.19
199
-	 * @param  string $context View or edit context.
200
-	 * @return string
201
-	 */
202
-	public function get_status( $context = 'view' ) {
203
-		return $this->get_prop( 'status', $context );
204
-    }
205
-
206
-	/**
207
-	 * Delete an object, set the ID to 0, and return result.
208
-	 *
209
-	 * @since  1.0.19
210
-	 * @param  bool $force_delete Should the data be deleted permanently.
211
-	 * @return bool result
212
-	 */
213
-	public function delete( $force_delete = false ) {
214
-		if ( $this->data_store && $this->exists() ) {
215
-			$this->data_store->delete( $this, array( 'force_delete' => $force_delete ) );
216
-			$this->set_id( 0 );
217
-			return true;
218
-		}
219
-		return false;
220
-	}
221
-
222
-	/**
223
-	 * Save should create or update based on object existence.
224
-	 *
225
-	 * @since  1.0.19
226
-	 * @return int
227
-	 */
228
-	public function save() {
229
-		if ( ! $this->data_store ) {
230
-			return $this->get_id();
231
-		}
232
-
233
-		/**
234
-		 * Trigger action before saving to the DB. Allows you to adjust object props before save.
235
-		 *
236
-		 * @param GetPaid_Data          $this The object being saved.
237
-		 * @param GetPaid_Data_Store_WP $data_store The data store persisting the data.
238
-		 */
239
-		do_action( 'getpaid_before_' . $this->object_type . '_object_save', $this, $this->data_store );
240
-
241
-		if ( $this->get_id() ) {
242
-			$this->data_store->update( $this );
243
-		} else {
244
-			$this->data_store->create( $this );
245
-		}
246
-
247
-		/**
248
-		 * Trigger action after saving to the DB.
249
-		 *
250
-		 * @param GetPaid_Data          $this The object being saved.
251
-		 * @param GetPaid_Data_Store_WP $data_store The data store persisting the data.
252
-		 */
253
-		do_action( 'getpaid_after_' . $this->object_type . '_object_save', $this, $this->data_store );
254
-
255
-		return $this->get_id();
256
-	}
257
-
258
-	/**
259
-	 * Change data to JSON format.
260
-	 *
261
-	 * @since  1.0.19
262
-	 * @return string Data in JSON format.
263
-	 */
264
-	public function __toString() {
265
-		return wp_json_encode( $this->get_data() );
266
-	}
267
-
268
-	/**
269
-	 * Returns all data for this object.
270
-	 *
271
-	 * @since  1.0.19
272
-	 * @return array
273
-	 */
274
-	public function get_data() {
275
-		return array_merge( array( 'id' => $this->get_id() ), $this->data, array( 'meta_data' => $this->get_meta_data() ) );
276
-	}
277
-
278
-	/**
279
-	 * Returns array of expected data keys for this object.
280
-	 *
281
-	 * @since   1.0.19
282
-	 * @return array
283
-	 */
284
-	public function get_data_keys() {
285
-		return array_keys( $this->data );
286
-	}
287
-
288
-	/**
289
-	 * Returns all "extra" data keys for an object (for sub objects like item types).
290
-	 *
291
-	 * @since  1.0.19
292
-	 * @return array
293
-	 */
294
-	public function get_extra_data_keys() {
295
-		return array_keys( $this->extra_data );
296
-	}
297
-
298
-	/**
299
-	 * Filter null meta values from array.
300
-	 *
301
-	 * @since  1.0.19
302
-	 * @param mixed $meta Meta value to check.
303
-	 * @return bool
304
-	 */
305
-	protected function filter_null_meta( $meta ) {
306
-		return ! is_null( $meta->value );
307
-	}
308
-
309
-	/**
310
-	 * Get All Meta Data.
311
-	 *
312
-	 * @since 1.0.19
313
-	 * @return array of objects.
314
-	 */
315
-	public function get_meta_data() {
316
-		$this->maybe_read_meta_data();
317
-		return array_values( array_filter( $this->meta_data, array( $this, 'filter_null_meta' ) ) );
318
-	}
319
-
320
-	/**
321
-	 * Check if the key is an internal one.
322
-	 *
323
-	 * @since  1.0.19
324
-	 * @param  string $key Key to check.
325
-	 * @return bool   true if it's an internal key, false otherwise
326
-	 */
327
-	protected function is_internal_meta_key( $key ) {
328
-		$internal_meta_key = ! empty( $key ) && $this->data_store && in_array( $key, $this->data_store->get_internal_meta_keys(), true );
329
-
330
-		if ( ! $internal_meta_key ) {
331
-			return false;
332
-		}
333
-
334
-		$has_setter_or_getter = is_callable( array( $this, 'set_' . $key ) ) || is_callable( array( $this, 'get_' . $key ) );
335
-
336
-		if ( ! $has_setter_or_getter ) {
337
-			return false;
338
-		}
339
-
340
-		/* translators: %s: $key Key to check */
341
-		getpaid_doing_it_wrong( __FUNCTION__, sprintf( __( 'Generic add/update/get meta methods should not be used for internal meta data, including "%s". Use getters and setters.', 'invoicing' ), $key ), '1.0.19' );
342
-
343
-		return true;
344
-	}
345
-
346
-	/**
347
-	 * Magic method for setting data fields.
348
-	 *
349
-	 * This method does not update custom fields in the database.
350
-	 *
351
-	 * @since 1.0.19
352
-	 * @access public
353
-	 *
354
-	 */
355
-	public function __set( $key, $value ) {
356
-
357
-		if ( 'id' == strtolower( $key ) ) {
358
-			return $this->set_id( $value );
359
-		}
360
-
361
-		if ( method_exists( $this, "set_$key" ) ) {
362
-
363
-			/* translators: %s: $key Key to set */
364
-			getpaid_doing_it_wrong( __FUNCTION__, sprintf( __( 'Object data such as "%s" should not be accessed directly. Use getters and setters.', 'invoicing' ), $key ), '1.0.19' );
365
-
366
-			call_user_func( array( $this, "set_$key" ), $value );
367
-		} else {
368
-			$this->set_prop( $key, $value );
369
-		}
370
-
371
-	}
372
-
373
-	/**
24
+    /**
25
+     * ID for this object.
26
+     *
27
+     * @since 1.0.19
28
+     * @var int
29
+     */
30
+    protected $id = 0;
31
+
32
+    /**
33
+     * Core data for this object. Name value pairs (name + default value).
34
+     *
35
+     * @since 1.0.19
36
+     * @var array
37
+     */
38
+    protected $data = array();
39
+
40
+    /**
41
+     * Core data changes for this object.
42
+     *
43
+     * @since 1.0.19
44
+     * @var array
45
+     */
46
+    protected $changes = array();
47
+
48
+    /**
49
+     * This is false until the object is read from the DB.
50
+     *
51
+     * @since 1.0.19
52
+     * @var bool
53
+     */
54
+    protected $object_read = false;
55
+
56
+    /**
57
+     * This is the name of this object type.
58
+     *
59
+     * @since 1.0.19
60
+     * @var string
61
+     */
62
+    protected $object_type = 'data';
63
+
64
+    /**
65
+     * Extra data for this object. Name value pairs (name + default value).
66
+     * Used as a standard way for sub classes (like item types) to add
67
+     * additional information to an inherited class.
68
+     *
69
+     * @since 1.0.19
70
+     * @var array
71
+     */
72
+    protected $extra_data = array();
73
+
74
+    /**
75
+     * Set to _data on construct so we can track and reset data if needed.
76
+     *
77
+     * @since 1.0.19
78
+     * @var array
79
+     */
80
+    protected $default_data = array();
81
+
82
+    /**
83
+     * Contains a reference to the data store for this class.
84
+     *
85
+     * @since 1.0.19
86
+     * @var GetPaid_Data_Store
87
+     */
88
+    protected $data_store;
89
+
90
+    /**
91
+     * Stores meta in cache for future reads.
92
+     * A group must be set to to enable caching.
93
+     *
94
+     * @since 1.0.19
95
+     * @var string
96
+     */
97
+    protected $cache_group = '';
98
+
99
+    /**
100
+     * Stores the last error.
101
+     *
102
+     * @since 1.0.19
103
+     * @var string
104
+     */
105
+    public $last_error = '';
106
+
107
+    /**
108
+     * Stores additional meta data.
109
+     *
110
+     * @since 1.0.19
111
+     * @var array
112
+     */
113
+    protected $meta_data = null;
114
+
115
+    /**
116
+     * Default constructor.
117
+     *
118
+     * @param int|object|array|string $read ID to load from the DB (optional) or already queried data.
119
+     */
120
+    public function __construct( $read = 0 ) {
121
+        $this->data         = array_merge( $this->data, $this->extra_data );
122
+        $this->default_data = $this->data;
123
+    }
124
+
125
+    /**
126
+     * Only store the object ID to avoid serializing the data object instance.
127
+     *
128
+     * @return array
129
+     */
130
+    public function __sleep() {
131
+        return array( 'id' );
132
+    }
133
+
134
+    /**
135
+     * Re-run the constructor with the object ID.
136
+     *
137
+     * If the object no longer exists, remove the ID.
138
+     */
139
+    public function __wakeup() {
140
+        $this->__construct( absint( $this->id ) );
141
+
142
+        if ( ! empty( $this->last_error ) ) {
143
+            $this->set_id( 0 );
144
+        }
145
+
146
+    }
147
+
148
+    /**
149
+     * When the object is cloned, make sure meta is duplicated correctly.
150
+     *
151
+     * @since 1.0.19
152
+     */
153
+    public function __clone() {
154
+        $this->maybe_read_meta_data();
155
+        if ( ! empty( $this->meta_data ) ) {
156
+            foreach ( $this->meta_data as $array_key => $meta ) {
157
+                $this->meta_data[ $array_key ] = clone $meta;
158
+                if ( ! empty( $meta->id ) ) {
159
+                    $this->meta_data[ $array_key ]->id = null;
160
+                }
161
+            }
162
+        }
163
+    }
164
+
165
+    /**
166
+     * Get the data store.
167
+     *
168
+     * @since  1.0.19
169
+     * @return object
170
+     */
171
+    public function get_data_store() {
172
+        return $this->data_store;
173
+    }
174
+
175
+    /**
176
+     * Get the object type.
177
+     *
178
+     * @since  1.0.19
179
+     * @return string
180
+     */
181
+    public function get_object_type() {
182
+        return $this->object_type;
183
+    }
184
+
185
+    /**
186
+     * Returns the unique ID for this object.
187
+     *
188
+     * @since  1.0.19
189
+     * @return int
190
+     */
191
+    public function get_id() {
192
+        return $this->id;
193
+    }
194
+
195
+    /**
196
+     * Get form status.
197
+     *
198
+     * @since 1.0.19
199
+     * @param  string $context View or edit context.
200
+     * @return string
201
+     */
202
+    public function get_status( $context = 'view' ) {
203
+        return $this->get_prop( 'status', $context );
204
+    }
205
+
206
+    /**
207
+     * Delete an object, set the ID to 0, and return result.
208
+     *
209
+     * @since  1.0.19
210
+     * @param  bool $force_delete Should the data be deleted permanently.
211
+     * @return bool result
212
+     */
213
+    public function delete( $force_delete = false ) {
214
+        if ( $this->data_store && $this->exists() ) {
215
+            $this->data_store->delete( $this, array( 'force_delete' => $force_delete ) );
216
+            $this->set_id( 0 );
217
+            return true;
218
+        }
219
+        return false;
220
+    }
221
+
222
+    /**
223
+     * Save should create or update based on object existence.
224
+     *
225
+     * @since  1.0.19
226
+     * @return int
227
+     */
228
+    public function save() {
229
+        if ( ! $this->data_store ) {
230
+            return $this->get_id();
231
+        }
232
+
233
+        /**
234
+         * Trigger action before saving to the DB. Allows you to adjust object props before save.
235
+         *
236
+         * @param GetPaid_Data          $this The object being saved.
237
+         * @param GetPaid_Data_Store_WP $data_store The data store persisting the data.
238
+         */
239
+        do_action( 'getpaid_before_' . $this->object_type . '_object_save', $this, $this->data_store );
240
+
241
+        if ( $this->get_id() ) {
242
+            $this->data_store->update( $this );
243
+        } else {
244
+            $this->data_store->create( $this );
245
+        }
246
+
247
+        /**
248
+         * Trigger action after saving to the DB.
249
+         *
250
+         * @param GetPaid_Data          $this The object being saved.
251
+         * @param GetPaid_Data_Store_WP $data_store The data store persisting the data.
252
+         */
253
+        do_action( 'getpaid_after_' . $this->object_type . '_object_save', $this, $this->data_store );
254
+
255
+        return $this->get_id();
256
+    }
257
+
258
+    /**
259
+     * Change data to JSON format.
260
+     *
261
+     * @since  1.0.19
262
+     * @return string Data in JSON format.
263
+     */
264
+    public function __toString() {
265
+        return wp_json_encode( $this->get_data() );
266
+    }
267
+
268
+    /**
269
+     * Returns all data for this object.
270
+     *
271
+     * @since  1.0.19
272
+     * @return array
273
+     */
274
+    public function get_data() {
275
+        return array_merge( array( 'id' => $this->get_id() ), $this->data, array( 'meta_data' => $this->get_meta_data() ) );
276
+    }
277
+
278
+    /**
279
+     * Returns array of expected data keys for this object.
280
+     *
281
+     * @since   1.0.19
282
+     * @return array
283
+     */
284
+    public function get_data_keys() {
285
+        return array_keys( $this->data );
286
+    }
287
+
288
+    /**
289
+     * Returns all "extra" data keys for an object (for sub objects like item types).
290
+     *
291
+     * @since  1.0.19
292
+     * @return array
293
+     */
294
+    public function get_extra_data_keys() {
295
+        return array_keys( $this->extra_data );
296
+    }
297
+
298
+    /**
299
+     * Filter null meta values from array.
300
+     *
301
+     * @since  1.0.19
302
+     * @param mixed $meta Meta value to check.
303
+     * @return bool
304
+     */
305
+    protected function filter_null_meta( $meta ) {
306
+        return ! is_null( $meta->value );
307
+    }
308
+
309
+    /**
310
+     * Get All Meta Data.
311
+     *
312
+     * @since 1.0.19
313
+     * @return array of objects.
314
+     */
315
+    public function get_meta_data() {
316
+        $this->maybe_read_meta_data();
317
+        return array_values( array_filter( $this->meta_data, array( $this, 'filter_null_meta' ) ) );
318
+    }
319
+
320
+    /**
321
+     * Check if the key is an internal one.
322
+     *
323
+     * @since  1.0.19
324
+     * @param  string $key Key to check.
325
+     * @return bool   true if it's an internal key, false otherwise
326
+     */
327
+    protected function is_internal_meta_key( $key ) {
328
+        $internal_meta_key = ! empty( $key ) && $this->data_store && in_array( $key, $this->data_store->get_internal_meta_keys(), true );
329
+
330
+        if ( ! $internal_meta_key ) {
331
+            return false;
332
+        }
333
+
334
+        $has_setter_or_getter = is_callable( array( $this, 'set_' . $key ) ) || is_callable( array( $this, 'get_' . $key ) );
335
+
336
+        if ( ! $has_setter_or_getter ) {
337
+            return false;
338
+        }
339
+
340
+        /* translators: %s: $key Key to check */
341
+        getpaid_doing_it_wrong( __FUNCTION__, sprintf( __( 'Generic add/update/get meta methods should not be used for internal meta data, including "%s". Use getters and setters.', 'invoicing' ), $key ), '1.0.19' );
342
+
343
+        return true;
344
+    }
345
+
346
+    /**
347
+     * Magic method for setting data fields.
348
+     *
349
+     * This method does not update custom fields in the database.
350
+     *
351
+     * @since 1.0.19
352
+     * @access public
353
+     *
354
+     */
355
+    public function __set( $key, $value ) {
356
+
357
+        if ( 'id' == strtolower( $key ) ) {
358
+            return $this->set_id( $value );
359
+        }
360
+
361
+        if ( method_exists( $this, "set_$key" ) ) {
362
+
363
+            /* translators: %s: $key Key to set */
364
+            getpaid_doing_it_wrong( __FUNCTION__, sprintf( __( 'Object data such as "%s" should not be accessed directly. Use getters and setters.', 'invoicing' ), $key ), '1.0.19' );
365
+
366
+            call_user_func( array( $this, "set_$key" ), $value );
367
+        } else {
368
+            $this->set_prop( $key, $value );
369
+        }
370
+
371
+    }
372
+
373
+    /**
374 374
      * Margic method for retrieving a property.
375 375
      */
376 376
     public function __get( $key ) {
@@ -378,10 +378,10 @@  discard block
 block discarded – undo
378 378
         // Check if we have a helper method for that.
379 379
         if ( method_exists( $this, 'get_' . $key ) ) {
380 380
 
381
-			if ( 'post_type' != $key ) {
382
-				/* translators: %s: $key Key to set */
383
-				getpaid_doing_it_wrong( __FUNCTION__, sprintf( __( 'Object data such as "%s" should not be accessed directly. Use getters and setters.', 'invoicing' ), $key ), '1.0.19' );
384
-			}
381
+            if ( 'post_type' != $key ) {
382
+                /* translators: %s: $key Key to set */
383
+                getpaid_doing_it_wrong( __FUNCTION__, sprintf( __( 'Object data such as "%s" should not be accessed directly. Use getters and setters.', 'invoicing' ), $key ), '1.0.19' );
384
+            }
385 385
 
386 386
             return call_user_func( array( $this, 'get_' . $key ) );
387 387
         }
@@ -391,513 +391,513 @@  discard block
 block discarded – undo
391 391
             return $this->post->$key;
392 392
         }
393 393
 
394
-		return $this->get_prop( $key );
395
-
396
-    }
397
-
398
-	/**
399
-	 * Get Meta Data by Key.
400
-	 *
401
-	 * @since  1.0.19
402
-	 * @param  string $key Meta Key.
403
-	 * @param  bool   $single return first found meta with key, or all with $key.
404
-	 * @param  string $context What the value is for. Valid values are view and edit.
405
-	 * @return mixed
406
-	 */
407
-	public function get_meta( $key = '', $single = true, $context = 'view' ) {
408
-
409
-		// Check if this is an internal meta key.
410
-		$_key = str_replace( '_wpinv', '', $key );
411
-		$_key = str_replace( 'wpinv', '', $_key );
412
-		if ( $this->is_internal_meta_key( $key ) ) {
413
-			$function = 'get_' . $_key;
414
-
415
-			if ( is_callable( array( $this, $function ) ) ) {
416
-				return $this->{$function}();
417
-			}
418
-		}
419
-
420
-		// Read the meta data if not yet read.
421
-		$this->maybe_read_meta_data();
422
-		$meta_data  = $this->get_meta_data();
423
-		$array_keys = array_keys( wp_list_pluck( $meta_data, 'key' ), $key, true );
424
-		$value      = $single ? '' : array();
425
-
426
-		if ( ! empty( $array_keys ) ) {
427
-			// We don't use the $this->meta_data property directly here because we don't want meta with a null value (i.e. meta which has been deleted via $this->delete_meta_data()).
428
-			if ( $single ) {
429
-				$value = $meta_data[ current( $array_keys ) ]->value;
430
-			} else {
431
-				$value = array_intersect_key( $meta_data, array_flip( $array_keys ) );
432
-			}
433
-		}
434
-
435
-		if ( 'view' === $context ) {
436
-			$value = apply_filters( $this->get_hook_prefix() . $key, $value, $this );
437
-		}
438
-
439
-		return $value;
440
-	}
441
-
442
-	/**
443
-	 * See if meta data exists, since get_meta always returns a '' or array().
444
-	 *
445
-	 * @since  1.0.19
446
-	 * @param  string $key Meta Key.
447
-	 * @return boolean
448
-	 */
449
-	public function meta_exists( $key = '' ) {
450
-		$this->maybe_read_meta_data();
451
-		$array_keys = wp_list_pluck( $this->get_meta_data(), 'key' );
452
-		return in_array( $key, $array_keys, true );
453
-	}
454
-
455
-	/**
456
-	 * Set all meta data from array.
457
-	 *
458
-	 * @since 1.0.19
459
-	 * @param array $data Key/Value pairs.
460
-	 */
461
-	public function set_meta_data( $data ) {
462
-		if ( ! empty( $data ) && is_array( $data ) ) {
463
-			$this->maybe_read_meta_data();
464
-			foreach ( $data as $meta ) {
465
-				$meta = (array) $meta;
466
-				if ( isset( $meta['key'], $meta['value'], $meta['id'] ) ) {
467
-					$this->meta_data[] = new GetPaid_Meta_Data(
468
-						array(
469
-							'id'    => $meta['id'],
470
-							'key'   => $meta['key'],
471
-							'value' => $meta['value'],
472
-						)
473
-					);
474
-				}
475
-			}
476
-		}
477
-	}
478
-
479
-	/**
480
-	 * Add meta data.
481
-	 *
482
-	 * @since 1.0.19
483
-	 *
484
-	 * @param string       $key Meta key.
485
-	 * @param string|array $value Meta value.
486
-	 * @param bool         $unique Should this be a unique key?.
487
-	 */
488
-	public function add_meta_data( $key, $value, $unique = false ) {
489
-		if ( $this->is_internal_meta_key( $key ) ) {
490
-			$function = 'set_' . $key;
491
-
492
-			if ( is_callable( array( $this, $function ) ) ) {
493
-				return $this->{$function}( $value );
494
-			}
495
-		}
496
-
497
-		$this->maybe_read_meta_data();
498
-		if ( $unique ) {
499
-			$this->delete_meta_data( $key );
500
-		}
501
-		$this->meta_data[] = new GetPaid_Meta_Data(
502
-			array(
503
-				'key'   => $key,
504
-				'value' => $value,
505
-			)
506
-		);
507
-
508
-		$this->save();
509
-	}
510
-
511
-	/**
512
-	 * Update meta data by key or ID, if provided.
513
-	 *
514
-	 * @since  1.0.19
515
-	 *
516
-	 * @param  string       $key Meta key.
517
-	 * @param  string|array $value Meta value.
518
-	 * @param  int          $meta_id Meta ID.
519
-	 */
520
-	public function update_meta_data( $key, $value, $meta_id = 0 ) {
521
-		if ( $this->is_internal_meta_key( $key ) ) {
522
-			$function = 'set_' . $key;
523
-
524
-			if ( is_callable( array( $this, $function ) ) ) {
525
-				return $this->{$function}( $value );
526
-			}
527
-		}
528
-
529
-		$this->maybe_read_meta_data();
530
-
531
-		$array_key = false;
532
-
533
-		if ( $meta_id ) {
534
-			$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'id' ), $meta_id, true );
535
-			$array_key  = $array_keys ? current( $array_keys ) : false;
536
-		} else {
537
-			// Find matches by key.
538
-			$matches = array();
539
-			foreach ( $this->meta_data as $meta_data_array_key => $meta ) {
540
-				if ( $meta->key === $key ) {
541
-					$matches[] = $meta_data_array_key;
542
-				}
543
-			}
544
-
545
-			if ( ! empty( $matches ) ) {
546
-				// Set matches to null so only one key gets the new value.
547
-				foreach ( $matches as $meta_data_array_key ) {
548
-					$this->meta_data[ $meta_data_array_key ]->value = null;
549
-				}
550
-				$array_key = current( $matches );
551
-			}
552
-		}
553
-
554
-		if ( false !== $array_key ) {
555
-			$meta        = $this->meta_data[ $array_key ];
556
-			$meta->key   = $key;
557
-			$meta->value = $value;
558
-		} else {
559
-			$this->add_meta_data( $key, $value, true );
560
-		}
561
-	}
562
-
563
-	/**
564
-	 * Delete meta data.
565
-	 *
566
-	 * @since 1.0.19
567
-	 * @param string $key Meta key.
568
-	 */
569
-	public function delete_meta_data( $key ) {
570
-		$this->maybe_read_meta_data();
571
-		$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'key' ), $key, true );
572
-
573
-		if ( $array_keys ) {
574
-			foreach ( $array_keys as $array_key ) {
575
-				$this->meta_data[ $array_key ]->value = null;
576
-			}
577
-		}
578
-	}
579
-
580
-	/**
581
-	 * Delete meta data.
582
-	 *
583
-	 * @since 1.0.19
584
-	 * @param int $mid Meta ID.
585
-	 */
586
-	public function delete_meta_data_by_mid( $mid ) {
587
-		$this->maybe_read_meta_data();
588
-		$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'id' ), (int) $mid, true );
589
-
590
-		if ( $array_keys ) {
591
-			foreach ( $array_keys as $array_key ) {
592
-				$this->meta_data[ $array_key ]->value = null;
593
-			}
594
-		}
595
-	}
596
-
597
-	/**
598
-	 * Read meta data if null.
599
-	 *
600
-	 * @since 1.0.19
601
-	 */
602
-	protected function maybe_read_meta_data() {
603
-		if ( is_null( $this->meta_data ) ) {
604
-			$this->read_meta_data();
605
-		}
606
-	}
607
-
608
-	/**
609
-	 * Read Meta Data from the database. Ignore any internal properties.
610
-	 * Uses it's own caches because get_metadata does not provide meta_ids.
611
-	 *
612
-	 * @since 1.0.19
613
-	 * @param bool $force_read True to force a new DB read (and update cache).
614
-	 */
615
-	public function read_meta_data( $force_read = false ) {
616
-
617
-		// Reset meta data.
618
-		$this->meta_data = array();
619
-
620
-		// Maybe abort early.
621
-		if ( ! $this->get_id() || ! $this->data_store ) {
622
-			return;
623
-		}
624
-
625
-		// Only read from cache if the cache key is set.
626
-		$cache_key = null;
627
-		if ( ! $force_read && ! empty( $this->cache_group ) ) {
628
-			$cache_key     = GetPaid_Cache_Helper::get_cache_prefix( $this->cache_group ) . GetPaid_Cache_Helper::get_cache_prefix( 'object_' . $this->get_id() ) . 'object_meta_' . $this->get_id();
629
-			$raw_meta_data = wp_cache_get( $cache_key, $this->cache_group );
630
-		}
631
-
632
-		// Should we force read?
633
-		if ( empty( $raw_meta_data ) ) {
634
-			$raw_meta_data = $this->data_store->read_meta( $this );
635
-
636
-			if ( ! empty( $cache_key ) ) {
637
-				wp_cache_set( $cache_key, $raw_meta_data, $this->cache_group );
638
-			}
394
+        return $this->get_prop( $key );
395
+
396
+    }
397
+
398
+    /**
399
+     * Get Meta Data by Key.
400
+     *
401
+     * @since  1.0.19
402
+     * @param  string $key Meta Key.
403
+     * @param  bool   $single return first found meta with key, or all with $key.
404
+     * @param  string $context What the value is for. Valid values are view and edit.
405
+     * @return mixed
406
+     */
407
+    public function get_meta( $key = '', $single = true, $context = 'view' ) {
408
+
409
+        // Check if this is an internal meta key.
410
+        $_key = str_replace( '_wpinv', '', $key );
411
+        $_key = str_replace( 'wpinv', '', $_key );
412
+        if ( $this->is_internal_meta_key( $key ) ) {
413
+            $function = 'get_' . $_key;
414
+
415
+            if ( is_callable( array( $this, $function ) ) ) {
416
+                return $this->{$function}();
417
+            }
418
+        }
419
+
420
+        // Read the meta data if not yet read.
421
+        $this->maybe_read_meta_data();
422
+        $meta_data  = $this->get_meta_data();
423
+        $array_keys = array_keys( wp_list_pluck( $meta_data, 'key' ), $key, true );
424
+        $value      = $single ? '' : array();
425
+
426
+        if ( ! empty( $array_keys ) ) {
427
+            // We don't use the $this->meta_data property directly here because we don't want meta with a null value (i.e. meta which has been deleted via $this->delete_meta_data()).
428
+            if ( $single ) {
429
+                $value = $meta_data[ current( $array_keys ) ]->value;
430
+            } else {
431
+                $value = array_intersect_key( $meta_data, array_flip( $array_keys ) );
432
+            }
433
+        }
434
+
435
+        if ( 'view' === $context ) {
436
+            $value = apply_filters( $this->get_hook_prefix() . $key, $value, $this );
437
+        }
438
+
439
+        return $value;
440
+    }
441
+
442
+    /**
443
+     * See if meta data exists, since get_meta always returns a '' or array().
444
+     *
445
+     * @since  1.0.19
446
+     * @param  string $key Meta Key.
447
+     * @return boolean
448
+     */
449
+    public function meta_exists( $key = '' ) {
450
+        $this->maybe_read_meta_data();
451
+        $array_keys = wp_list_pluck( $this->get_meta_data(), 'key' );
452
+        return in_array( $key, $array_keys, true );
453
+    }
454
+
455
+    /**
456
+     * Set all meta data from array.
457
+     *
458
+     * @since 1.0.19
459
+     * @param array $data Key/Value pairs.
460
+     */
461
+    public function set_meta_data( $data ) {
462
+        if ( ! empty( $data ) && is_array( $data ) ) {
463
+            $this->maybe_read_meta_data();
464
+            foreach ( $data as $meta ) {
465
+                $meta = (array) $meta;
466
+                if ( isset( $meta['key'], $meta['value'], $meta['id'] ) ) {
467
+                    $this->meta_data[] = new GetPaid_Meta_Data(
468
+                        array(
469
+                            'id'    => $meta['id'],
470
+                            'key'   => $meta['key'],
471
+                            'value' => $meta['value'],
472
+                        )
473
+                    );
474
+                }
475
+            }
476
+        }
477
+    }
478
+
479
+    /**
480
+     * Add meta data.
481
+     *
482
+     * @since 1.0.19
483
+     *
484
+     * @param string       $key Meta key.
485
+     * @param string|array $value Meta value.
486
+     * @param bool         $unique Should this be a unique key?.
487
+     */
488
+    public function add_meta_data( $key, $value, $unique = false ) {
489
+        if ( $this->is_internal_meta_key( $key ) ) {
490
+            $function = 'set_' . $key;
491
+
492
+            if ( is_callable( array( $this, $function ) ) ) {
493
+                return $this->{$function}( $value );
494
+            }
495
+        }
496
+
497
+        $this->maybe_read_meta_data();
498
+        if ( $unique ) {
499
+            $this->delete_meta_data( $key );
500
+        }
501
+        $this->meta_data[] = new GetPaid_Meta_Data(
502
+            array(
503
+                'key'   => $key,
504
+                'value' => $value,
505
+            )
506
+        );
507
+
508
+        $this->save();
509
+    }
510
+
511
+    /**
512
+     * Update meta data by key or ID, if provided.
513
+     *
514
+     * @since  1.0.19
515
+     *
516
+     * @param  string       $key Meta key.
517
+     * @param  string|array $value Meta value.
518
+     * @param  int          $meta_id Meta ID.
519
+     */
520
+    public function update_meta_data( $key, $value, $meta_id = 0 ) {
521
+        if ( $this->is_internal_meta_key( $key ) ) {
522
+            $function = 'set_' . $key;
523
+
524
+            if ( is_callable( array( $this, $function ) ) ) {
525
+                return $this->{$function}( $value );
526
+            }
527
+        }
528
+
529
+        $this->maybe_read_meta_data();
530
+
531
+        $array_key = false;
532
+
533
+        if ( $meta_id ) {
534
+            $array_keys = array_keys( wp_list_pluck( $this->meta_data, 'id' ), $meta_id, true );
535
+            $array_key  = $array_keys ? current( $array_keys ) : false;
536
+        } else {
537
+            // Find matches by key.
538
+            $matches = array();
539
+            foreach ( $this->meta_data as $meta_data_array_key => $meta ) {
540
+                if ( $meta->key === $key ) {
541
+                    $matches[] = $meta_data_array_key;
542
+                }
543
+            }
544
+
545
+            if ( ! empty( $matches ) ) {
546
+                // Set matches to null so only one key gets the new value.
547
+                foreach ( $matches as $meta_data_array_key ) {
548
+                    $this->meta_data[ $meta_data_array_key ]->value = null;
549
+                }
550
+                $array_key = current( $matches );
551
+            }
552
+        }
553
+
554
+        if ( false !== $array_key ) {
555
+            $meta        = $this->meta_data[ $array_key ];
556
+            $meta->key   = $key;
557
+            $meta->value = $value;
558
+        } else {
559
+            $this->add_meta_data( $key, $value, true );
560
+        }
561
+    }
562
+
563
+    /**
564
+     * Delete meta data.
565
+     *
566
+     * @since 1.0.19
567
+     * @param string $key Meta key.
568
+     */
569
+    public function delete_meta_data( $key ) {
570
+        $this->maybe_read_meta_data();
571
+        $array_keys = array_keys( wp_list_pluck( $this->meta_data, 'key' ), $key, true );
572
+
573
+        if ( $array_keys ) {
574
+            foreach ( $array_keys as $array_key ) {
575
+                $this->meta_data[ $array_key ]->value = null;
576
+            }
577
+        }
578
+    }
579
+
580
+    /**
581
+     * Delete meta data.
582
+     *
583
+     * @since 1.0.19
584
+     * @param int $mid Meta ID.
585
+     */
586
+    public function delete_meta_data_by_mid( $mid ) {
587
+        $this->maybe_read_meta_data();
588
+        $array_keys = array_keys( wp_list_pluck( $this->meta_data, 'id' ), (int) $mid, true );
589
+
590
+        if ( $array_keys ) {
591
+            foreach ( $array_keys as $array_key ) {
592
+                $this->meta_data[ $array_key ]->value = null;
593
+            }
594
+        }
595
+    }
596
+
597
+    /**
598
+     * Read meta data if null.
599
+     *
600
+     * @since 1.0.19
601
+     */
602
+    protected function maybe_read_meta_data() {
603
+        if ( is_null( $this->meta_data ) ) {
604
+            $this->read_meta_data();
605
+        }
606
+    }
607
+
608
+    /**
609
+     * Read Meta Data from the database. Ignore any internal properties.
610
+     * Uses it's own caches because get_metadata does not provide meta_ids.
611
+     *
612
+     * @since 1.0.19
613
+     * @param bool $force_read True to force a new DB read (and update cache).
614
+     */
615
+    public function read_meta_data( $force_read = false ) {
616
+
617
+        // Reset meta data.
618
+        $this->meta_data = array();
619
+
620
+        // Maybe abort early.
621
+        if ( ! $this->get_id() || ! $this->data_store ) {
622
+            return;
623
+        }
624
+
625
+        // Only read from cache if the cache key is set.
626
+        $cache_key = null;
627
+        if ( ! $force_read && ! empty( $this->cache_group ) ) {
628
+            $cache_key     = GetPaid_Cache_Helper::get_cache_prefix( $this->cache_group ) . GetPaid_Cache_Helper::get_cache_prefix( 'object_' . $this->get_id() ) . 'object_meta_' . $this->get_id();
629
+            $raw_meta_data = wp_cache_get( $cache_key, $this->cache_group );
630
+        }
631
+
632
+        // Should we force read?
633
+        if ( empty( $raw_meta_data ) ) {
634
+            $raw_meta_data = $this->data_store->read_meta( $this );
635
+
636
+            if ( ! empty( $cache_key ) ) {
637
+                wp_cache_set( $cache_key, $raw_meta_data, $this->cache_group );
638
+            }
639 639
 }
640 640
 
641
-		// Set meta data.
642
-		if ( is_array( $raw_meta_data ) ) {
643
-
644
-			foreach ( $raw_meta_data as $meta ) {
645
-				$this->meta_data[] = new GetPaid_Meta_Data(
646
-					array(
647
-						'id'    => (int) $meta->meta_id,
648
-						'key'   => $meta->meta_key,
649
-						'value' => maybe_unserialize( $meta->meta_value ),
650
-					)
651
-				);
652
-			}
641
+        // Set meta data.
642
+        if ( is_array( $raw_meta_data ) ) {
643
+
644
+            foreach ( $raw_meta_data as $meta ) {
645
+                $this->meta_data[] = new GetPaid_Meta_Data(
646
+                    array(
647
+                        'id'    => (int) $meta->meta_id,
648
+                        'key'   => $meta->meta_key,
649
+                        'value' => maybe_unserialize( $meta->meta_value ),
650
+                    )
651
+                );
652
+            }
653 653
 }
654 654
 
655
-	}
656
-
657
-	/**
658
-	 * Update Meta Data in the database.
659
-	 *
660
-	 * @since 1.0.19
661
-	 */
662
-	public function save_meta_data() {
663
-		if ( ! $this->data_store || is_null( $this->meta_data ) ) {
664
-			return;
665
-		}
666
-		foreach ( $this->meta_data as $array_key => $meta ) {
667
-			if ( is_null( $meta->value ) ) {
668
-				if ( ! empty( $meta->id ) ) {
669
-					$this->data_store->delete_meta( $this, $meta );
670
-					unset( $this->meta_data[ $array_key ] );
671
-				}
672
-			} elseif ( empty( $meta->id ) ) {
673
-				$meta->id = $this->data_store->add_meta( $this, $meta );
674
-				$meta->apply_changes();
675
-			} else {
676
-				if ( $meta->get_changes() ) {
677
-					$this->data_store->update_meta( $this, $meta );
678
-					$meta->apply_changes();
679
-				}
680
-			}
681
-		}
682
-		if ( ! empty( $this->cache_group ) ) {
683
-			$cache_key = GetPaid_Cache_Helper::get_cache_prefix( $this->cache_group ) . GetPaid_Cache_Helper::get_cache_prefix( 'object_' . $this->get_id() ) . 'object_meta_' . $this->get_id();
684
-			wp_cache_delete( $cache_key, $this->cache_group );
685
-		}
686
-	}
687
-
688
-	/**
689
-	 * Set ID.
690
-	 *
691
-	 * @since 1.0.19
692
-	 * @param int $id ID.
693
-	 */
694
-	public function set_id( $id ) {
695
-		$this->id = absint( $id );
696
-	}
697
-
698
-	/**
699
-	 * Sets item status.
700
-	 *
701
-	 * @since 1.0.19
702
-	 * @param string $status New status.
703
-	 * @return array details of change.
704
-	 */
705
-	public function set_status( $status ) {
655
+    }
656
+
657
+    /**
658
+     * Update Meta Data in the database.
659
+     *
660
+     * @since 1.0.19
661
+     */
662
+    public function save_meta_data() {
663
+        if ( ! $this->data_store || is_null( $this->meta_data ) ) {
664
+            return;
665
+        }
666
+        foreach ( $this->meta_data as $array_key => $meta ) {
667
+            if ( is_null( $meta->value ) ) {
668
+                if ( ! empty( $meta->id ) ) {
669
+                    $this->data_store->delete_meta( $this, $meta );
670
+                    unset( $this->meta_data[ $array_key ] );
671
+                }
672
+            } elseif ( empty( $meta->id ) ) {
673
+                $meta->id = $this->data_store->add_meta( $this, $meta );
674
+                $meta->apply_changes();
675
+            } else {
676
+                if ( $meta->get_changes() ) {
677
+                    $this->data_store->update_meta( $this, $meta );
678
+                    $meta->apply_changes();
679
+                }
680
+            }
681
+        }
682
+        if ( ! empty( $this->cache_group ) ) {
683
+            $cache_key = GetPaid_Cache_Helper::get_cache_prefix( $this->cache_group ) . GetPaid_Cache_Helper::get_cache_prefix( 'object_' . $this->get_id() ) . 'object_meta_' . $this->get_id();
684
+            wp_cache_delete( $cache_key, $this->cache_group );
685
+        }
686
+    }
687
+
688
+    /**
689
+     * Set ID.
690
+     *
691
+     * @since 1.0.19
692
+     * @param int $id ID.
693
+     */
694
+    public function set_id( $id ) {
695
+        $this->id = absint( $id );
696
+    }
697
+
698
+    /**
699
+     * Sets item status.
700
+     *
701
+     * @since 1.0.19
702
+     * @param string $status New status.
703
+     * @return array details of change.
704
+     */
705
+    public function set_status( $status ) {
706 706
         $old_status = $this->get_status();
707 707
 
708
-		$this->set_prop( 'status', $status );
709
-
710
-		return array(
711
-			'from' => $old_status,
712
-			'to'   => $status,
713
-		);
714
-    }
715
-
716
-	/**
717
-	 * Set all props to default values.
718
-	 *
719
-	 * @since 1.0.19
720
-	 */
721
-	public function set_defaults() {
722
-		$this->data    = $this->default_data;
723
-		$this->changes = array();
724
-		$this->set_object_read( false );
725
-	}
726
-
727
-	/**
728
-	 * Set object read property.
729
-	 *
730
-	 * @since 1.0.19
731
-	 * @param boolean $read Should read?.
732
-	 */
733
-	public function set_object_read( $read = true ) {
734
-		$this->object_read = (bool) $read;
735
-	}
736
-
737
-	/**
738
-	 * Get object read property.
739
-	 *
740
-	 * @since  1.0.19
741
-	 * @return boolean
742
-	 */
743
-	public function get_object_read() {
744
-		return (bool) $this->object_read;
745
-	}
746
-
747
-	/**
748
-	 * Set a collection of props in one go, collect any errors, and return the result.
749
-	 * Only sets using public methods.
750
-	 *
751
-	 * @since  1.0.19
752
-	 *
753
-	 * @param array  $props Key value pairs to set. Key is the prop and should map to a setter function name.
754
-	 * @param string $context In what context to run this.
755
-	 *
756
-	 * @return bool|WP_Error
757
-	 */
758
-	public function set_props( $props, $context = 'set' ) {
759
-		$errors = false;
760
-
761
-		$props = wp_unslash( $props );
762
-		foreach ( $props as $prop => $value ) {
763
-			try {
764
-				/**
765
-				 * Checks if the prop being set is allowed, and the value is not null.
766
-				 */
767
-				if ( is_null( $value ) || in_array( $prop, array( 'prop', 'date_prop', 'meta_data' ), true ) ) {
768
-					continue;
769
-				}
770
-				$setter = "set_$prop";
771
-
772
-				if ( is_callable( array( $this, $setter ) ) ) {
773
-					$this->{$setter}( $value );
774
-				}
775
-			} catch ( Exception $e ) {
776
-				if ( ! $errors ) {
777
-					$errors = new WP_Error();
778
-				}
779
-				$errors->add( $e->getCode(), $e->getMessage() );
780
-				$this->last_error = $e->getMessage();
781
-			}
782
-		}
783
-
784
-		return $errors && count( $errors->get_error_codes() ) ? $errors : true;
785
-	}
786
-
787
-	/**
788
-	 * Sets a prop for a setter method.
789
-	 *
790
-	 * This stores changes in a special array so we can track what needs saving
791
-	 * the the DB later.
792
-	 *
793
-	 * @since 1.0.19
794
-	 * @param string $prop Name of prop to set.
795
-	 * @param mixed  $value Value of the prop.
796
-	 */
797
-	protected function set_prop( $prop, $value ) {
798
-		if ( array_key_exists( $prop, $this->data ) ) {
799
-			if ( true === $this->object_read ) {
800
-				if ( $value !== $this->data[ $prop ] || array_key_exists( $prop, $this->changes ) ) {
801
-					$this->changes[ $prop ] = $value;
802
-				}
803
-			} else {
804
-				$this->data[ $prop ] = $value;
805
-			}
806
-		}
807
-	}
808
-
809
-	/**
810
-	 * Return data changes only.
811
-	 *
812
-	 * @since 1.0.19
813
-	 * @return array
814
-	 */
815
-	public function get_changes() {
816
-		return $this->changes;
817
-	}
818
-
819
-	/**
820
-	 * Merge changes with data and clear.
821
-	 *
822
-	 * @since 1.0.19
823
-	 */
824
-	public function apply_changes() {
825
-		$this->data    = array_replace( $this->data, $this->changes );
826
-		$this->changes = array();
827
-	}
828
-
829
-	/**
830
-	 * Prefix for action and filter hooks on data.
831
-	 *
832
-	 * @since  1.0.19
833
-	 * @return string
834
-	 */
835
-	protected function get_hook_prefix() {
836
-		return 'wpinv_get_' . $this->object_type . '_';
837
-	}
838
-
839
-	/**
840
-	 * Gets a prop for a getter method.
841
-	 *
842
-	 * Gets the value from either current pending changes, or the data itself.
843
-	 * Context controls what happens to the value before it's returned.
844
-	 *
845
-	 * @since  1.0.19
846
-	 * @param  string $prop Name of prop to get.
847
-	 * @param  string $context What the value is for. Valid values are view and edit.
848
-	 * @return mixed
849
-	 */
850
-	protected function get_prop( $prop, $context = 'view' ) {
851
-		$value = null;
852
-
853
-		if ( array_key_exists( $prop, $this->data ) ) {
854
-			$value = array_key_exists( $prop, $this->changes ) ? $this->changes[ $prop ] : $this->data[ $prop ];
855
-
856
-			if ( 'view' === $context ) {
857
-				$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
858
-			}
859
-		}
860
-
861
-		return $value;
862
-	}
863
-
864
-	/**
865
-	 * Sets a date prop whilst handling formatting and datetime objects.
866
-	 *
867
-	 * @since 1.0.19
868
-	 * @param string         $prop Name of prop to set.
869
-	 * @param string|integer $value Value of the prop.
870
-	 */
871
-	protected function set_date_prop( $prop, $value ) {
872
-
873
-		if ( empty( $value ) ) {
874
-			$this->set_prop( $prop, null );
875
-			return;
876
-		}
877
-		$this->set_prop( $prop, $value );
878
-
879
-	}
880
-
881
-	/**
882
-	 * When invalid data is found, throw an exception unless reading from the DB.
883
-	 *
884
-	 * @since 1.0.19
885
-	 * @param string $code             Error code.
886
-	 * @param string $message          Error message.
887
-	 */
888
-	protected function error( $code, $message ) {
889
-		$this->last_error = $message;
890
-	}
891
-
892
-	/**
893
-	 * Checks if the object is saved in the database
894
-	 *
895
-	 * @since 1.0.19
896
-	 * @return bool
897
-	 */
898
-	public function exists() {
899
-		$id = $this->get_id();
900
-		return ! empty( $id );
901
-	}
708
+        $this->set_prop( 'status', $status );
709
+
710
+        return array(
711
+            'from' => $old_status,
712
+            'to'   => $status,
713
+        );
714
+    }
715
+
716
+    /**
717
+     * Set all props to default values.
718
+     *
719
+     * @since 1.0.19
720
+     */
721
+    public function set_defaults() {
722
+        $this->data    = $this->default_data;
723
+        $this->changes = array();
724
+        $this->set_object_read( false );
725
+    }
726
+
727
+    /**
728
+     * Set object read property.
729
+     *
730
+     * @since 1.0.19
731
+     * @param boolean $read Should read?.
732
+     */
733
+    public function set_object_read( $read = true ) {
734
+        $this->object_read = (bool) $read;
735
+    }
736
+
737
+    /**
738
+     * Get object read property.
739
+     *
740
+     * @since  1.0.19
741
+     * @return boolean
742
+     */
743
+    public function get_object_read() {
744
+        return (bool) $this->object_read;
745
+    }
746
+
747
+    /**
748
+     * Set a collection of props in one go, collect any errors, and return the result.
749
+     * Only sets using public methods.
750
+     *
751
+     * @since  1.0.19
752
+     *
753
+     * @param array  $props Key value pairs to set. Key is the prop and should map to a setter function name.
754
+     * @param string $context In what context to run this.
755
+     *
756
+     * @return bool|WP_Error
757
+     */
758
+    public function set_props( $props, $context = 'set' ) {
759
+        $errors = false;
760
+
761
+        $props = wp_unslash( $props );
762
+        foreach ( $props as $prop => $value ) {
763
+            try {
764
+                /**
765
+                 * Checks if the prop being set is allowed, and the value is not null.
766
+                 */
767
+                if ( is_null( $value ) || in_array( $prop, array( 'prop', 'date_prop', 'meta_data' ), true ) ) {
768
+                    continue;
769
+                }
770
+                $setter = "set_$prop";
771
+
772
+                if ( is_callable( array( $this, $setter ) ) ) {
773
+                    $this->{$setter}( $value );
774
+                }
775
+            } catch ( Exception $e ) {
776
+                if ( ! $errors ) {
777
+                    $errors = new WP_Error();
778
+                }
779
+                $errors->add( $e->getCode(), $e->getMessage() );
780
+                $this->last_error = $e->getMessage();
781
+            }
782
+        }
783
+
784
+        return $errors && count( $errors->get_error_codes() ) ? $errors : true;
785
+    }
786
+
787
+    /**
788
+     * Sets a prop for a setter method.
789
+     *
790
+     * This stores changes in a special array so we can track what needs saving
791
+     * the the DB later.
792
+     *
793
+     * @since 1.0.19
794
+     * @param string $prop Name of prop to set.
795
+     * @param mixed  $value Value of the prop.
796
+     */
797
+    protected function set_prop( $prop, $value ) {
798
+        if ( array_key_exists( $prop, $this->data ) ) {
799
+            if ( true === $this->object_read ) {
800
+                if ( $value !== $this->data[ $prop ] || array_key_exists( $prop, $this->changes ) ) {
801
+                    $this->changes[ $prop ] = $value;
802
+                }
803
+            } else {
804
+                $this->data[ $prop ] = $value;
805
+            }
806
+        }
807
+    }
808
+
809
+    /**
810
+     * Return data changes only.
811
+     *
812
+     * @since 1.0.19
813
+     * @return array
814
+     */
815
+    public function get_changes() {
816
+        return $this->changes;
817
+    }
818
+
819
+    /**
820
+     * Merge changes with data and clear.
821
+     *
822
+     * @since 1.0.19
823
+     */
824
+    public function apply_changes() {
825
+        $this->data    = array_replace( $this->data, $this->changes );
826
+        $this->changes = array();
827
+    }
828
+
829
+    /**
830
+     * Prefix for action and filter hooks on data.
831
+     *
832
+     * @since  1.0.19
833
+     * @return string
834
+     */
835
+    protected function get_hook_prefix() {
836
+        return 'wpinv_get_' . $this->object_type . '_';
837
+    }
838
+
839
+    /**
840
+     * Gets a prop for a getter method.
841
+     *
842
+     * Gets the value from either current pending changes, or the data itself.
843
+     * Context controls what happens to the value before it's returned.
844
+     *
845
+     * @since  1.0.19
846
+     * @param  string $prop Name of prop to get.
847
+     * @param  string $context What the value is for. Valid values are view and edit.
848
+     * @return mixed
849
+     */
850
+    protected function get_prop( $prop, $context = 'view' ) {
851
+        $value = null;
852
+
853
+        if ( array_key_exists( $prop, $this->data ) ) {
854
+            $value = array_key_exists( $prop, $this->changes ) ? $this->changes[ $prop ] : $this->data[ $prop ];
855
+
856
+            if ( 'view' === $context ) {
857
+                $value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
858
+            }
859
+        }
860
+
861
+        return $value;
862
+    }
863
+
864
+    /**
865
+     * Sets a date prop whilst handling formatting and datetime objects.
866
+     *
867
+     * @since 1.0.19
868
+     * @param string         $prop Name of prop to set.
869
+     * @param string|integer $value Value of the prop.
870
+     */
871
+    protected function set_date_prop( $prop, $value ) {
872
+
873
+        if ( empty( $value ) ) {
874
+            $this->set_prop( $prop, null );
875
+            return;
876
+        }
877
+        $this->set_prop( $prop, $value );
878
+
879
+    }
880
+
881
+    /**
882
+     * When invalid data is found, throw an exception unless reading from the DB.
883
+     *
884
+     * @since 1.0.19
885
+     * @param string $code             Error code.
886
+     * @param string $message          Error message.
887
+     */
888
+    protected function error( $code, $message ) {
889
+        $this->last_error = $message;
890
+    }
891
+
892
+    /**
893
+     * Checks if the object is saved in the database
894
+     *
895
+     * @since 1.0.19
896
+     * @return bool
897
+     */
898
+    public function exists() {
899
+        $id = $this->get_id();
900
+        return ! empty( $id );
901
+    }
902 902
 
903 903
 }
Please login to merge, or discard this patch.
includes/data-stores/class-getpaid-subscription-data-store.php 1 patch
Indentation   +182 added lines, -182 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
  *
6 6
  */
7 7
 if ( ! defined( 'ABSPATH' ) ) {
8
-	exit;
8
+    exit;
9 9
 }
10 10
 
11 11
 /**
@@ -15,198 +15,198 @@  discard block
 block discarded – undo
15 15
  */
16 16
 class GetPaid_Subscription_Data_Store {
17 17
 
18
-	/**
19
-	 * A map of database fields to data types.
20
-	 *
21
-	 * @since 1.0.19
22
-	 * @var array
23
-	 */
24
-	protected $database_fields_to_data_type = array(
25
-		'id'                => '%d',
26
-		'customer_id'       => '%d',
27
-		'frequency'         => '%d',
28
-		'period'            => '%s',
29
-		'initial_amount'    => '%s',
30
-		'recurring_amount'  => '%s',
31
-		'bill_times'        => '%d',
32
-		'transaction_id'    => '%s',
33
-		'parent_payment_id' => '%d',
34
-		'product_id'        => '%d',
35
-		'created'           => '%s',
36
-		'expiration'        => '%s',
37
-		'trial_period'      => '%s',
38
-		'status'            => '%s',
39
-		'profile_id'        => '%s',
40
-	);
41
-
42
-	/*
18
+    /**
19
+     * A map of database fields to data types.
20
+     *
21
+     * @since 1.0.19
22
+     * @var array
23
+     */
24
+    protected $database_fields_to_data_type = array(
25
+        'id'                => '%d',
26
+        'customer_id'       => '%d',
27
+        'frequency'         => '%d',
28
+        'period'            => '%s',
29
+        'initial_amount'    => '%s',
30
+        'recurring_amount'  => '%s',
31
+        'bill_times'        => '%d',
32
+        'transaction_id'    => '%s',
33
+        'parent_payment_id' => '%d',
34
+        'product_id'        => '%d',
35
+        'created'           => '%s',
36
+        'expiration'        => '%s',
37
+        'trial_period'      => '%s',
38
+        'status'            => '%s',
39
+        'profile_id'        => '%s',
40
+    );
41
+
42
+    /*
43 43
 	|--------------------------------------------------------------------------
44 44
 	| CRUD Methods
45 45
 	|--------------------------------------------------------------------------
46 46
 	*/
47 47
 
48
-	/**
49
-	 * Method to create a new subscription in the database.
50
-	 *
51
-	 * @param WPInv_Subscription $subscription Subscription object.
52
-	 */
53
-	public function create( &$subscription ) {
54
-		global $wpdb;
55
-
56
-		$values  = array();
57
-		$formats = array();
58
-
59
-		$fields = $this->database_fields_to_data_type;
60
-		unset( $fields['id'] );
61
-
62
-		foreach ( $fields as $key => $format ) {
63
-			$method       = "get_$key";
64
-			$values[ $key ] = $subscription->$method( 'edit' );
65
-			$formats[]    = $format;
66
-		}
67
-
68
-		$result = $wpdb->insert( $wpdb->prefix . 'wpinv_subscriptions', $values, $formats );
69
-
70
-		if ( $result ) {
71
-			$subscription->set_id( $wpdb->insert_id );
72
-			$subscription->apply_changes();
73
-			$subscription->clear_cache();
74
-			update_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscription_id', $subscription->get_id() );
75
-			do_action( 'getpaid_new_subscription', $subscription );
76
-			return true;
77
-		}
78
-
79
-		return false;
80
-	}
81
-
82
-	/**
83
-	 * Method to read a subscription from the database.
84
-	 *
85
-	 * @param WPInv_Subscription $subscription Subscription object.
86
-	 *
87
-	 */
88
-	public function read( &$subscription ) {
89
-		global $wpdb;
90
-
91
-		$subscription->set_defaults();
92
-
93
-		if ( ! $subscription->get_id() ) {
94
-			$subscription->last_error = __( 'Invalid subscription ID.', 'invoicing' );
95
-			$subscription->set_id( 0 );
96
-			return false;
97
-		}
98
-
99
-		// Maybe retrieve from the cache.
100
-		$raw_subscription = wp_cache_get( $subscription->get_id(), 'getpaid_subscriptions' );
101
-
102
-		// If not found, retrieve from the db.
103
-		if ( false === $raw_subscription ) {
104
-
105
-			$raw_subscription = $wpdb->get_row(
106
-				$wpdb->prepare(
107
-					"SELECT * FROM {$wpdb->prefix}wpinv_subscriptions WHERE id = %d",
108
-					$subscription->get_id()
109
-				)
110
-			);
111
-
112
-			// Update the cache with our data
113
-			wp_cache_set( $subscription->get_id(), $raw_subscription, 'getpaid_subscriptions' );
114
-
115
-		}
116
-
117
-		if ( ! $raw_subscription ) {
118
-			$subscription->set_id( 0 );
119
-			$subscription->last_error = __( 'Invalid subscription ID.', 'invoicing' );
120
-			return false;
121
-		}
122
-
123
-		foreach ( array_keys( $this->database_fields_to_data_type ) as $key ) {
124
-			$method     = "set_$key";
125
-			$subscription->$method( $raw_subscription->$key );
126
-		}
127
-
128
-		$subscription->set_object_read( true );
129
-		do_action( 'getpaid_read_subscription', $subscription );
130
-
131
-	}
132
-
133
-	/**
134
-	 * Method to update a subscription in the database.
135
-	 *
136
-	 * @param WPInv_Subscription $subscription Subscription object.
137
-	 */
138
-	public function update( &$subscription ) {
139
-		global $wpdb;
140
-
141
-		$changes = $subscription->get_changes();
142
-		$values  = array();
143
-		$formats = array();
144
-
145
-		foreach ( $this->database_fields_to_data_type as $key => $format ) {
146
-			if ( array_key_exists( $key, $changes ) ) {
147
-				$method       = "get_$key";
148
-				$values[ $key ] = $subscription->$method( 'edit' );
149
-				$formats[]    = $format;
150
-			}
151
-		}
152
-
153
-		if ( empty( $values ) ) {
154
-			return;
155
-		}
156
-
157
-		$wpdb->update(
158
-			$wpdb->prefix . 'wpinv_subscriptions',
159
-			$values,
160
-			array(
161
-				'id' => $subscription->get_id(),
162
-			),
163
-			$formats,
164
-			'%d'
165
-		);
166
-
167
-		// Apply the changes.
168
-		$subscription->apply_changes();
169
-
170
-		// Delete cache.
171
-		$subscription->clear_cache();
172
-
173
-		update_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscr_profile_id', $subscription->get_profile_id() );
174
-		update_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscription_id', $subscription->get_id() );
175
-
176
-		// Fire a hook.
177
-		do_action( 'getpaid_update_subscription', $subscription );
178
-
179
-	}
180
-
181
-	/**
182
-	 * Method to delete a subscription from the database.
183
-	 *
184
-	 * @param WPInv_Subscription $subscription
185
-	 */
186
-	public function delete( &$subscription ) {
187
-		global $wpdb;
188
-
189
-		$wpdb->query(
190
-			$wpdb->prepare(
191
-				"DELETE FROM {$wpdb->prefix}wpinv_subscriptions
48
+    /**
49
+     * Method to create a new subscription in the database.
50
+     *
51
+     * @param WPInv_Subscription $subscription Subscription object.
52
+     */
53
+    public function create( &$subscription ) {
54
+        global $wpdb;
55
+
56
+        $values  = array();
57
+        $formats = array();
58
+
59
+        $fields = $this->database_fields_to_data_type;
60
+        unset( $fields['id'] );
61
+
62
+        foreach ( $fields as $key => $format ) {
63
+            $method       = "get_$key";
64
+            $values[ $key ] = $subscription->$method( 'edit' );
65
+            $formats[]    = $format;
66
+        }
67
+
68
+        $result = $wpdb->insert( $wpdb->prefix . 'wpinv_subscriptions', $values, $formats );
69
+
70
+        if ( $result ) {
71
+            $subscription->set_id( $wpdb->insert_id );
72
+            $subscription->apply_changes();
73
+            $subscription->clear_cache();
74
+            update_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscription_id', $subscription->get_id() );
75
+            do_action( 'getpaid_new_subscription', $subscription );
76
+            return true;
77
+        }
78
+
79
+        return false;
80
+    }
81
+
82
+    /**
83
+     * Method to read a subscription from the database.
84
+     *
85
+     * @param WPInv_Subscription $subscription Subscription object.
86
+     *
87
+     */
88
+    public function read( &$subscription ) {
89
+        global $wpdb;
90
+
91
+        $subscription->set_defaults();
92
+
93
+        if ( ! $subscription->get_id() ) {
94
+            $subscription->last_error = __( 'Invalid subscription ID.', 'invoicing' );
95
+            $subscription->set_id( 0 );
96
+            return false;
97
+        }
98
+
99
+        // Maybe retrieve from the cache.
100
+        $raw_subscription = wp_cache_get( $subscription->get_id(), 'getpaid_subscriptions' );
101
+
102
+        // If not found, retrieve from the db.
103
+        if ( false === $raw_subscription ) {
104
+
105
+            $raw_subscription = $wpdb->get_row(
106
+                $wpdb->prepare(
107
+                    "SELECT * FROM {$wpdb->prefix}wpinv_subscriptions WHERE id = %d",
108
+                    $subscription->get_id()
109
+                )
110
+            );
111
+
112
+            // Update the cache with our data
113
+            wp_cache_set( $subscription->get_id(), $raw_subscription, 'getpaid_subscriptions' );
114
+
115
+        }
116
+
117
+        if ( ! $raw_subscription ) {
118
+            $subscription->set_id( 0 );
119
+            $subscription->last_error = __( 'Invalid subscription ID.', 'invoicing' );
120
+            return false;
121
+        }
122
+
123
+        foreach ( array_keys( $this->database_fields_to_data_type ) as $key ) {
124
+            $method     = "set_$key";
125
+            $subscription->$method( $raw_subscription->$key );
126
+        }
127
+
128
+        $subscription->set_object_read( true );
129
+        do_action( 'getpaid_read_subscription', $subscription );
130
+
131
+    }
132
+
133
+    /**
134
+     * Method to update a subscription in the database.
135
+     *
136
+     * @param WPInv_Subscription $subscription Subscription object.
137
+     */
138
+    public function update( &$subscription ) {
139
+        global $wpdb;
140
+
141
+        $changes = $subscription->get_changes();
142
+        $values  = array();
143
+        $formats = array();
144
+
145
+        foreach ( $this->database_fields_to_data_type as $key => $format ) {
146
+            if ( array_key_exists( $key, $changes ) ) {
147
+                $method       = "get_$key";
148
+                $values[ $key ] = $subscription->$method( 'edit' );
149
+                $formats[]    = $format;
150
+            }
151
+        }
152
+
153
+        if ( empty( $values ) ) {
154
+            return;
155
+        }
156
+
157
+        $wpdb->update(
158
+            $wpdb->prefix . 'wpinv_subscriptions',
159
+            $values,
160
+            array(
161
+                'id' => $subscription->get_id(),
162
+            ),
163
+            $formats,
164
+            '%d'
165
+        );
166
+
167
+        // Apply the changes.
168
+        $subscription->apply_changes();
169
+
170
+        // Delete cache.
171
+        $subscription->clear_cache();
172
+
173
+        update_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscr_profile_id', $subscription->get_profile_id() );
174
+        update_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscription_id', $subscription->get_id() );
175
+
176
+        // Fire a hook.
177
+        do_action( 'getpaid_update_subscription', $subscription );
178
+
179
+    }
180
+
181
+    /**
182
+     * Method to delete a subscription from the database.
183
+     *
184
+     * @param WPInv_Subscription $subscription
185
+     */
186
+    public function delete( &$subscription ) {
187
+        global $wpdb;
188
+
189
+        $wpdb->query(
190
+            $wpdb->prepare(
191
+                "DELETE FROM {$wpdb->prefix}wpinv_subscriptions
192 192
 				WHERE id = %d",
193
-				$subscription->get_id()
194
-			)
195
-		);
193
+                $subscription->get_id()
194
+            )
195
+        );
196 196
 
197
-		delete_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscr_profile_id' );
198
-		delete_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscription_id' );
197
+        delete_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscr_profile_id' );
198
+        delete_post_meta( $subscription->get_parent_invoice_id(), '_wpinv_subscription_id' );
199 199
 
200
-		// Delete cache.
201
-		$subscription->clear_cache();
200
+        // Delete cache.
201
+        $subscription->clear_cache();
202 202
 
203
-		// Fire a hook.
204
-		do_action( 'getpaid_delete_subscription', $subscription );
203
+        // Fire a hook.
204
+        do_action( 'getpaid_delete_subscription', $subscription );
205 205
 
206
-		$subscription->set_id( 0 );
207
-	}
206
+        $subscription->set_id( 0 );
207
+    }
208 208
 
209
-	/*
209
+    /*
210 210
 	|--------------------------------------------------------------------------
211 211
 	| Additional Methods
212 212
 	|--------------------------------------------------------------------------
Please login to merge, or discard this patch.
includes/data-stores/class-getpaid-discount-data-store.php 1 patch
Indentation   +188 added lines, -188 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
  *
6 6
  */
7 7
 if ( ! defined( 'ABSPATH' ) ) {
8
-	exit;
8
+    exit;
9 9
 }
10 10
 
11 11
 /**
@@ -15,198 +15,198 @@  discard block
 block discarded – undo
15 15
  */
16 16
 class GetPaid_Discount_Data_Store extends GetPaid_Data_Store_WP {
17 17
 
18
-	/**
19
-	 * Data stored in meta keys, but not considered "meta" for a discount.
20
-	 *
21
-	 * @since 1.0.19
22
-	 * @var array
23
-	 */
24
-	protected $internal_meta_keys = array(
25
-		'_wpi_discount_code',
26
-		'_wpi_discount_amount',
27
-		'_wpi_discount_start',
28
-		'_wpi_discount_expiration',
29
-		'_wpi_discount_type',
30
-		'_wpi_discount_uses',
31
-		'_wpi_discount_is_single_use',
32
-		'_wpi_discount_items',
33
-		'_wpi_discount_excluded_items',
34
-		'_wpi_discount_required_items',
35
-		'_wpi_discount_max_uses',
36
-		'_wpi_discount_is_recurring',
37
-		'_wpi_discount_min_total',
38
-		'_wpi_discount_max_total',
39
-	);
40
-
41
-	/**
42
-	 * A map of meta keys to data props.
43
-	 *
44
-	 * @since 1.0.19
45
-	 *
46
-	 * @var array
47
-	 */
48
-	protected $meta_key_to_props = array(
49
-		'_wpi_discount_code'           => 'code',
50
-		'_wpi_discount_amount'         => 'amount',
51
-		'_wpi_discount_start'          => 'start',
52
-		'_wpi_discount_expiration'     => 'expiration',
53
-		'_wpi_discount_type'           => 'type',
54
-		'_wpi_discount_uses'           => 'uses',
55
-		'_wpi_discount_is_single_use'  => 'is_single_use',
56
-		'_wpi_discount_items'          => 'items',
57
-		'_wpi_discount_excluded_items' => 'excluded_items',
58
-		'_wpi_discount_required_items' => 'required_items',
59
-		'_wpi_discount_max_uses'       => 'max_uses',
60
-		'_wpi_discount_is_recurring'   => 'is_recurring',
61
-		'_wpi_discount_min_total'      => 'min_total',
62
-		'_wpi_discount_max_total'      => 'max_total',
63
-	);
64
-
65
-	/*
18
+    /**
19
+     * Data stored in meta keys, but not considered "meta" for a discount.
20
+     *
21
+     * @since 1.0.19
22
+     * @var array
23
+     */
24
+    protected $internal_meta_keys = array(
25
+        '_wpi_discount_code',
26
+        '_wpi_discount_amount',
27
+        '_wpi_discount_start',
28
+        '_wpi_discount_expiration',
29
+        '_wpi_discount_type',
30
+        '_wpi_discount_uses',
31
+        '_wpi_discount_is_single_use',
32
+        '_wpi_discount_items',
33
+        '_wpi_discount_excluded_items',
34
+        '_wpi_discount_required_items',
35
+        '_wpi_discount_max_uses',
36
+        '_wpi_discount_is_recurring',
37
+        '_wpi_discount_min_total',
38
+        '_wpi_discount_max_total',
39
+    );
40
+
41
+    /**
42
+     * A map of meta keys to data props.
43
+     *
44
+     * @since 1.0.19
45
+     *
46
+     * @var array
47
+     */
48
+    protected $meta_key_to_props = array(
49
+        '_wpi_discount_code'           => 'code',
50
+        '_wpi_discount_amount'         => 'amount',
51
+        '_wpi_discount_start'          => 'start',
52
+        '_wpi_discount_expiration'     => 'expiration',
53
+        '_wpi_discount_type'           => 'type',
54
+        '_wpi_discount_uses'           => 'uses',
55
+        '_wpi_discount_is_single_use'  => 'is_single_use',
56
+        '_wpi_discount_items'          => 'items',
57
+        '_wpi_discount_excluded_items' => 'excluded_items',
58
+        '_wpi_discount_required_items' => 'required_items',
59
+        '_wpi_discount_max_uses'       => 'max_uses',
60
+        '_wpi_discount_is_recurring'   => 'is_recurring',
61
+        '_wpi_discount_min_total'      => 'min_total',
62
+        '_wpi_discount_max_total'      => 'max_total',
63
+    );
64
+
65
+    /*
66 66
 	|--------------------------------------------------------------------------
67 67
 	| CRUD Methods
68 68
 	|--------------------------------------------------------------------------
69 69
 	*/
70 70
 
71
-	/**
72
-	 * Method to create a new discount in the database.
73
-	 *
74
-	 * @param WPInv_Discount $discount Discount object.
75
-	 */
76
-	public function create( &$discount ) {
77
-		$discount->set_version( WPINV_VERSION );
78
-		$discount->set_date_created( current_time( 'mysql' ) );
79
-
80
-		// Create a new post.
81
-		$id = wp_insert_post(
82
-			apply_filters(
83
-				'getpaid_new_discount_data',
84
-				array(
85
-					'post_date'    => $discount->get_date_created( 'edit' ),
86
-					'post_type'    => 'wpi_discount',
87
-					'post_status'  => $this->get_post_status( $discount ),
88
-					'ping_status'  => 'closed',
89
-					'post_author'  => $discount->get_author( 'edit' ),
90
-					'post_title'   => $discount->get_name( 'edit' ),
91
-					'post_excerpt' => $discount->get_description( 'edit' ),
92
-				)
93
-			),
94
-			true
95
-		);
96
-
97
-		if ( $id && ! is_wp_error( $id ) ) {
98
-			$discount->set_id( $id );
99
-			$this->update_post_meta( $discount );
100
-			$discount->save_meta_data();
101
-			$discount->apply_changes();
102
-			$this->clear_caches( $discount );
103
-			do_action( 'getpaid_new_discount', $discount );
104
-			return true;
105
-		}
106
-
107
-		if ( is_wp_error( $id ) ) {
108
-			$discount->last_error = $id->get_error_message();
109
-		}
110
-
111
-		return false;
112
-	}
113
-
114
-	/**
115
-	 * Method to read a discount from the database.
116
-	 *
117
-	 * @param WPInv_Discount $discount Discount object.
118
-	 *
119
-	 */
120
-	public function read( &$discount ) {
121
-
122
-		$discount->set_defaults();
123
-		$discount_object = get_post( $discount->get_id() );
124
-
125
-		if ( ! $discount->get_id() || ! $discount_object || $discount_object->post_type != 'wpi_discount' ) {
126
-			$discount->last_error = __( 'Invalid discount.', 'invoicing' );
127
-			$discount->set_id( 0 );
128
-			return false;
129
-		}
130
-
131
-		$discount->set_props(
132
-			array(
133
-				'date_created'  => 0 < $discount_object->post_date ? $discount_object->post_date : null,
134
-				'date_modified' => 0 < $discount_object->post_modified ? $discount_object->post_modified : null,
135
-				'status'        => $discount_object->post_status,
136
-				'name'          => $discount_object->post_title,
137
-				'author'        => $discount_object->post_author,
138
-				'description'   => $discount_object->post_excerpt,
139
-			)
140
-		);
141
-
142
-		$this->read_object_data( $discount, $discount_object );
143
-		$discount->read_meta_data();
144
-		$discount->set_object_read( true );
145
-		do_action( 'getpaid_read_discount', $discount );
146
-
147
-	}
148
-
149
-	/**
150
-	 * Method to update a discount in the database.
151
-	 *
152
-	 * @param WPInv_Discount $discount Discount object.
153
-	 */
154
-	public function update( &$discount ) {
155
-		$discount->save_meta_data();
156
-		$discount->set_version( WPINV_VERSION );
157
-
158
-		if ( null === $discount->get_date_created( 'edit' ) ) {
159
-			$discount->set_date_created( current_time( 'mysql' ) );
160
-		}
161
-
162
-		// Grab the current status so we can compare.
163
-		$previous_status = get_post_status( $discount->get_id() );
164
-
165
-		$changes = $discount->get_changes();
166
-
167
-		// Only update the post when the post data changes.
168
-		if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'name', 'author', 'post_excerpt' ), array_keys( $changes ) ) ) {
169
-			$post_data = array(
170
-				'post_date'     => $discount->get_date_created( 'edit' ),
171
-				'post_status'   => $discount->get_status( 'edit' ),
172
-				'post_title'    => $discount->get_name( 'edit' ),
173
-				'post_author'   => $discount->get_author( 'edit' ),
174
-				'post_modified' => $discount->get_date_modified( 'edit' ),
175
-				'post_excerpt'  => $discount->get_description( 'edit' ),
176
-			);
177
-
178
-			/**
179
-			 * When updating this object, to prevent infinite loops, use $wpdb
180
-			 * to update data, since wp_update_post spawns more calls to the
181
-			 * save_post action.
182
-			 *
183
-			 * This ensures hooks are fired by either WP itself (admin screen save),
184
-			 * or an update purely from CRUD.
185
-			 */
186
-			if ( doing_action( 'save_post' ) ) {
187
-				$GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $discount->get_id() ) );
188
-				clean_post_cache( $discount->get_id() );
189
-			} else {
190
-				wp_update_post( array_merge( array( 'ID' => $discount->get_id() ), $post_data ) );
191
-			}
192
-			$discount->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
193
-		}
194
-		$this->update_post_meta( $discount );
195
-		$discount->apply_changes();
196
-		$this->clear_caches( $discount );
197
-
198
-		// Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
199
-		$new_status = $discount->get_status( 'edit' );
200
-
201
-		if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
202
-			do_action( 'getpaid_new_discount', $discount );
203
-		} else {
204
-			do_action( 'getpaid_update_discount', $discount );
205
-		}
206
-
207
-	}
208
-
209
-	/*
71
+    /**
72
+     * Method to create a new discount in the database.
73
+     *
74
+     * @param WPInv_Discount $discount Discount object.
75
+     */
76
+    public function create( &$discount ) {
77
+        $discount->set_version( WPINV_VERSION );
78
+        $discount->set_date_created( current_time( 'mysql' ) );
79
+
80
+        // Create a new post.
81
+        $id = wp_insert_post(
82
+            apply_filters(
83
+                'getpaid_new_discount_data',
84
+                array(
85
+                    'post_date'    => $discount->get_date_created( 'edit' ),
86
+                    'post_type'    => 'wpi_discount',
87
+                    'post_status'  => $this->get_post_status( $discount ),
88
+                    'ping_status'  => 'closed',
89
+                    'post_author'  => $discount->get_author( 'edit' ),
90
+                    'post_title'   => $discount->get_name( 'edit' ),
91
+                    'post_excerpt' => $discount->get_description( 'edit' ),
92
+                )
93
+            ),
94
+            true
95
+        );
96
+
97
+        if ( $id && ! is_wp_error( $id ) ) {
98
+            $discount->set_id( $id );
99
+            $this->update_post_meta( $discount );
100
+            $discount->save_meta_data();
101
+            $discount->apply_changes();
102
+            $this->clear_caches( $discount );
103
+            do_action( 'getpaid_new_discount', $discount );
104
+            return true;
105
+        }
106
+
107
+        if ( is_wp_error( $id ) ) {
108
+            $discount->last_error = $id->get_error_message();
109
+        }
110
+
111
+        return false;
112
+    }
113
+
114
+    /**
115
+     * Method to read a discount from the database.
116
+     *
117
+     * @param WPInv_Discount $discount Discount object.
118
+     *
119
+     */
120
+    public function read( &$discount ) {
121
+
122
+        $discount->set_defaults();
123
+        $discount_object = get_post( $discount->get_id() );
124
+
125
+        if ( ! $discount->get_id() || ! $discount_object || $discount_object->post_type != 'wpi_discount' ) {
126
+            $discount->last_error = __( 'Invalid discount.', 'invoicing' );
127
+            $discount->set_id( 0 );
128
+            return false;
129
+        }
130
+
131
+        $discount->set_props(
132
+            array(
133
+                'date_created'  => 0 < $discount_object->post_date ? $discount_object->post_date : null,
134
+                'date_modified' => 0 < $discount_object->post_modified ? $discount_object->post_modified : null,
135
+                'status'        => $discount_object->post_status,
136
+                'name'          => $discount_object->post_title,
137
+                'author'        => $discount_object->post_author,
138
+                'description'   => $discount_object->post_excerpt,
139
+            )
140
+        );
141
+
142
+        $this->read_object_data( $discount, $discount_object );
143
+        $discount->read_meta_data();
144
+        $discount->set_object_read( true );
145
+        do_action( 'getpaid_read_discount', $discount );
146
+
147
+    }
148
+
149
+    /**
150
+     * Method to update a discount in the database.
151
+     *
152
+     * @param WPInv_Discount $discount Discount object.
153
+     */
154
+    public function update( &$discount ) {
155
+        $discount->save_meta_data();
156
+        $discount->set_version( WPINV_VERSION );
157
+
158
+        if ( null === $discount->get_date_created( 'edit' ) ) {
159
+            $discount->set_date_created( current_time( 'mysql' ) );
160
+        }
161
+
162
+        // Grab the current status so we can compare.
163
+        $previous_status = get_post_status( $discount->get_id() );
164
+
165
+        $changes = $discount->get_changes();
166
+
167
+        // Only update the post when the post data changes.
168
+        if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'name', 'author', 'post_excerpt' ), array_keys( $changes ) ) ) {
169
+            $post_data = array(
170
+                'post_date'     => $discount->get_date_created( 'edit' ),
171
+                'post_status'   => $discount->get_status( 'edit' ),
172
+                'post_title'    => $discount->get_name( 'edit' ),
173
+                'post_author'   => $discount->get_author( 'edit' ),
174
+                'post_modified' => $discount->get_date_modified( 'edit' ),
175
+                'post_excerpt'  => $discount->get_description( 'edit' ),
176
+            );
177
+
178
+            /**
179
+             * When updating this object, to prevent infinite loops, use $wpdb
180
+             * to update data, since wp_update_post spawns more calls to the
181
+             * save_post action.
182
+             *
183
+             * This ensures hooks are fired by either WP itself (admin screen save),
184
+             * or an update purely from CRUD.
185
+             */
186
+            if ( doing_action( 'save_post' ) ) {
187
+                $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $discount->get_id() ) );
188
+                clean_post_cache( $discount->get_id() );
189
+            } else {
190
+                wp_update_post( array_merge( array( 'ID' => $discount->get_id() ), $post_data ) );
191
+            }
192
+            $discount->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
193
+        }
194
+        $this->update_post_meta( $discount );
195
+        $discount->apply_changes();
196
+        $this->clear_caches( $discount );
197
+
198
+        // Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
199
+        $new_status = $discount->get_status( 'edit' );
200
+
201
+        if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
202
+            do_action( 'getpaid_new_discount', $discount );
203
+        } else {
204
+            do_action( 'getpaid_update_discount', $discount );
205
+        }
206
+
207
+    }
208
+
209
+    /*
210 210
 	|--------------------------------------------------------------------------
211 211
 	| Additional Methods
212 212
 	|--------------------------------------------------------------------------
Please login to merge, or discard this patch.