Passed
Pull Request — master (#371)
by Brian
101:52
created

GetPaid_Item_Data_Store::update_post_meta()   A

Complexity

Conditions 5
Paths 10

Size

Total Lines 43
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 30
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 43
rs 9.1288
1
<?php
2
/**
3
 * GetPaid_Item_Data_Store class file.
4
 *
5
 */
6
if ( ! defined( 'ABSPATH' ) ) {
7
	exit;
8
}
9
10
/**
11
 * Abstract item Data Store: Stored in CPT.
12
 *
13
 * @version  1.0.19
14
 */
15
class GetPaid_Item_Data_Store extends GetPaid_Data_Store_WP {
16
17
	/**
18
	 * Internal meta type used to store order data.
19
	 *
20
	 * @since 1.0.19
21
	 * @var string
22
	 */
23
	protected $meta_type = 'post';
24
25
	/**
26
	 * Data stored in meta keys, but not considered "meta" for an item.
27
	 *
28
	 * @since 1.0.19
29
	 * @var array
30
	 */
31
	protected $internal_meta_keys = array(
32
		'_wpinv_price',
33
		'_wpinv_vat_rule',
34
		'_wpinv_vat_class',
35
		'_wpinv_type',
36
		'_wpinv_custom_id',
37
		'_wpinv_custom_name',
38
		'_wpinv_custom_singular_name',
39
		'_wpinv_editable',
40
		'_wpinv_dynamic_pricing',
41
		'_minimum_price',
42
		'_wpinv_is_recurring',
43
		'_wpinv_recurring_period',
44
		'_wpinv_recurring_interval',
45
		'_wpinv_recurring_limit',
46
		'_wpinv_free_trial',
47
		'_wpinv_trial_period',
48
		'_wpinv_trial_interval'
49
	);
50
51
	/*
52
	|--------------------------------------------------------------------------
53
	| CRUD Methods
54
	|--------------------------------------------------------------------------
55
	*/
56
57
	/**
58
	 * Method to create a new item in the database.
59
	 *
60
	 * @param WPInv_Item $item Item object.
61
	 */
62
	public function create( &$item ) {
63
		$item->set_version( WPINV_VERSION );
64
		$item->set_date_created( current_time('mysql') );
65
66
		// Create a new post.
67
		$id = wp_insert_post(
68
			apply_filters(
69
				'getpaid_new_item_data',
70
				array(
71
					'post_date'     => $item->get_date_created( 'edit' ),
72
					'post_type'     => 'wpi_item',
73
					'post_status'   => $this->get_post_status( $item ),
74
					'ping_status'   => 'closed',
75
					'post_author'   => $item->get_author( 'edit' ),
76
					'post_title'    => $item->get_name( 'edit' ),
77
					'post_parent'   => 0,
78
					'post_excerpt'  => $item->get_description( 'edit' ),
79
				)
80
			),
81
			true
82
		);
83
84
		if ( $id && ! is_wp_error( $id ) ) {
85
			$item->set_id( $id );
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type WP_Error; however, parameter $id of GetPaid_Data::set_id() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

85
			$item->set_id( /** @scrutinizer ignore-type */ $id );
Loading history...
86
			$this->update_post_meta( $item );
87
			$item->save_meta_data();
88
			$item->apply_changes();
89
			$this->clear_caches( $item );
90
			return true;
91
		}
92
93
		if ( is_wp_error( $id ) ) {
94
			$item->last_error = $id->get_error_message();
95
		}
96
		
97
		return false;
98
	}
99
100
	/**
101
	 * Method to read an item from the database.
102
	 *
103
	 * @param WPInv_Item $item Item object.
104
	 *
105
	 */
106
	public function read( &$item ) {
107
108
		$item->set_defaults();
109
		$item_object = get_post( $item->get_id() );
110
111
		if ( ! $item->get_id() || ! $item_object || $item_object->post_type != 'wpi_item' ) {
112
			$item->last_error = __( 'Invalid item.', 'invoicing' );
113
			return false;
114
		}
115
116
		$item->set_props(
117
			array(
118
				'parent_id'     => $item_object->post_parent,
119
				'date_created'  => 0 < $item_object->post_date_gmt ? $item_object->post_date_gmt : null,
120
				'date_modified' => 0 < $item_object->post_modified_gmt ? $item_object->post_modified_gmt : null,
121
				'status'        => $item_object->post_status,
122
				'name'          => $item_object->post_title,
123
				'description'   => $item_object->post_excerpt,
124
				'author'        => $item_object->post_author,
125
			)
126
		);
127
128
		$this->read_item_data( $item, $item_object );
129
		$item->read_meta_data();
130
		$item->set_object_read( true );
131
132
	}
133
134
	/**
135
	 * Method to update an item in the database.
136
	 *
137
	 * @param WPInv_Item $item Order object.
138
	 */
139
	public function update( &$item ) {
140
		$item->save_meta_data();
141
		$item->set_version( WPINV_VERSION );
142
143
		if ( null === $item->get_date_created( 'edit' ) ) {
0 ignored issues
show
introduced by
The condition null === $item->get_date_created('edit') is always false.
Loading history...
144
			$item->set_date_created(  current_time('mysql') );
145
		}
146
147
		$changes = $item->get_changes();
148
149
		// Only update the post when the post data changes.
150
		if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt' ), array_keys( $changes ) ) ) {
151
			$post_data = array(
152
				'post_date'         => $item->get_date_created( 'edit' ),
153
				'post_status'       => $item->get_status( $item ),
154
				'post_parent'       => $item->get_parent_id(),
155
				'post_excerpt'      => $item->get_description(),
156
				'post_modified'     => $item->get_date_modified( 'edit' ),
157
			);
158
159
			/**
160
			 * When updating this object, to prevent infinite loops, use $wpdb
161
			 * to update data, since wp_update_post spawns more calls to the
162
			 * save_post action.
163
			 *
164
			 * This ensures hooks are fired by either WP itself (admin screen save),
165
			 * or an update purely from CRUD.
166
			 */
167
			if ( doing_action( 'save_post' ) ) {
168
				$GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $item->get_id() ) );
169
				clean_post_cache( $item->get_id() );
170
			} else {
171
				wp_update_post( array_merge( array( 'ID' => $item->get_id() ), $post_data ) );
172
			}
173
			$item->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
174
		}
