PluginProbe
Stream – Activity Log & Audit Trail / 4.0.2
Stream – Activity Log & Audit Trail v4.0.2
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
stream / connectors / class-connector-posts.php

class-connector-posts.php in Stream – Activity Log & Audit Trail 4.0.2, at connectors/class-connector-posts.php

416 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Connector for Posts
4 *
5 * @package WP_Stream
6 */
7
8 namespace WP_Stream;
9
10 /**
11 * Class - Connector_Posts
12 */
13 class Connector_Posts extends Connector {
14 /**
15 * Connector slug
16 *
17 * @var string
18 */
19 public $name = 'posts';
20
21 /**
22 * Actions registered for this connector
23 *
24 * @var array
25 */
26 public $actions = array(
27 'transition_post_status',
28 'deleted_post',
29 );
30
31 /**
32 * Return translated connector label
33 *
34 * @return string Translated connector label
35 */
36 public function get_label() {
37 return esc_html__( 'Posts', 'stream' );
38 }
39
40 /**
41 * Return translated action labels
42 *
43 * @return array Action label translations
44 */
45 public function get_action_labels() {
46 return array(
47 'updated' => esc_html__( 'Updated', 'stream' ),
48 'created' => esc_html__( 'Created', 'stream' ),
49 'trashed' => esc_html__( 'Trashed', 'stream' ),
50 'untrashed' => esc_html__( 'Restored', 'stream' ),
51 'deleted' => esc_html__( 'Deleted', 'stream' ),
52 );
53 }
54
55 /**
56 * Return translated context labels
57 *
58 * @return array Context label translations
59 */
60 public function get_context_labels() {
61 global $wp_post_types;
62
63 $post_types = wp_filter_object_list( $wp_post_types, array(), null, 'label' );
64 $post_types = array_diff_key( $post_types, array_flip( $this->get_excluded_post_types() ) );
65
66 add_action( 'registered_post_type', array( $this, 'registered_post_type' ), 10, 2 );
67
68 return $post_types;
69 }
70
71 /**
72 * Add action links to Stream drop row in admin list screen
73 *
74 * @filter wp_stream_action_links_{connector}
75 *
76 * @param array $links Previous links registered.
77 * @param Record $record Stream record.
78 *
79 * @return array Action links
80 */
81 public function action_links( $links, $record ) {
82 $post = get_post( $record->object_id );
83
84 if ( $post && $post->post_status === $record->get_meta( 'new_status', true ) ) {
85 $post_type_name = $this->get_post_type_name( get_post_type( $post->ID ) );
86
87 if ( 'trash' === $post->post_status ) {
88 $untrash = wp_nonce_url(
89 add_query_arg(
90 array(
91 'action' => 'untrash',
92 'post' => $post->ID,
93 ),
94 admin_url( 'post.php' )
95 ),
96 sprintf( 'untrash-post_%d', $post->ID )
97 );
98
99 $delete = wp_nonce_url(
100 add_query_arg(
101 array(
102 'action' => 'delete',
103 'post' => $post->ID,
104 ),
105 admin_url( 'post.php' )
106 ),
107 sprintf( 'delete-post_%d', $post->ID )
108 );
109
110 /* translators: %s: a post type singular name (e.g. "Post") */
111 $links[ sprintf( esc_html_x( 'Restore %s', 'Post type singular name', 'stream' ), $post_type_name ) ] = $untrash;
112 /* translators: %s: a post type singular name (e.g. "Post") */
113 $links[ sprintf( esc_html_x( 'Delete %s Permanently', 'Post type singular name', 'stream' ), $post_type_name ) ] = $delete;
114 } else {
115 /* translators: %s a post type singular name (e.g. "Post") */
116 $links[ sprintf( esc_html_x( 'Edit %s', 'Post type singular name', 'stream' ), $post_type_name ) ] = get_edit_post_link( $post->ID );
117
118 $view_link = get_permalink( $post->ID );
119 if ( $view_link ) {
120 $links[ esc_html__( 'View', 'stream' ) ] = $view_link;
121 }
122
123 $revision_id = absint( $record->get_meta( 'revision_id', true ) );
124 $revision_id = $this->get_adjacent_post_revision( $revision_id, false );
125
126 if ( $revision_id ) {
127 $links[ esc_html__( 'Revision', 'stream' ) ] = get_edit_post_link( $revision_id );
128 }
129 }
130 }
131
132 return $links;
133 }
134
135 /**
136 * Catch registration of post_types after initial loading, to cache its labels
137 *
138 * @action registered_post_type
139 *
140 * @param string $post_type Post type slug.
141 * @param array $args Arguments used to register the post type.
142 */
143 public function registered_post_type( $post_type, $args ) {
144 unset( $args );
145
146 $post_type_obj = get_post_type_object( $post_type );
147 $label = $post_type_obj->label;
148
149 wp_stream_get_instance()->connectors->term_labels['stream_context'][ $post_type ] = $label;
150 }
151
152 /**
153 * Log all post status changes ( creating / updating / trashing )
154 *
155 * @action transition_post_status
156 *
157 * @param mixed $new_status New status.
158 * @param mixed $old_status Old status.
159 * @param \WP_Post $post Post object.
160 */
161 public function callback_transition_post_status( $new_status, $old_status, $post ) {
162 if ( in_array( $post->post_type, $this->get_excluded_post_types(), true ) ) {
163 return;
164 }
165
166 $start_statuses = array( 'auto-draft', 'inherit', 'new' );
167 if ( in_array( $new_status, $start_statuses, true ) ) {
168 return;
169 } elseif ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
170 return;
171 } elseif ( 'draft' === $new_status && 'publish' === $old_status ) {
172 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
173 $summary = _x(
174 '"%1$s" %2$s unpublished',
175 '1: Post title, 2: Post type singular name',
176 'stream'
177 );
178 } elseif ( 'trash' === $old_status && 'trash' !== $new_status ) {
179 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
180 $summary = _x(
181 '"%1$s" %2$s restored from trash',
182 '1: Post title, 2: Post type singular name',
183 'stream'
184 );
185 $action = 'untrashed';
186 } elseif ( 'draft' === $new_status && 'draft' === $old_status ) {
187 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
188 $summary = _x(
189 '"%1$s" %2$s draft saved',
190 '1: Post title, 2: Post type singular name',
191 'stream'
192 );
193 } elseif ( 'publish' === $new_status && ! in_array( $old_status, array( 'future', 'publish' ), true ) ) {
194 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
195 $summary = _x(
196 '"%1$s" %2$s published',
197 '1: Post title, 2: Post type singular name',
198 'stream'
199 );
200 } elseif ( 'draft' === $new_status ) {
201 /* translators: %1$s: a post title, %2$s a post type singular name (e.g. "Hello World", "Post") */
202 $summary = _x(
203 '"%1$s" %2$s drafted',
204 '1: Post title, 2: Post type singular name',
205 'stream'
206 );
207 } elseif ( 'pending' === $new_status ) {
208 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
209 $summary = _x(
210 '"%1$s" %2$s pending review',
211 '1: Post title, 2: Post type singular name',
212 'stream'
213 );
214 } elseif ( 'future' === $new_status ) {
215 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
216 $summary = _x(
217 '"%1$s" %2$s scheduled for %3$s',
218 '1: Post title, 2: Post type singular name, 3: Scheduled post date',
219 'stream'
220 );
221 } elseif ( 'future' === $old_status && 'publish' === $new_status ) {
222 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
223 $summary = _x(
224 '"%1$s" scheduled %2$s published',
225 '1: Post title, 2: Post type singular name',
226 'stream'
227 );
228 } elseif ( 'private' === $new_status ) {
229 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
230 $summary = _x(
231 '"%1$s" %2$s privately published',
232 '1: Post title, 2: Post type singular name',
233 'stream'
234 );
235 } elseif ( 'trash' === $new_status ) {
236 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
237 $summary = _x(
238 '"%1$s" %2$s trashed',
239 '1: Post title, 2: Post type singular name',
240 'stream'
241 );
242 $action = 'trashed';
243 } else {
244 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
245 $summary = _x(
246 '"%1$s" %2$s updated',
247 '1: Post title, 2: Post type singular name',
248 'stream'
249 );
250 }
251
252 if ( in_array( $old_status, $start_statuses, true ) && ! in_array( $new_status, $start_statuses, true ) ) {
253 $action = 'created';
254 }
255
256 if ( empty( $action ) ) {
257 $action = 'updated';
258 }
259
260 $revision_id = null;
261
262 if ( wp_revisions_enabled( $post ) ) {
263 $revision = get_children(
264 array(
265 'post_type' => 'revision',
266 'post_status' => 'inherit',
267 'post_parent' => $post->ID,
268 'posts_per_page' => 1, // VIP safe.
269 'orderby' => 'post_date',
270 'order' => 'DESC',
271 )
272 );
273
274 if ( $revision ) {
275 $revision = array_values( $revision );
276 $revision_id = $revision[0]->ID;
277 }
278 }
279
280 $post_type_name = strtolower( $this->get_post_type_name( $post->post_type ) );
281
282 $this->log(
283 $summary,
284 array(
285 'post_title' => $post->post_title,
286 'singular_name' => $post_type_name,
287 'post_date' => $post->post_date,
288 'post_date_gmt' => $post->post_date_gmt,
289 'new_status' => $new_status,
290 'old_status' => $old_status,
291 'revision_id' => $revision_id,
292 ),
293 $post->ID,
294 $post->post_type,
295 $action
296 );
297 }
298
299 /**
300 * Log post deletion
301 *
302 * @action deleted_post
303 *
304 * @param integer $post_id Post ID.
305 */
306 public function callback_deleted_post( $post_id ) {
307 $post = get_post( $post_id );
308
309 // We check if post is an instance of WP_Post as it doesn't always resolve in unit testing.
310 if ( ! ( $post instanceof \WP_Post ) || in_array( $post->post_type, $this->get_excluded_post_types(), true ) ) {
311 return;
312 }
313
314 // Ignore auto-drafts that are deleted by the system, see issue-293.
315 if ( 'auto-draft' === $post->post_status ) {
316 return;
317 }
318
319 $post_type_name = strtolower( $this->get_post_type_name( $post->post_type ) );
320
321 $this->log(
322 /* translators: %1$s: a post title, %2$s: a post type singular name (e.g. "Hello World", "Post") */
323 _x(
324 '"%1$s" %2$s deleted from trash',
325 '1: Post title, 2: Post type singular name',
326 'stream'
327 ),
328 array(
329 'post_title' => $post->post_title,
330 'singular_name' => $post_type_name,
331 ),
332 $post->ID,
333 $post->post_type,
334 'deleted'
335 );
336 }
337
338 /**
339 * Constructs list of excluded post types for the Posts connector
340 *
341 * @return array List of excluded post types
342 */
343 public function get_excluded_post_types() {
344 return apply_filters(
345 'wp_stream_posts_exclude_post_types',
346 array(
347 'nav_menu_item',
348 'attachment',
349 'revision',
350 )
351 );
352 }
353
354 /**
355 * Gets the singular post type label
356 *
357 * @param string $post_type_slug Post type slug.
358 *
359 * @return string Post type label
360 */
361 public function get_post_type_name( $post_type_slug ) {
362 $name = esc_html__( 'Post', 'stream' ); // Default.
363
364 if ( post_type_exists( $post_type_slug ) ) {
365 $post_type = get_post_type_object( $post_type_slug );
366 $name = $post_type->labels->singular_name;
367 }
368
369 return $name;
370 }
371
372 /**
373 * Get an adjacent post revision ID
374 *
375 * @param int $revision_id Revision ID.
376 * @param bool $previous Has there been any revision before this one?.
377 *
378 * @return int $revision_id
379 */
380 public function get_adjacent_post_revision( $revision_id, $previous = true ) {
381 if ( empty( $revision_id ) || ! wp_is_post_revision( $revision_id ) ) {
382 return false;
383 }
384
385 $revision = wp_get_post_revision( $revision_id );
386 $operator = ( $previous ) ? '<' : '>';
387 $order = ( $previous ) ? 'DESC' : 'ASC';
388
389 global $wpdb;
390 // @codingStandardsIgnoreStart
391 $revision_id = $wpdb->get_var( // db call okay
392 $wpdb->prepare(
393 "SELECT p.ID
394 FROM $wpdb->posts AS p
395 WHERE p.post_date {$operator} %s
396 AND p.post_type = 'revision'
397 AND p.post_parent = %d
398 ORDER BY p.post_date {$order}
399 LIMIT 1",
400 $revision->post_date,
401 $revision->post_parent
402 )
403 );
404 // @codingStandardsIgnoreEnd
405 // prepare okay
406
407 $revision_id = absint( $revision_id );
408
409 if ( ! wp_is_post_revision( $revision_id ) ) {
410 return false;
411 }
412
413 return $revision_id;
414 }
415 }
416