PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
← All changes | models/model-post.php +61 -75 1.14 → 3.4 View file →
@@ -7,13 +7,16 @@
7 7 * @author Tobias Bäthge
8 8 * @since 1.0.0
9 9 */
10 10
11 +declare(strict_types=1);
12 +
11 13 // Prohibit direct script loading.
12 14 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13 15
14 16 /**
15 17 * Post Model class
18 + *
16 19 * @package TablePress
17 20 * @subpackage Models
18 21 * @author Tobias Bäthge
19 22 * @since 1.0.0
@@ -23,34 +26,34 @@
23 26 /**
24 27 * Name of the "Custom Post Type" for the tables.
25 28 *
26 29 * @since 1.0.0
27 - * @var string
30 + * @var lowercase-string&non-empty-string
28 31 */
29 - protected $post_type = 'tablepress_table';
32 + protected string $post_type = 'tablepress_table';
30 33
31 34 /**
32 - * Init the model by registering the Custom Post Type.
35 + * Inits the model by registering the Custom Post Type.
33 36 *
34 37 * @since 1.0.0
35 38 */
36 39 public function __construct() {
37 40 parent::__construct();
38 - $this->_register_post_type(); // we are on WP "init" hook already
41 + $this->_register_post_type(); // We are on WP "init" hook already.
39 42 }
40 43
41 44 /**
42 - * Register the Custom Post Type which the tables use.
45 + * Registers the Custom Post Type which the tables use.
43 46 *
44 47 * @since 1.0.0
45 48 */
46 - protected function _register_post_type() {
49 + protected function _register_post_type(): void {
47 50 /**
48 - * Filter the "Custom Post Type" that TablePress uses for storing tables in the database.
51 + * Filters the "Custom Post Type" that TablePress uses for storing tables in the database.
49 52 *
50 53 * @since 1.0.0
51 54 *
52 - * @param string $post_type The "Custom Post Type" that TablePress uses.
55 + * @param lowercase-string&non-empty-string $post_type The "Custom Post Type" that TablePress uses.
53 56 */
54 57 $this->post_type = apply_filters( 'tablepress_post_type', $this->post_type );
55 58 $post_type_args = array(
56 59 'labels' => array(
@@ -65,13 +68,13 @@
65 68 'supports' => array( 'title', 'editor', 'excerpt', 'revisions' ),
66 69 'can_export' => true,
67 70 );
68 71 /**
69 - * Filter the arguments for the registration of the "Custom Post Type" that TablePress uses.
72 + * Filters the arguments for the registration of the "Custom Post Type" that TablePress uses.
70 73 *
71 74 * @since 1.0.0
72 75 *
73 - * @param array $post_type_args Arguments for the registration of the TablePress "Custom Post Type".
76 + * @param array<string, mixed> $post_type_args Arguments for the registration of the TablePress "Custom Post Type".
74 77 */
75 78 $post_type_args = apply_filters( 'tablepress_post_type_args', $post_type_args );
76 79 register_post_type( $this->post_type, $post_type_args );
77 80 }
@@ -76,18 +79,18 @@
76 79 register_post_type( $this->post_type, $post_type_args );
77 80 }
78 81
79 82 /**
80 - * Insert a post with the correct Custom Post Type and default values in the the wp_posts table in the database.
83 + * Inserts a post with the correct Custom Post Type and default values in the wp_posts table in the database.
81 84 *
82 85 * @since 1.0.0
83 86 *
84 - * @param array $post Post to insert.
87 + * @param array<string, mixed> $post Post to insert.
85 88 * @return int|WP_Error Post ID of the inserted post on success, WP_Error on error.
86 89 */
87 - public function insert( array $post ) {
90 + public function insert( array $post ) /* : int|WP_Error */ {
88 91 $default_post = array(
89 - 'ID' => false, // false on new insert, but existing post ID on update
92 + 'ID' => false, // false on new insert, but existing post ID on update.
90 93 'comment_status' => 'closed',
91 94 'ping_status' => 'closed',
92 95 'post_category' => false,
93 96 'post_content' => '',
@@ -106,8 +109,9 @@
106 109
107 110 // Remove balanceTags() from sanitize_post(), as it can destroy the JSON when messing with HTML.
108 111 remove_filter( 'content_save_pre', 'balanceTags', 50 );
109 112 remove_filter( 'excerpt_save_pre', 'balanceTags', 50 );
113 +
110 114 /*
111 115 * Remove possible KSES filtering, as it can destroy the JSON when messing with HTML.
112 116 * KSES filtering is done to table cells individually, when saving.
113 117 */
@@ -114,13 +118,8 @@
114 118 $has_kses = ( false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ) );
115 119 if ( $has_kses ) {
116 120 kses_remove_filters();
117 121 }
118 - // Remove filter that adds `rel="noopener" to <a> HTML tags, but destroys JSON code. See https://core.trac.wordpress.org/ticket/46316.
119 - $has_targeted_link_rel_filters = ( false !== has_filter( 'content_save_pre', 'wp_targeted_link_rel' ) );
120 - if ( $has_targeted_link_rel_filters ) {
121 - wp_remove_targeted_link_rel_filters();
122 - }
123 122
124 123 $post_id = wp_insert_post( $post, true );
125 124
126 125 // Restore removed content filters.
@@ -128,10 +127,12 @@
128 127 add_filter( 'excerpt_save_pre', 'balanceTags', 50 );
129 128 if ( $has_kses ) {
130 129 kses_init_filters();
131 130 }
132 - if ( $has_targeted_link_rel_filters ) {
133 - wp_init_targeted_link_rel_filters();
131 +
132 + // In rare cases, `wp_insert_post()` returns 0 as the post ID, when an error happens, so it's converted to a WP_Error here.
133 + if ( 0 === $post_id ) { // @phpstan-ignore identical.alwaysFalse (False-positive in the PHPStan WordPress stubs.)
134 + return new WP_Error( 'post_insert', '' );
134 135 }
135 136
136 137 return $post_id;
137 138 }
@@ -136,18 +137,18 @@
136 137 return $post_id;
137 138 }
138 139
139 140 /**
140 - * Update an existing post with the correct Custom Post Type and default values in the the wp_posts table in the database.
141 + * Updates an existing post with the correct Custom Post Type and default values in the wp_posts table in the database.
141 142 *
142 143 * @since 1.0.0
143 144 *
144 - * @param array $post Post.
145 + * @param array<string, mixed> $post Post.
145 146 * @return int|WP_Error Post ID of the updated post on success, WP_Error on error.
146 147 */
147 - public function update( array $post ) {
148 + public function update( array $post ) /* : int|WP_Error */ {
148 149 $default_post = array(
149 - 'ID' => false, // false on new insert, but existing post ID on update
150 + 'ID' => false, // false on new insert, but existing post ID on update.
150 151 'comment_status' => 'closed',
151 152 'ping_status' => 'closed',
152 153 'post_category' => false,
153 154 'post_content' => '',
@@ -163,11 +164,12 @@
163 164 $post = array_merge( $default_post, $post );
164 165 // WP expects everything to be slashed.
165 166 $post = wp_slash( $post );
166 167
167 - // Remove balanceTags() from sanitize_post(), as it can destroy the JSON when messing with HTML
168 + // Remove balanceTags() from sanitize_post(), as it can destroy the JSON when messing with HTML.
168 169 remove_filter( 'content_save_pre', 'balanceTags', 50 );
169 170 remove_filter( 'excerpt_save_pre', 'balanceTags', 50 );
171 +
170 172 /*
171 173 * Remove possible KSES filtering, as it can destroy the JSON when messing with HTML.
172 174 * KSES filtering is done to table cells individually, when saving.
173 175 */
@@ -174,13 +176,8 @@
174 176 $has_kses = ( false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ) );
175 177 if ( $has_kses ) {
176 178 kses_remove_filters();
177 179 }
178 - // Remove filter that adds `rel="noopener" to <a> HTML tags, but destroys JSON code. See https://core.trac.wordpress.org/ticket/46316.
179 - $has_targeted_link_rel_filters = ( false !== has_filter( 'content_save_pre', 'wp_targeted_link_rel' ) );
180 - if ( $has_targeted_link_rel_filters ) {
181 - wp_remove_targeted_link_rel_filters();
182 - }
183 180
184 181 $post_id = wp_update_post( $post, true );
185 182
186 183 // Restore removed content filters.
@@ -188,17 +185,14 @@
188 185 add_filter( 'excerpt_save_pre', 'balanceTags', 50 );
189 186 if ( $has_kses ) {
190 187 kses_init_filters();
191 188 }
192 - if ( $has_targeted_link_rel_filters ) {
193 - wp_init_targeted_link_rel_filters();
194 - }
195 189
196 190 return $post_id;
197 191 }
198 192
199 193 /**
200 - * Get a post from the wp_posts table in the database.
194 + * Gets a post from the wp_posts table in the database.
201 195 *
202 196 * @since 1.0.0
203 197 *
204 198 * @param int $post_id Post ID.
@@ -203,9 +197,9 @@
203 197 *
204 198 * @param int $post_id Post ID.
205 199 * @return WP_Post|false Post on success, false on error.
206 200 */
207 - public function get( $post_id ) {
201 + public function get( int $post_id ) /* : WP_Post|false */ {
208 202 $post = get_post( $post_id );
209 203 if ( is_null( $post ) ) {
210 204 return false;
211 205 }
@@ -212,9 +206,9 @@
212 206 return $post;
213 207 }
214 208
215 209 /**
216 - * Delete a post (and all revisions) from the wp_posts table in the database.
210 + * Deletes a post (and all revisions) from the wp_posts table in the database.
217 211 *
218 212 * @since 1.0.0
219 213 *
220 214 * @param int $post_id Post ID.
@@ -219,14 +213,14 @@
219 213 *
220 214 * @param int $post_id Post ID.
221 215 * @return WP_Post|false|null Post data on success, false or null on failure.
222 216 */
223 - public function delete( $post_id ) {
224 - return wp_delete_post( $post_id, true ); // true means force delete, although for CPTs this is automatic in this function
217 + public function delete( int $post_id ) /* : WP_Post|false|null */ {
218 + return wp_delete_post( $post_id, true ); // true means force delete, although for CPTs this is automatic in this function.
225 219 }
226 220
227 221 /**
228 - * Move a post to the trash (if trash is globally enabled), instead of directly deleting the post.
222 + * Moves a post to the trash (if trash is globally enabled), instead of directly deleting the post.
229 223 * (yet unused)
230 224 *
231 225 * @since 1.0.0
232 226 *
@@ -232,27 +226,27 @@
232 226 *
233 227 * @param int $post_id Post ID.
234 228 * @return WP_Post|false|null Post data on success, false or null on failure.
235 229 */
236 - public function trash( $post_id ) {
230 + public function trash( int $post_id ) /* : WP_Post|false|null */ {
237 231 return wp_trash_post( $post_id );
238 232 }
239 233
240 234 /**
241 - * Restore a post from the trash.
235 + * Restores a post from the trash.
242 236 * (yet unused)
243 237 *
244 238 * @since 1.0.0
245 239 *
246 240 * @param int $post_id Post ID.
247 - * @return WP_Post|false Post on success, false on error.
241 + * @return WP_Post|false|null Post on success, false or null on error.
248 242 */
249 - public function untrash( $post_id ) {
243 + public function untrash( int $post_id ) /* : WP_Post|false */ {
250 244 return wp_untrash_post( $post_id );
251 245 }
252 246
253 247 /**
254 - * Load all posts with one query, to prime the cache.
248 + * Loads all posts with one query, to prime the cache.
255 249 *
256 250 * @since 1.0.0
257 251 *
258 252 * @global wpdb $wpdb WordPress database abstraction object.
@@ -257,26 +251,23 @@
257 251 *
258 252 * @global wpdb $wpdb WordPress database abstraction object.
259 253 * @see get_post()
260 254 *
261 - * @param array $all_post_ids List of Post IDs.
255 + * @param int[] $all_post_ids List of Post IDs.
262 256 * @param bool $update_meta_cache Optional. Whether to update the Post Meta Cache (for table options and visibility).
263 257 */
264 - public function load_posts( array $all_post_ids, $update_meta_cache = true ) {
258 + public function load_posts( array $all_post_ids, bool $update_meta_cache = true ): void {
265 259 global $wpdb;
266 260
267 261 // Split post loading, to save memory.
268 - $offset = 0;
269 - $length = 100; // 100 posts at a time
270 - $number_of_posts = count( $all_post_ids );
271 - while ( $offset < $number_of_posts ) {
272 - $post_ids = array_slice( $all_post_ids, $offset, $length );
262 + while ( ! empty( $all_post_ids ) ) {
263 + $post_ids = array_splice( $all_post_ids, 0, 100 ); // Extract 100 posts at a time.
273 264 // Don't load posts that are in the cache already.
274 265 $post_ids = _get_non_cached_ids( $post_ids, 'posts' );
275 266 if ( ! empty( $post_ids ) ) {
276 267 $post_ids_list = implode( ',', $post_ids );
277 268 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
278 - $posts = $wpdb->get_results( "SELECT {$wpdb->posts}.* FROM {$wpdb->posts} WHERE ID IN ({$post_ids_list})" );
269 + $posts = $wpdb->get_results( "SELECT {$wpdb->posts}.* FROM {$wpdb->posts} WHERE ID IN ({$post_ids_list})" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
279 270 update_post_cache( $posts );
280 271 if ( $update_meta_cache ) {
281 272 // Get all post meta data for all table posts, @see get_post_meta().
282 273 update_meta_cache( 'post', $post_ids );
@@ -281,14 +272,13 @@
281 272 // Get all post meta data for all table posts, @see get_post_meta().
282 273 update_meta_cache( 'post', $post_ids );
283 274 }
284 275 }
285 - $offset += $length; // next array_slice() $offset
286 276 }
287 277 }
288 278
289 279 /**
290 - * Count the number of posts with the model's CPT in the wp_posts table in the database.
280 + * Counts the number of posts with the model's CPT in the wp_posts table in the database.
291 281 * (currently for debug only)
292 282 *
293 283 * @since 1.0.0
294 284 *
@@ -293,14 +283,14 @@
293 283 * @since 1.0.0
294 284 *
295 285 * @return int Number of posts.
296 286 */
297 - public function count_posts() {
298 - return array_sum( (array) wp_count_posts( $this->post_type ) ); // original return value is object with the counts for each post_status
287 + public function count_posts(): int {
288 + return array_sum( (array) wp_count_posts( $this->post_type ) ); // Original return value is object with the counts for each post_status.
299 289 }
300 290
301 291 /**
302 - * Add a post meta field to a post.
292 + * Adds a post meta field to a post.
303 293 *
304 294 * @since 1.0.0
305 295 *
306 296 * @param int $post_id ID of the post for which the field shall be added.
@@ -307,12 +297,10 @@
307 297 * @param string $field Name of the post meta field.
308 298 * @param string $value Value of the post meta field (not slashed).
309 299 * @return bool True on success, false on error.
310 300 */
311 - public function add_meta_field( $post_id, $field, $value ) {
312 - // WP expects a slashed value.
313 - $value = wp_slash( $value );
314 - $success = add_post_meta( $post_id, $field, $value, true ); // true means unique
301 + public function add_meta_field( int $post_id, string $field, string $value ): bool {
302 + $success = add_post_meta( $post_id, wp_slash( $field ), wp_slash( $value ), true ); // WP expects slashed values, `true` means unique.
315 303 // Make sure that $success is a boolean, as add_post_meta() returns an ID or false.
316 304 $success = ( false === $success ) ? false : true;
317 305 return $success;
318 306 }
@@ -317,9 +305,9 @@
317 305 return $success;
318 306 }
319 307
320 308 /**
321 - * Update the value of a post meta field of a post.
309 + * Updatse the value of a post meta field of a post.
322 310 *
323 311 * If the field does not yet exist, it is added.
324 312 *
325 313 * @since 1.0.0
@@ -328,9 +316,9 @@
328 316 * @param string $field Name of the post meta field.
329 317 * @param string $value Value of the post meta field (not slashed).
330 318 * @return bool True on success, false on error.
331 319 */
332 - public function update_meta_field( $post_id, $field, $value ) {
320 + public function update_meta_field( int $post_id, string $field, string $value ): bool {
333 321 $prev_value = (string) get_post_meta( $post_id, $field, true );
334 322 // No need to update, if values are equal (also, update_post_meta() would return false for this).
335 323 if ( $prev_value === $value ) {
336 324 return true;
@@ -335,15 +323,13 @@
335 323 if ( $prev_value === $value ) {
336 324 return true;
337 325 }
338 326
339 - // WP expects a slashed value.
340 - $value = wp_slash( $value );
341 - return (bool) update_post_meta( $post_id, $field, $value, $prev_value );
327 + return (bool) update_post_meta( $post_id, wp_slash( $field ), wp_slash( $value ), $prev_value ); // WP expects slashed values.
342 328 }
343 329
344 330 /**
345 - * Get the value of a post meta field of a post.
331 + * Gets the value of a post meta field of a post.
346 332 *
347 333 * @since 1.0.0
348 334 *
349 335 * @param int $post_id ID of the post for which the field shall be retrieved.
@@ -349,14 +335,14 @@
349 335 * @param int $post_id ID of the post for which the field shall be retrieved.
350 336 * @param string $field Name of the post meta field.
351 337 * @return string Value of the meta field.
352 338 */
353 - public function get_meta_field( $post_id, $field ) {
354 - return get_post_meta( $post_id, $field, true ); // true means single value
339 + public function get_meta_field( int $post_id, string $field ): string {
340 + return get_post_meta( $post_id, $field, true ); // `true` means single value.
355 341 }
356 342
357 343 /**
358 - * Delete a post meta field of a post.
344 + * Deletes a post meta field of a post.
359 345 * (yet unused)
360 346 *
361 347 * @since 1.0.0
362 348 *
@@ -363,20 +349,20 @@
363 349 * @param int $post_id ID of the post of which the field shall be deleted.
364 350 * @param string $field Name of the post meta field.
365 351 * @return bool True on success, false on error.
366 352 */
367 - public function delete_meta_field( $post_id, $field ) {
368 - return delete_post_meta( $post_id, $field, true ); // true means single value
353 + public function delete_meta_field( int $post_id, string $field ): bool {
354 + return delete_post_meta( $post_id, wp_slash( $field ) ); // WP expects a slashed value.
369 355 }
370 356
371 357 /**
372 - * Return the Custom Post Type that TablePress uses.
358 + * Returns the Custom Post Type that TablePress uses.
373 359 *
374 360 * @since 1.5.0
375 361 *
376 362 * @return string The used Custom Post Type.
377 363 */
378 - public function get_post_type() {
364 + public function get_post_type(): string {
379 365 return $this->post_type;
380 366 }
381 367
382 368 } // class TablePress_Post_Model