175
		$this->update_post_meta( $item );
176
		$item->apply_changes();
177
		$this->clear_caches( $item );
178
	}
179
180
	/**
181
	 * Method to delete an item from the database.
182
	 *
183
	 * @param WPInv_Item $item Item object.
184
	 * @param array    $args Array of args to pass to the delete method.
185
	 *
186
	 * @return void
187
	 */
188
	public function delete( &$item, $args = array() ) {
189
		$id   = $item->get_id();
190
		$args = wp_parse_args(
191
			$args,
192
			array(
193
				'force_delete' => false,
194
			)
195
		);
196
197
		if ( ! $id ) {
198
			return;
199
		}
200
201
		if ( $args['force_delete'] ) {
202
			wp_delete_post( $id );
203
			$item->set_id( 0 );
204
			do_action( 'getpaid_delete_item', $id );
205
		} else {
206
			wp_trash_post( $id );
207
			$item->set_status( 'trash' );
208
			do_action( 'getpaid_trash_item', $id );
209
		}
210
	}
211
212
	/*
213
	|--------------------------------------------------------------------------
214
	| Additional Methods
215
	|--------------------------------------------------------------------------
216
	*/
217
218
	/**
219
	 * Get the status to save to the post object.
220
	 *
221
	 *
222
	 * @since 1.0.19
223
	 * @param  WPInv_item $item Item object.
224
	 * @return string
225
	 */
226
	protected function get_post_status( $item ) {
227
		$item_status = $item->get_status( 'edit' );
228
229
		if ( ! $item_status ) {
230
			$item_status = apply_filters( 'getpaid_default_item_status', 'draft' );
231
		}
232
233
		return $item_status;
234
	}
235
236
	/**
237
	 * Read item data.
238
	 *
239
	 * @param WPInv_Item $item Item object.
240
	 * @param WP_Post   $post_object Post object.
241
	 * @since 1.0.19
242
	 */
