Completed
Push — add/copy-a-post ( bb2565...1e1608 )
by Kirk
07:31 queued 23s
created

Jetpack_Copy_Post::update_post_format()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Module Name: Copy Post
4
 * Module Description: Copy an existing post's content into a new post.
5
 * Jumpstart Description: Copy an existing post's content into a new post.
6
 * Sort Order: 15
7
 * First Introduced: 6.9
8
 * Requires Connection: No
9
 * Auto Activate: No
10
 * Module Tags: Writing
11
 * Feature: Writing
12
 * Additional Search Queries: copy, duplicate
13
 */
14
15
class Jetpack_Copy_Post {
16
17
    /**
18
     * Jetpack_Copy_Post_By_Param constructor.
19
     * Add row actions to post/page/CPT listing screens.
20
     * Process any `?copy` param if on a create new post/page/CPT screen.
21
     *
22
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
23
     */
24
    function __construct() {
25
        if ( 'edit.php' === $GLOBALS[ 'pagenow' ] ) {
26
            add_filter( 'post_row_actions', array( $this, 'add_row_action' ), 10, 2 );
27
            add_filter( 'page_row_actions', array( $this, 'add_row_action' ), 10, 2 );
28
            return;
29
        }
30
31
        if ( ! empty( $_GET[ 'copy' ] ) && 'post-new.php' === $GLOBALS[ 'pagenow' ] ) {
32
            add_action( 'wp_insert_post', array( $this, 'update_post_data' ), 10, 3 );
33
        }
34
    }
35
36
    /**
37
     * Update the new (target) post data with the source post data.
38
     *
39
     * @param int     $target_post_id Target post ID.
40
	 * @param WP_Post $post           Target post object (not used).
41
	 * @param bool    $update         Whether this is an existing post being updated or not.
42
     * @return void
43
     */
44
    function update_post_data( $target_post_id, $post, $update ) {
45
        // This avoids infinite loops of trying to update our updated post.
46
        if ( $update ) {
47
            return;
48
        }
49
50
        $source_post = get_post( $_GET['copy'] );
51
        if ( ! $source_post || ! $this->user_can_edit_post( $source_post ) ) {
52
            return;
53
        }
54
55
        $update_content = $this->update_content_and_taxonomies( $source_post, $target_post_id );
56
        $update_featured_image = $this->update_featured_image( $source_post, $target_post_id );
57
        $update_post_format = $this->update_post_format( $source_post, $target_post_id );
58
59
        // Required to satify get_default_post_to_edit(), which has these filters after post creation.
60
        add_filter( 'default_title', array( $this, 'filter_title' ), 10, 2 );
61
        add_filter( 'default_content', array( $this, 'filter_content' ), 10, 2 );
62
        add_filter( 'default_excerpt', array( $this, 'filter_excerpt' ), 10, 2 );
63
64
        do_action( 'jetpack_copy_post', $source_post, $target_post_id, $update_content, $update_featured_image, $update_post_format );
65
    }
66
67
    /**
68
     * Determine if the current user has access to the source post.
69
     *
70
	 * @param WP_Post $post Source post object (the post being copied).
71
     * @return bool         True if current user is the post author, or has permissions for `edit_others_posts`; false otherwise.
72
     */
73
    protected function user_can_edit_post( $post ) {
74
        return get_current_user_id() === (int) $post->post_author || current_user_can( 'edit_others_posts' );
75
    }
76
77
    /**
78
     * Update the target post's title, content, excerpt, categories, and tags.
79
     *
80
	 * @param WP_Post $source_post Post object to be copied.
81
     * @param int     $target_post_id Target post ID.
82
     * @return int    0 on failure, or the updated post ID on success.
83
     */
84
    protected function update_content_and_taxonomies( $source_post, $target_post_id ) {
85
        $data = apply_filters( 'jetpack_copy_post_data', array(
86
            'ID' => $target_post_id,
87
            'post_title' => $source_post->post_title,
88
            'post_content' => $source_post->post_content,
89
            'post_excerpt' => $source_post->post_excerpt,
90
            'post_category' => $source_post->post_category,
91
            'tags_input' => $source_post->tags_input,
92
        ) );
93
        return wp_update_post( $data );
94
    }
95
96
    /**
97
     * Update the target post's featured image.
98
     *
99
	 * @param WP_Post   $source_post Post object to be copied.
100
     * @param int       $target_post_id Target post ID.
101
     * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
102
     */
103
    protected function update_featured_image( $source_post, $target_post_id ) {
104
        $featured_image_id = get_post_thumbnail_id( $source_post );
105
        return update_post_meta( $target_post_id, '_thumbnail_id', $featured_image_id );
106
    }
107
108
    /**
109
     * Update the target post's post format.
110
     *
111
     * @param WP_Post               $source_post Post object to be copied.
112
     * @param int                   $target_post_id Target post ID.
113
     * @return array|WP_Error|false WP_Error on error, array of affected term IDs on success.
114
     */
115
    protected function update_post_format( $source_post, $target_post_id ) {
116
        $post_format = get_post_format( $source_post );
117
        return set_post_format( $target_post_id, $post_format );
118
    }
119
120
    /**
121
     * Update the target post's title.
122
     *
123
     * @param string  $post_title Post title determined by `get_default_post_to_edit()`.
124
     * @param WP_Post $post       Post object of newly-inserted post.
125
     * @return string             Updated post title from source post.
126
     */
127
    function filter_title( $post_title, $post ) {
128
        return $post->post_title;
129
    }
130
131
    /**
132
     * Update the target post's content (`post_content`).
133
     *
134
     * @param string  $post_content Post content determined by `get_default_post_to_edit()`.
135
     * @param WP_Post $post         Post object of newly-inserted post.
136
     * @return string               Updated post content from source post.
137
     */
138
    function filter_content( $post_content, $post ) {
139
        return $post->post_content;
140
    }
141
142
    /**
143
     * Update the target post's excerpt.
144
     *
145
     * @param string  $post_excerpt Post excerpt determined by `get_default_post_to_edit()`.
146
     * @param WP_Post $post         Post object of newly-inserted post.
147
     * @return string               Updated post excerpt from source post.
148
     */
149
    function filter_excerpt( $post_excerpt, $post ) {
150
        return $post->post_excerpt;
151
    }
152
153
    /**
154
     * Add a "Copy" row action to posts/pages/CPTs on list views.
155
     *
156
     * @param array   $actions Existing actions.
157
     * @param WP_Post $post    Post object of current post in list.
158
     * @return array           Array of updated row actions.
159
     */
160
    function add_row_action( $actions, $post ) {
161
        $edit_url = add_query_arg( array(
162
            'post_type' => $post->post_type,
163
            'copy' => $post->ID,
164
            '_wpnonce' => wp_create_nonce( 'jetpack-copy-post' ),
165
        ), admin_url( 'post-new.php' ) );
166
        $edit_action = array(
167
            'copy' => sprintf(
168
                '<a href="%s" aria-label="%s">%s</a>',
169
                esc_url( $edit_url ),
170
                esc_attr( __( 'Copy this post.' ) ),
171
                __( 'Copy' )
172
            ),
173
        );
174
175
        // Insert the Copy action before the Trash action.
176
        $edit_offset = array_search( 'trash', array_keys( $actions ), true );
177
        $actions = array_merge(
178
            array_slice( $actions, 0, $edit_offset ),
179
            $edit_action,
180
            array_slice( $actions, $edit_offset )
181
        );
182
183
        return $actions;
184
    }
185
}
186
187
function jetpack_copy_post_init() {
188
    new Jetpack_Copy_Post();
189
}
190
add_action( 'admin_init', 'jetpack_copy_post_init' );
191