Passed
Pull Request — master (#371)
by Brian
104:46
created

GetPaid_Data_Store_WP::update_meta()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 2
rs 10
1
<?php
2
/**
3
 * Shared logic for WP based data.
4
 *
5
 * @version 1.0.19
6
 */
7
8
defined( 'ABSPATH' ) || exit;
9
10
/**
11
 * GetPaid_Data_Store_WP class.
12
 */
13
class GetPaid_Data_Store_WP {
14
15
	/**
16
	 * Meta type. This should match up with
17
	 * the types available at https://developer.wordpress.org/reference/functions/add_metadata/.
18
	 * WP defines 'post', 'user', 'comment', and 'term'.
19
	 *
20
	 * @var string
21
	 */
22
	protected $meta_type = 'post';
23
24
	/**
25
	 * This only needs set if you are using a custom metadata type (for example payment tokens.
26
	 *
27
	 * @var string
28
	 */
29
	protected $object_id_field_for_meta = '';
30
31
	/**
32
	 * Data stored in meta keys, but not considered "meta" for an object.
33
	 *
34
	 * @since 1.0.19
35
	 *
36
	 * @var array
37
	 */
38
	protected $internal_meta_keys = array();
39
40
	/**
41
	 * Meta data which should exist in the DB, even if empty.
42
	 *
43
	 * @since 1.0.19
44
	 *
45
	 * @var array
46
	 */
47
	protected $must_exist_meta_keys = array();
48
49
	/**
50
	 * Returns an array of meta for an object.
51
	 *
52
	 * @since  1.0.19
53
	 * @param  GetPaid_Data $object GetPaid_Data object.
54
	 * @return array
55
	 */
56
	public function read_meta( &$object ) {
57
		global $wpdb;
58
		$db_info       = $this->get_db_info();
59
		$raw_meta_data = $wpdb->get_results(
60
			$wpdb->prepare(
61
				"SELECT {$db_info['meta_id_field']} as meta_id, meta_key, meta_value
62
				FROM {$db_info['table']}
63
				WHERE {$db_info['object_id_field']} = %d
64
				ORDER BY {$db_info['meta_id_field']}",
65
				$object->get_id()
66
			)
67
		);
68
69
		$this->internal_meta_keys = array_merge( array_map( array( $this, 'prefix_key' ), $object->get_data_keys() ), $this->internal_meta_keys );
70
		$meta_data                = array_filter( $raw_meta_data, array( $this, 'exclude_internal_meta_keys' ) );
71
		return apply_filters( "getpaid_data_store_wp_{$this->meta_type}_read_meta", $meta_data, $object, $this );
72
	}
73
74
	/**
75
	 * Deletes meta based on meta ID.
76
	 *
77
	 * @since  1.0.19
78
	 * @param  GetPaid_Data  $object GetPaid_Data object.
79
	 * @param  stdClass $meta (containing at least ->id).
80
	 */
81
	public function delete_meta( &$object, $meta ) {
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed. ( Ignorable by Annotation )

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

81
	public function delete_meta( /** @scrutinizer ignore-unused */ &$object, $meta ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
82
		delete_metadata_by_mid( $this->meta_type, $meta->id );
83
	}
84
85
	/**
86
	 * Add new piece of meta.
87
	 *
88
	 * @since  1.0.19
89
	 * @param  GetPaid_Data  $object GetPaid_Data object.
90
	 * @param  stdClass $meta (containing ->key and ->value).
91
	 * @return int meta ID
92
	 */
93
	public function add_meta( &$object, $meta ) {
94
		return add_metadata( $this->meta_type, $object->get_id(), $meta->key, is_string( $meta->value ) ? wp_slash( $meta->value ) : $meta->value, false );
0 ignored issues
show
Bug Best Practice introduced by
The expression return add_metadata($thi... : $meta->value, false) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
95
	}
96
97
	/**
98
	 * Update meta.
99
	 *
100
	 * @since  1.0.19
101
	 * @param  GetPaid_Data  $object GetPaid_Data object.
102
	 * @param  stdClass $meta (containing ->id, ->key and ->value).
103
	 */
104
	public function update_meta( &$object, $meta ) {
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed. ( Ignorable by Annotation )

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

104
	public function update_meta( /** @scrutinizer ignore-unused */ &$object, $meta ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
105
		update_metadata_by_mid( $this->meta_type, $meta->id, $meta->value, $meta->key );
106
	}
107
108
	/**
109
	 * Table structure is slightly different between meta types, this function will return what we need to know.
110
	 *
111
	 * @since  1.0.19
112
	 * @return array Array elements: table, object_id_field, meta_id_field
113
	 */
114
	protected function get_db_info() {
115
		global $wpdb;
116
117
		$meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well.
118
		$table         = $wpdb->prefix;
119
120
		// If we are dealing with a type of metadata that is not a core type, the table should be prefixed.
121
		if ( ! in_array( $this->meta_type, array( 'post', 'user', 'comment', 'term' ), true ) ) {
122
			$table .= 'getpaid_';
123
		}
124
125
		$table          .= $this->meta_type . 'meta';
126
		$object_id_field = $this->meta_type . '_id';
127
128
		// Figure out our field names.
129
		if ( 'user' === $this->meta_type ) {
130
			$meta_id_field = 'umeta_id';
131
			$table         = $wpdb->usermeta;
132
		}
133
134
		if ( ! empty( $this->object_id_field_for_meta ) ) {
135
			$object_id_field = $this->object_id_field_for_meta;
136
		}
137
138
		return array(
139
			'table'           => $table,
140
			'object_id_field' => $object_id_field,
141
			'meta_id_field'   => $meta_id_field,
142
		);
143
	}
144
145
	/**
146
	 * Internal meta keys we don't want exposed as part of meta_data. This is in
147
	 * addition to all data props with _ prefix.
148
	 *
149
	 * @since 1.0.19
150
	 *
151
	 * @param string $key Prefix to be added to meta keys.
152
	 * @return string
153
	 */
154
	protected function prefix_key( $key ) {
155
		return '_' === substr( $key, 0, 1 ) ? $key : '_' . $key;
156
	}
157
158
	/**
159
	 * Callback to remove unwanted meta data.
160
	 *
161
	 * @param object $meta Meta object to check if it should be excluded or not.
162
	 * @return bool
163
	 */
164
	protected function exclude_internal_meta_keys( $meta ) {
165
		return ! in_array( $meta->meta_key, $this->internal_meta_keys, true ) && 0 !== stripos( $meta->meta_key, 'wp_' );
166
	}
167
168
	/**
169
	 * Gets a list of props and meta keys that need updated based on change state
170
	 * or if they are present in the database or not.
171
	 *
172
	 * @param  GetPaid_Data $object         The GetPaid_Data object.
173
	 * @param  array   $meta_key_to_props   A mapping of meta keys => prop names.
174
	 * @param  string  $meta_type           The internal WP meta type (post, user, etc).
175
	 * @return array                        A mapping of meta keys => prop names, filtered by ones that should be updated.
176
	 */
177
	protected function get_props_to_update( $object, $meta_key_to_props, $meta_type = 'post' ) {
178
		$props_to_update = array();
179
		$changed_props   = $object->get_changes();
180
181
		// Props should be updated if they are a part of the $changed array or don't exist yet.
182
		foreach ( $meta_key_to_props as $meta_key => $prop ) {
183
			if ( array_key_exists( $prop, $changed_props ) || ! metadata_exists( $meta_type, $object->get_id(), $meta_key ) ) {
184
				$props_to_update[ $meta_key ] = $prop;
185
			}
186
		}
187
188
		return $props_to_update;
189
	}
190
191
	/**
192
	 * Update meta data in, or delete it from, the database.
193
	 *
194
	 * Avoids storing meta when it's either an empty string or empty array or null.
195
	 * Other empty values such as numeric 0 should still be stored.
196
	 * Data-stores can force meta to exist using `must_exist_meta_keys`.
197
	 *
198
	 * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist.
199
	 *
200
	 * @param GetPaid_Data $object The GetPaid_Data object.
201
	 * @param string  $meta_key Meta key to update.
202
	 * @param mixed   $meta_value Value to save.
203
	 *
204
	 * @since 1.0.19 Added to prevent empty meta being stored unless required.
205
	 *
206
	 * @return bool True if updated/deleted.
207
	 */
208
	protected function update_or_delete_post_meta( $object, $meta_key, $meta_value ) {
209
		if ( in_array( $meta_value, array( array(), '', null ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) {
210
			$updated = delete_post_meta( $object->get_id(), $meta_key );
211
		} else {
212
			$updated = update_post_meta( $object->get_id(), $meta_key, $meta_value );
213
		}
214
215
		return (bool) $updated;
216
	}
217
218
	/**
219
	 * Return list of internal meta keys.
220
	 *
221
	 * @since 1.0.19
222
	 * @return array
223
	 */
224
	public function get_internal_meta_keys() {
225
		return $this->internal_meta_keys;
226
	}
227
228
}
229