243
	protected function read_item_data( &$item, $post_object ) {
244
		$id = $item->get_id();
245
246
		// Set item properties.
247
		$item->set_props(
248
			array(
249
				'price'                => get_post_meta( $id, '_wpinv_price', true ),
250
				'vat_rule'             => get_post_meta( $id, '_wpinv_vat_rule', true ),
251
				'vat_class'            => get_post_meta( $id, '_wpinv_vat_class', true ),
252
				'type'                 => get_post_meta( $id, '_wpinv_type', true ),
253
				'custom_id'            => get_post_meta( $id, '_wpinv_custom_id', true ),
254
				'custom_name'          => get_post_meta( $id, '_wpinv_custom_name', true ),
255
				'custom_singular_name' => get_post_meta( $id, '_wpinv_custom_singular_name', true ),
256
				'is_editable'          => get_post_meta( $id, '_wpinv_editable', true ),
257
				'is_dynamic_pricing'   => get_post_meta( $id, '_wpinv_dynamic_pricing', true ),
258
				'minimum_price'        => get_post_meta( $id, '_minimum_price', true ),
259
				'is_recurring'         => get_post_meta( $id, '_wpinv_is_recurring', true ),
260
				'recurring_period'     => get_post_meta( $id, '_wpinv_recurring_period', true ),
261
				'recurring_interval'   => get_post_meta( $id, '_wpinv_recurring_interval', true ),
262
				'recurring_limit'      => get_post_meta( $id, '_wpinv_recurring_limit', true ),
263
				'is_free_trial'        => get_post_meta( $id, '_wpinv_free_trial', true ),
264
				'trial_period'         => get_post_meta( $id, '_wpinv_trial_period', true ),
265
				'trial_interval'       => get_post_meta( $id, '_wpinv_trial_interval', true ),
266
				'version'              => get_post_meta( $id, '_wpinv_version', true ),
267
			)
268
		);
269
270
		// Gets extra data associated with the item if needed.
271
		foreach ( $item->get_extra_data_keys() as $key ) {
272
			$function = 'set_' . $key;
273
			if ( is_callable( array( $item, $function ) ) ) {
274
				$item->{$function}( get_post_meta( $item->get_id(), '_' . $key, true ) );
275
			}
276
		}
277
	}
278
279
	/**
280
	 * Helper method that updates all the post meta for an item based on it's settings in the WPInv_Item class.
281
	 *
282
	 * @param WPInv_Item $item Item object.
283
	 * @since 1.0.19
284
	 */
285
	protected function update_post_meta( &$item ) {
286
		$updated_props     = array();
287
288
		$meta_key_to_props = array(
289
			'_wpinv_price'                => 'price',
290
			'_wpinv_vat_rule'             => 'vat_rule',
291
			'_wpinv_vat_class'            => 'vat_class',
292
			'_wpinv_type'                 => 'type',
293
			'_wpinv_custom_id'            => 'custom_id',
294
			'_wpinv_custom_name'          => 'custom_name',
295
			'_wpinv_custom_singular_name' => 'custom_singular_name',
296
			'_wpinv_editable'             => 'is_editable',
297
			'_wpinv_dynamic_pricing'      => 'is_dynamic_pricing',
298
			'_minimum_price'              => 'minimum_price',
299
			'_wpinv_custom_name'          => 'custom_name',
300
			'_wpinv_is_recurring'         => 'is_recurring',
301
			'_wpinv_recurring_period'     => 'recurring_period',
302
			'_wpinv_recurring_interval'   => 'recurring_interval',
303
			'_wpinv_recurring_limit'      => 'recurring_limit',
304
			'_wpinv_free_trial'           => 'is_free_trial',
305
			'_wpinv_trial_period'         => 'trial_period',
306
			'_wpinv_trial_interval'       => 'trial_interval',
307
		);
308
309
		$props_to_update = $this->get_props_to_update( $item, $meta_key_to_props );
310
311
		// Ensure that we have a custom id.
312
        if ( ! $item->get_custom_id() ) {
313
            $item->set_custom_id( $item->get_id() );
314
        }
315
316
		foreach ( $props_to_update as $meta_key => $prop ) {
317
			$value = $item->{"get_$prop"}( 'edit' );
318
			$value = is_string( $value ) ? wp_slash( $value ) : $value;
319
320
			$updated = $this->update_or_delete_post_meta( $item, $meta_key, $value );
321
322
			if ( $updated ) {
323
				$updated_props[] = $prop;
324
			}
325
		}
326
327
		do_action( 'getpaid_item_object_updated_props', $item, $updated_props );
328
	}
329
330
	/**
331
	 * Clear any caches.
332
	 *
333
	 * @param WPInv_Item $item Item object.
334
	 * @since 1.0.19
335
	 */
336
	protected function clear_caches( &$item ) {
337
		clean_post_cache( $item->get_id() );
338
	}
339
340
}
341