PluginProbe
TablePress – Tables in WordPress made easy / 2.0.4
TablePress – Tables in WordPress made easy v2.0.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 2.4.4 All 44 releases
tablepress / models / model-post.php

model-post.php in TablePress – Tables in WordPress made easy 2.0.4, at models/model-post.php

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