PluginProbe
Stream – Activity Log & Audit Trail / 3.8.2
Stream – Activity Log & Audit Trail v3.8.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 3.8.2, at connectors/class-connector-posts.php

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