PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.1.5
Jetpack – WP Security, Backup, Speed, & Growth v13.1.5
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / json-endpoints / class.wpcom-json-api-post-endpoint.php
jetpack / json-endpoints Last commit date
jetpack 2 years ago class.wpcom-json-api-add-widget-endpoint.php 2 years ago class.wpcom-json-api-autosave-post-v1-1-endpoint.php 5 years ago class.wpcom-json-api-bulk-delete-post-endpoint.php 4 years ago class.wpcom-json-api-bulk-restore-post-endpoint.php 4 years ago class.wpcom-json-api-bulk-update-comments-endpoint.php 3 years ago class.wpcom-json-api-comment-endpoint.php 2 years ago class.wpcom-json-api-delete-media-endpoint.php 4 years ago class.wpcom-json-api-delete-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-edit-media-v1-2-endpoint.php 2 years ago class.wpcom-json-api-get-autosave-v1-1-endpoint.php 5 years ago class.wpcom-json-api-get-comment-counts-endpoint.php 4 years ago class.wpcom-json-api-get-comment-endpoint.php 4 years ago class.wpcom-json-api-get-comment-history-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php 4 years ago class.wpcom-json-api-get-customcss.php 2 years ago class.wpcom-json-api-get-media-endpoint.php 4 years ago class.wpcom-json-api-get-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-media-v1-2-endpoint.php 2 years ago class.wpcom-json-api-get-post-counts-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-post-endpoint.php 2 years ago class.wpcom-json-api-get-post-v1-1-endpoint.php 2 years ago class.wpcom-json-api-get-site-endpoint.php 2 years ago class.wpcom-json-api-get-site-v1-2-endpoint.php 2 years ago class.wpcom-json-api-get-taxonomies-endpoint.php 2 years ago class.wpcom-json-api-get-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-get-term-endpoint.php 4 years ago class.wpcom-json-api-list-comments-endpoint.php 2 years ago class.wpcom-json-api-list-dropdown-pages-endpoint.php 3 years ago class.wpcom-json-api-list-embeds-endpoint.php 4 years ago class.wpcom-json-api-list-media-endpoint.php 2 years ago class.wpcom-json-api-list-media-v1-1-endpoint.php 2 years ago class.wpcom-json-api-list-media-v1-2-endpoint.php 2 years ago class.wpcom-json-api-list-post-type-taxonomies-endpoint.php 4 years ago class.wpcom-json-api-list-post-types-endpoint.php 3 years ago class.wpcom-json-api-list-posts-endpoint.php 3 years ago class.wpcom-json-api-list-posts-v1-1-endpoint.php 3 years ago class.wpcom-json-api-list-posts-v1-2-endpoint.php 3 years ago class.wpcom-json-api-list-roles-endpoint.php 2 years ago class.wpcom-json-api-list-shortcodes-endpoint.php 4 years ago class.wpcom-json-api-list-terms-endpoint.php 2 years ago class.wpcom-json-api-list-users-endpoint.php 2 years ago class.wpcom-json-api-menus-v1-1-endpoint.php 2 years ago class.wpcom-json-api-post-endpoint.php 3 years ago class.wpcom-json-api-post-v1-1-endpoint.php 2 years ago class.wpcom-json-api-render-embed-endpoint.php 2 years ago class.wpcom-json-api-render-embed-reversal-endpoint.php 2 years ago class.wpcom-json-api-render-endpoint.php 3 years ago class.wpcom-json-api-render-shortcode-endpoint.php 3 years ago class.wpcom-json-api-sharing-buttons-endpoint.php 2 years ago class.wpcom-json-api-site-settings-endpoint.php 2 years ago class.wpcom-json-api-site-settings-v1-2-endpoint.php 2 years ago class.wpcom-json-api-site-settings-v1-3-endpoint.php 2 years ago class.wpcom-json-api-site-settings-v1-4-endpoint.php 2 years ago class.wpcom-json-api-site-user-endpoint.php 2 years ago class.wpcom-json-api-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-comment-endpoint.php 2 years ago class.wpcom-json-api-update-customcss.php 2 years ago class.wpcom-json-api-update-media-endpoint.php 4 years ago class.wpcom-json-api-update-media-v1-1-endpoint.php 2 years ago class.wpcom-json-api-update-post-endpoint.php 3 years ago class.wpcom-json-api-update-post-v1-1-endpoint.php 3 years ago class.wpcom-json-api-update-post-v1-2-endpoint.php 2 years ago class.wpcom-json-api-update-site-homepage-endpoint.php 4 years ago class.wpcom-json-api-update-site-logo-endpoint.php 2 years ago class.wpcom-json-api-update-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-term-endpoint.php 4 years ago class.wpcom-json-api-update-user-endpoint.php 3 years ago class.wpcom-json-api-upload-media-endpoint.php 3 years ago class.wpcom-json-api-upload-media-v1-1-endpoint.php 2 years ago
class.wpcom-json-api-post-endpoint.php
759 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 /**
4 * Post Endpoint class.
5 */
6 abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint {
7 /**
8 * Post object format.
9 *
10 * @var array
11 */
12 public $post_object_format = array(
13 // explicitly document and cast all output
14 'ID' => '(int) The post ID.',
15 'site_ID' => '(int) The site ID.',
16 'author' => '(object>author) The author of the post.',
17 'date' => "(ISO 8601 datetime) The post's creation time.",
18 'modified' => "(ISO 8601 datetime) The post's most recent update time.",
19 'title' => '(HTML) <code>context</code> dependent.',
20 'URL' => '(URL) The full permalink URL to the post.',
21 'short_URL' => '(URL) The wp.me short URL.',
22 'content' => '(HTML) <code>context</code> dependent.',
23 'excerpt' => '(HTML) <code>context</code> dependent.',
24 'slug' => '(string) The name (slug) for the post, used in URLs.',
25 'guid' => '(string) The GUID for the post.',
26 'status' => array(
27 'publish' => 'The post is published.',
28 'draft' => 'The post is saved as a draft.',
29 'pending' => 'The post is pending editorial approval.',
30 'private' => 'The post is published privately',
31 'future' => 'The post is scheduled for future publishing.',
32 'trash' => 'The post is in the trash.',
33 'auto-draft' => 'The post is a placeholder for a new post.',
34 ),
35 'sticky' => '(bool) Is the post sticky?',
36 'password' => '(string) The plaintext password protecting the post, or, more likely, the empty string if the post is not password protected.',
37 'parent' => "(object>post_reference|false) A reference to the post's parent, if it has one.",
38 'type' => "(string) The post's post_type. Post types besides post, page and revision need to be whitelisted using the <code>rest_api_allowed_post_types</code> filter.",
39 'comments_open' => '(bool) Is the post open for comments?',
40 'pings_open' => '(bool) Is the post open for pingbacks, trackbacks?',
41 'likes_enabled' => '(bool) Is the post open to likes?',
42 'sharing_enabled' => '(bool) Should sharing buttons show on this post?',
43 'comment_count' => '(int) The number of comments for this post.',
44 'like_count' => '(int) The number of likes for this post.',
45 'i_like' => '(bool) Does the current user like this post?',
46 'is_reblogged' => '(bool) Did the current user reblog this post?',
47 'is_following' => '(bool) Is the current user following this blog?',
48 'global_ID' => '(string) A unique WordPress.com-wide representation of a post.',
49 'featured_image' => '(URL) The URL to the featured image for this post if it has one.',
50 'post_thumbnail' => '(object>attachment) The attachment object for the featured image if it has one.',
51 'format' => array(), // see constructor
52 'geo' => '(object>geo|false)',
53 'menu_order' => '(int) (Pages Only) The order pages should appear in.',
54 'publicize_URLs' => '(array:URL) Array of Facebook URLs published by this post.',
55 'tags' => '(object:tag) Hash of tags (keyed by tag name) applied to the post.',
56 'categories' => '(object:category) Hash of categories (keyed by category name) applied to the post.',
57 'attachments' => '(object:attachment) Hash of post attachments (keyed by attachment ID).',
58 'metadata' => '(array) Array of post metadata keys and values. All unprotected meta keys are available by default for read requests. Both unprotected and protected meta keys are available for authenticated requests with access. Protected meta keys can be made available with the <code>rest_api_allowed_public_metadata</code> filter.',
59 'meta' => '(object) API result meta data',
60 'current_user_can' => '(object) List of permissions. Note, deprecated in favor of `capabilities`',
61 'capabilities' => '(object) List of post-specific permissions for the user; publish_post, edit_post, delete_post',
62 );
63
64 /**
65 * Constructor function.
66 *
67 * @param string|array|object $args — Args.
68 */
69 public function __construct( $args ) {
70 if ( is_array( $this->post_object_format ) && isset( $this->post_object_format['format'] ) ) {
71 $this->post_object_format['format'] = get_post_format_strings();
72 }
73 if ( ! $this->response_format ) {
74 $this->response_format =& $this->post_object_format;
75 }
76 parent::__construct( $args );
77 }
78
79 /**
80 * Filter to replace the password form with a simple message that the post is protected.
81 *
82 * @return string
83 */
84 public function the_password_form() {
85 return __( 'This post is password protected.', 'jetpack' );
86 }
87
88 /**
89 * Get a post by a specified field and value
90 *
91 * @param string $field - the field.
92 * @param string $field_value - the field value.
93 * @param string $context Post use context (e.g. 'display').
94 * @return array|bool|WP_Error Post
95 **/
96 public function get_post_by( $field, $field_value, $context = 'display' ) {
97 global $blog_id;
98
99 /** This filter is documented in class.json-api-endpoints.php */
100 $is_jetpack = true === apply_filters( 'is_jetpack_site', false, $blog_id );
101
102 if ( defined( 'GEO_LOCATION__CLASS' ) && class_exists( GEO_LOCATION__CLASS ) ) {
103 $geo = call_user_func( array( GEO_LOCATION__CLASS, 'init' ) );
104 } else {
105 $geo = false;
106 }
107
108 if ( 'display' === $context ) {
109 $args = $this->query_args();
110 if ( isset( $args['content_width'] ) && $args['content_width'] ) {
111 $GLOBALS['content_width'] = (int) $args['content_width'];
112 }
113 }
114
115 if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && strpos( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ), 'wp-windows8' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- we're not using this value and making changes, just checking if it exists.
116 remove_shortcode( 'gallery', 'gallery_shortcode' );
117 add_shortcode( 'gallery', array( $this, 'win8_gallery_shortcode' ) );
118 }
119
120 switch ( $field ) {
121 case 'name':
122 $post_id = $this->get_post_id_by_name( $field_value );
123 if ( is_wp_error( $post_id ) ) {
124 return $post_id;
125 }
126 break;
127 default:
128 $post_id = (int) $field_value;
129 break;
130 }
131
132 $post = get_post( $post_id, OBJECT, $context );
133
134 if ( ! $post || is_wp_error( $post ) ) {
135 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
136 }
137
138 if ( ! $this->is_post_type_allowed( $post->post_type ) && ( ! function_exists( 'is_post_freshly_pressed' ) || ! is_post_freshly_pressed( $post->ID ) ) ) {
139 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
140 }
141
142 // Permissions
143 $capabilities = $this->get_current_user_capabilities( $post );
144
145 switch ( $context ) {
146 case 'edit':
147 if ( ! $capabilities['edit_post'] ) {
148 return new WP_Error( 'unauthorized', 'User cannot edit post', 403 );
149 }
150 break;
151 case 'display':
152 break;
153 default:
154 return new WP_Error( 'invalid_context', 'Invalid API CONTEXT', 400 );
155 }
156
157 $can_view = $this->user_can_view_post( $post->ID );
158 if ( ! $can_view || is_wp_error( $can_view ) ) {
159 return $can_view;
160 }
161
162 $GLOBALS['post'] = $post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
163
164 if ( 'display' === $context ) {
165 setup_postdata( $post );
166 }
167
168 $response = array();
169
170 $fields = null;
171 if ( 'display' === $context && ! empty( $this->api->query['fields'] ) ) {
172 $fields = array_fill_keys( array_map( 'trim', explode( ',', $this->api->query['fields'] ) ), true );
173 }
174
175 foreach ( array_keys( $this->post_object_format ) as $key ) {
176 if ( $fields !== null && ! isset( $fields[ $key ] ) ) {
177 continue;
178 }
179 switch ( $key ) {
180 case 'ID':
181 // explicitly cast all output
182 $response[ $key ] = (int) $post->ID;
183 break;
184 case 'site_ID':
185 $response[ $key ] = (int) $this->api->get_blog_id_for_output();
186 break;
187 case 'author':
188 $response[ $key ] = (object) $this->get_author( $post, 'edit' === $context && $capabilities['edit_post'] );
189 break;
190 case 'date':
191 $response[ $key ] = (string) $this->format_date( $post->post_date_gmt, $post->post_date );
192 break;
193 case 'modified':
194 $response[ $key ] = (string) $this->format_date( $post->post_modified_gmt, $post->post_modified );
195 break;
196 case 'title':
197 if ( 'display' === $context ) {
198 $response[ $key ] = (string) get_the_title( $post->ID );
199 } else {
200 $response[ $key ] = (string) htmlspecialchars_decode( $post->post_title, ENT_QUOTES );
201 }
202 break;
203 case 'URL':
204 if ( 'revision' === $post->post_type ) {
205 $response[ $key ] = (string) esc_url_raw( get_permalink( $post->post_parent ) );
206 } else {
207 $response[ $key ] = (string) esc_url_raw( get_permalink( $post->ID ) );
208 }
209 break;
210 case 'short_URL':
211 $response[ $key ] = (string) esc_url_raw( wp_get_shortlink( $post->ID ) );
212 break;
213 case 'content':
214 if ( 'display' === $context ) {
215 add_filter( 'the_password_form', array( $this, 'the_password_form' ) );
216 $response[ $key ] = (string) $this->get_the_post_content_for_display();
217 remove_filter( 'the_password_form', array( $this, 'the_password_form' ) );
218 } else {
219 $response[ $key ] = (string) $post->post_content;
220 }
221 break;
222 case 'excerpt':
223 if ( 'display' === $context ) {
224 add_filter( 'the_password_form', array( $this, 'the_password_form' ) );
225 ob_start();
226 the_excerpt();
227 $response[ $key ] = (string) ob_get_clean();
228 remove_filter( 'the_password_form', array( $this, 'the_password_form' ) );
229 } else {
230 $response[ $key ] = htmlspecialchars_decode( (string) $post->post_excerpt, ENT_QUOTES );
231 }
232 break;
233 case 'status':
234 $response[ $key ] = (string) get_post_status( $post->ID );
235 break;
236 case 'sticky':
237 $response[ $key ] = (bool) is_sticky( $post->ID );
238 break;
239 case 'slug':
240 $response[ $key ] = (string) $post->post_name;
241 break;
242 case 'guid':
243 $response[ $key ] = (string) $post->guid;
244 break;
245 case 'password':
246 $response[ $key ] = (string) $post->post_password;
247 if ( 'edit' === $context ) {
248 $response[ $key ] = htmlspecialchars_decode( (string) $response[ $key ], ENT_QUOTES );
249 }
250 break;
251 /** (object|false) */
252 case 'parent':
253 if ( $post->post_parent ) {
254 $parent = get_post( $post->post_parent );
255 if ( 'display' === $context ) {
256 $parent_title = (string) get_the_title( $parent->ID );
257 } else {
258 $parent_title = (string) htmlspecialchars_decode( $post->post_title, ENT_QUOTES );
259 }
260 $response[ $key ] = (object) array(
261 'ID' => (int) $parent->ID,
262 'type' => (string) $parent->post_type,
263 'link' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $parent->ID ),
264 'title' => $parent_title,
265 );
266 } else {
267 $response[ $key ] = false;
268 }
269 break;
270 case 'type':
271 $response[ $key ] = (string) $post->post_type;
272 break;
273 case 'comments_open':
274 $response[ $key ] = (bool) comments_open( $post->ID );
275 break;
276 case 'pings_open':
277 $response[ $key ] = (bool) pings_open( $post->ID );
278 break;
279 case 'likes_enabled':
280 /** This filter is documented in modules/likes.php */
281 $sitewide_likes_enabled = (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) );
282 $post_likes_switched = get_post_meta( $post->ID, 'switch_like_status', true );
283 $post_likes_enabled = $post_likes_switched || ( $sitewide_likes_enabled && $post_likes_switched !== '0' );
284 $response[ $key ] = (bool) $post_likes_enabled;
285 break;
286 case 'sharing_enabled':
287 $show = true;
288 /** This filter is documented in modules/sharedaddy/sharing-service.php */
289 $show = apply_filters( 'sharing_show', $show, $post );
290
291 $switched_status = get_post_meta( $post->ID, 'sharing_disabled', false );
292
293 if ( ! empty( $switched_status ) ) {
294 $show = false;
295 }
296 $response[ $key ] = (bool) $show;
297 break;
298 case 'comment_count':
299 $response[ $key ] = (int) $post->comment_count;
300 break;
301 case 'like_count':
302 $response[ $key ] = (int) $this->api->post_like_count( $blog_id, $post->ID );
303 break;
304 case 'i_like':
305 $response[ $key ] = (bool) $this->api->is_liked( $blog_id, $post->ID );
306 break;
307 case 'is_reblogged':
308 $response[ $key ] = (bool) $this->api->is_reblogged( $blog_id, $post->ID );
309 break;
310 case 'is_following':
311 $response[ $key ] = (bool) $this->api->is_following( $blog_id );
312 break;
313 case 'global_ID':
314 $response[ $key ] = (string) $this->api->add_global_ID( $blog_id, $post->ID );
315 break;
316 case 'featured_image':
317 if ( $is_jetpack && ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
318 $response[ $key ] = get_post_meta( $post->ID, '_jetpack_featured_image', true );
319 } else {
320 $image_attributes = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'full' );
321 if ( is_array( $image_attributes ) && isset( $image_attributes[0] ) ) {
322 $response[ $key ] = (string) $image_attributes[0];
323 } else {
324 $response[ $key ] = '';
325 }
326 }
327 break;
328 case 'post_thumbnail':
329 $response[ $key ] = null;
330
331 $thumb_id = get_post_thumbnail_id( $post->ID );
332 if ( ! empty( $thumb_id ) ) {
333 $attachment = get_post( $thumb_id );
334 if ( ! empty( $attachment ) ) {
335 $featured_image_object = $this->get_attachment( $attachment );
336 }
337
338 if ( ! empty( $featured_image_object ) ) {
339 $response[ $key ] = (object) $featured_image_object;
340 }
341 }
342 break;
343 case 'format':
344 $response[ $key ] = (string) get_post_format( $post->ID );
345 if ( ! $response[ $key ] ) {
346 $response[ $key ] = 'standard';
347 }
348 break;
349 /** (object|false) */
350 case 'geo':
351 if ( ! $geo ) {
352 $response[ $key ] = false;
353 } else {
354 $geo_data = $geo->get_geo( 'post', $post->ID );
355 $response[ $key ] = false;
356 if ( $geo_data ) {
357 $geo_data = array_intersect_key(
358 $geo_data,
359 array(
360 'latitude' => true,
361 'longitude' => true,
362 'address' => true,
363 'public' => true,
364 )
365 );
366 if ( $geo_data ) {
367 $response[ $key ] = (object) array(
368 'latitude' => isset( $geo_data['latitude'] ) ? (float) $geo_data['latitude'] : 0,
369 'longitude' => isset( $geo_data['longitude'] ) ? (float) $geo_data['longitude'] : 0,
370 'address' => isset( $geo_data['address'] ) ? (string) $geo_data['address'] : '',
371 );
372 } else {
373 $response[ $key ] = false;
374 }
375 // Private
376 if ( ! isset( $geo_data['public'] ) || ! $geo_data['public'] ) {
377 if ( 'edit' !== $context || ! $capabilities['edit_post'] ) {
378 // user can't access
379 $response[ $key ] = false;
380 }
381 }
382 }
383 }
384 break;
385 case 'menu_order':
386 $response[ $key ] = (int) $post->menu_order;
387 break;
388 case 'publicize_URLs':
389 $publicize_urls = array();
390 $publicize = get_post_meta( $post->ID, 'publicize_results', true );
391 if ( $publicize ) {
392 foreach ( $publicize as $service => $data ) {
393 switch ( $service ) {
394 // @todo Explore removing once Twitter has been removed from Publicize.
395 case 'twitter':
396 foreach ( $data as $datum ) {
397 $publicize_urls[] = esc_url_raw( "https://twitter.com/{$datum['user_id']}/status/{$datum['post_id']}" );
398 }
399 break;
400 case 'fb':
401 foreach ( $data as $datum ) {
402 $publicize_urls[] = esc_url_raw( "https://www.facebook.com/permalink.php?story_fbid={$datum['post_id']}&id={$datum['user_id']}" );
403 }
404 break;
405 }
406 }
407 }
408 $response[ $key ] = (array) $publicize_urls;
409 break;
410 case 'tags':
411 $response[ $key ] = array();
412 $terms = wp_get_post_tags( $post->ID );
413 foreach ( $terms as $term ) {
414 if ( ! empty( $term->name ) ) {
415 $response[ $key ][ $term->name ] = $this->format_taxonomy( $term, 'post_tag', 'display' );
416 }
417 }
418 $response[ $key ] = (object) $response[ $key ];
419 break;
420 case 'categories':
421 $response[ $key ] = array();
422 $terms = wp_get_object_terms( $post->ID, 'category', array( 'fields' => 'all' ) );
423 foreach ( $terms as $term ) {
424 if ( ! empty( $term->name ) ) {
425 $response[ $key ][ $term->name ] = $this->format_taxonomy( $term, 'category', 'display' );
426 }
427 }
428 $response[ $key ] = (object) $response[ $key ];
429 break;
430 case 'attachments':
431 $response[ $key ] = array();
432 $_attachments = get_posts(
433 array(
434 'post_parent' => $post->ID,
435 'post_status' => 'inherit',
436 'post_type' => 'attachment',
437 'posts_per_page' => 100,
438 )
439 );
440 foreach ( $_attachments as $attachment ) {
441 $response[ $key ][ $attachment->ID ] = $this->get_attachment( $attachment );
442 }
443 $response[ $key ] = (object) $response[ $key ];
444 break;
445 /** (array|false) */
446 case 'metadata':
447 $metadata = array();
448 foreach ( (array) has_meta( $post_id ) as $meta ) {
449 // Don't expose protected fields.
450 $show = false;
451 if ( WPCOM_JSON_API_Metadata::is_public( $meta['meta_key'] ) ) {
452 $show = true;
453 }
454 if ( current_user_can( 'edit_post_meta', $post_id, $meta['meta_key'] ) ) {
455 $show = true;
456 }
457
458 if (
459 in_array( $meta['meta_key'], Jetpack_SEO_Posts::POST_META_KEYS_ARRAY, true ) &&
460 ! Jetpack_SEO_Utils::is_enabled_jetpack_seo()
461 ) {
462 $show = false;
463 }
464
465 if ( ! $show ) {
466 continue;
467 }
468
469 $metadata[] = array(
470 'id' => $meta['meta_id'],
471 'key' => $meta['meta_key'],
472 'value' => maybe_unserialize( $meta['meta_value'] ),
473 );
474 }
475
476 if ( ! empty( $metadata ) ) {
477 $response[ $key ] = $metadata;
478 } else {
479 $response[ $key ] = false;
480 }
481 break;
482 case 'meta':
483 $response[ $key ] = (object) array(
484 'links' => (object) array(
485 'self' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ),
486 'help' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'help' ),
487 'site' => (string) $this->links->get_site_link( $this->api->get_blog_id_for_output() ),
488 'replies' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'replies/' ),
489 'likes' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'likes/' ),
490 ),
491 );
492 break;
493 case 'current_user_can':
494 $response[ $key ] = $capabilities;
495 break;
496 case 'capabilities':
497 $response[ $key ] = $capabilities;
498 break;
499
500 }
501 }
502
503 unset( $GLOBALS['post'] );
504 return $response;
505 }
506
507 /**
508 *
509 * Get the post content for display.
510 *
511 * No Blog ID parameter. No Post ID parameter. Depends on globals.
512 * Expects setup_postdata() to already have been run.
513 *
514 * @return string|false
515 */
516 public function get_the_post_content_for_display() {
517 global $pages, $page;
518
519 $old_pages = $pages;
520 $old_page = $page;
521
522 $content = implode( "\n\n", $pages );
523 $content = preg_replace( '/<!--more(.*?)?-->/', '', $content );
524 $pages = array( $content ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
525 $page = 1; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
526
527 ob_start();
528 the_content();
529 $return = ob_get_clean();
530
531 $pages = $old_pages; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
532 $page = $old_page; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
533
534 return $return;
535 }
536
537 /**
538 * Gets the blog post.
539 *
540 * @param int $blog_id - the blog ID.
541 * @param int $post_id - the post ID.
542 * @param string $context - the context.
543 * @return array|bool|WP_Error Post
544 */
545 public function get_blog_post( $blog_id, $post_id, $context = 'display' ) {
546 $blog_id = $this->api->get_blog_id( $blog_id );
547 if ( ! $blog_id || is_wp_error( $blog_id ) ) {
548 return $blog_id;
549 }
550 switch_to_blog( $blog_id );
551 $post = $this->get_post_by( 'ID', $post_id, $context );
552 restore_current_blog();
553 return $post;
554 }
555
556 /**
557 * Supporting featured media in post endpoints. Currently on for wpcom blogs
558 * since it's calling WPCOM_JSON_API_Read_Endpoint methods which presently
559 * rely on wpcom specific functionality.
560 *
561 * @param WP_Post $post - the WP Post object.
562 * @return object list of featured media
563 */
564 public static function find_featured_media( &$post ) {
565
566 if ( class_exists( 'WPCOM_JSON_API_Read_Endpoint' ) ) {
567 return WPCOM_JSON_API_Read_Endpoint::find_featured_worthy_media( (array) $post );
568 } else {
569 return (object) array();
570 }
571 }
572
573 /**
574 * Win8 Gallery shortcode.
575 *
576 * @param array $attr - the attribute.
577 */
578 public function win8_gallery_shortcode( $attr ) {
579 global $post;
580
581 static $instance = 0;
582 ++$instance;
583
584 // @todo - find out if this is a bug, intentionally unused, or can be removed.
585 $output = ''; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
586
587 // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
588 if ( isset( $attr['orderby'] ) ) {
589 $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
590 if ( ! $attr['orderby'] ) {
591 unset( $attr['orderby'] );
592 }
593 }
594
595 $atts = shortcode_atts(
596 array(
597 'order' => 'ASC',
598 'orderby' => 'menu_order ID',
599 'id' => $post->ID,
600 'include' => '',
601 'exclude' => '',
602 'slideshow' => false,
603 ),
604 $attr,
605 'gallery'
606 );
607 $id = ! empty( $atts['id'] ) ? (int) $atts['id'] : 0;
608
609 // Custom image size and always use it.
610 add_image_size( 'win8app-column', 480 );
611 $size = 'win8app-column';
612
613 if ( 'RAND' === $atts['order'] ) {
614 $orderby = 'none';
615 } else {
616 $orderby = $atts['orderby'];
617 }
618
619 if ( ! empty( $atts['include'] ) ) {
620 $include = preg_replace( '/[^0-9,]+/', '', $atts['include'] );
621 $_attachments = get_posts(
622 array(
623 'include' => $include,
624 'post_status' => 'inherit',
625 'post_type' => 'attachment',
626 'post_mime_type' => 'image',
627 'order' => $atts['order'],
628 'orderby' => $orderby,
629 )
630 );
631 $attachments = array();
632 foreach ( $_attachments as $key => $val ) {
633 $attachments[ $val->ID ] = $_attachments[ $key ];
634 }
635 } elseif ( ! empty( $atts['exclude'] ) ) {
636 $exclude = preg_replace( '/[^0-9,]+/', '', $atts['exclude'] );
637 $attachments = get_children(
638 array(
639 'post_parent' => $id,
640 'exclude' => $exclude,
641 'post_status' => 'inherit',
642 'post_type' => 'attachment',
643 'post_mime_type' => 'image',
644 'order' => $atts['order'],
645 'orderby' => $orderby,
646 )
647 );
648 } else {
649 $attachments = get_children(
650 array(
651 'post_parent' => $id,
652 'post_status' => 'inherit',
653 'post_type' => 'attachment',
654 'post_mime_type' => 'image',
655 'order' => $atts['order'],
656 'orderby' => $orderby,
657 )
658 );
659 }
660
661 if ( ! empty( $attachments ) ) {
662 foreach ( $attachments as $id => $attachment ) {
663 $link = isset( $attr['link'] ) && 'file' === $attr['link']
664 ? wp_get_attachment_link( $id, $size, false, false )
665 : wp_get_attachment_link( $id, $size, true, false );
666 // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
667 if ( $captiontag && trim( $attachment->post_excerpt ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
668 $output .= "<div class='wp-caption aligncenter'>$link
669 <p class='wp-caption-text'>" . wptexturize( $attachment->post_excerpt ) . '</p>
670 </div>';
671 } else {
672 $output .= $link . ' ';
673 }
674 // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
675 }
676 }
677 }
678
679 /**
680 * Returns attachment object.
681 *
682 * @param object - $attachment attachment row.
683 *
684 * @return object
685 */
686 public function get_attachment( $attachment ) {
687 $metadata = wp_get_attachment_metadata( $attachment->ID );
688
689 $result = array(
690 'ID' => (int) $attachment->ID,
691 'URL' => (string) wp_get_attachment_url( $attachment->ID ),
692 'guid' => (string) $attachment->guid,
693 'mime_type' => (string) $attachment->post_mime_type,
694 'width' => (int) isset( $metadata['width'] ) ? $metadata['width'] : 0,
695 'height' => (int) isset( $metadata['height'] ) ? $metadata['height'] : 0,
696 );
697
698 if ( isset( $metadata['duration'] ) ) {
699 $result['duration'] = (int) $metadata['duration'];
700 }
701
702 return (object) apply_filters( 'get_attachment', $result );
703 }
704
705 /**
706 * Get post-specific user capabilities
707 *
708 * @param WP_Post $post - the WP_Post object.
709 *
710 * @return array - array of post-level permissions; 'publish_post', 'delete_post', 'edit_post'
711 */
712 public function get_current_user_capabilities( $post ) {
713 return array(
714 'publish_post' => current_user_can( 'publish_post', $post->ID ),
715 'delete_post' => current_user_can( 'delete_post', $post->ID ),
716 'edit_post' => current_user_can( 'edit_post', $post->ID ),
717 );
718 }
719
720 /**
721 * Get post ID by name
722 *
723 * Attempts to match name on post title and page path
724 *
725 * @param string $name - the name of the post.
726 *
727 * @return int|object Post ID on success, WP_Error object on failure
728 **/
729 protected function get_post_id_by_name( $name ) {
730 $name = sanitize_title( $name );
731
732 if ( ! $name ) {
733 return new WP_Error( 'invalid_post', 'Invalid post', 400 );
734 }
735
736 $posts = get_posts(
737 array(
738 'name' => $name,
739 'numberposts' => 1,
740 'post_type' => $this->_get_whitelisted_post_types(),
741 )
742 );
743
744 if ( ! $posts || ! isset( $posts[0]->ID ) || ! $posts[0]->ID ) {
745 $page = get_page_by_path( $name );
746
747 if ( ! $page ) {
748 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
749 }
750
751 $post_id = $page->ID;
752 } else {
753 $post_id = (int) $posts[0]->ID;
754 }
755
756 return $post_id;
757 }
758 }
759