PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.0.3
Jetpack – WP Security, Backup, Speed, & Growth v12.0.3
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 3 years ago class.wpcom-json-api-add-widget-endpoint.php 3 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 4 years ago class.wpcom-json-api-comment-endpoint.php 4 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 3 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 4 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 3 years ago class.wpcom-json-api-get-post-counts-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-post-endpoint.php 4 years ago class.wpcom-json-api-get-post-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-site-endpoint.php 3 years ago class.wpcom-json-api-get-site-v1-2-endpoint.php 3 years ago class.wpcom-json-api-get-taxonomies-endpoint.php 4 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 3 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 4 years ago class.wpcom-json-api-list-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-list-media-v1-2-endpoint.php 3 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 4 years ago class.wpcom-json-api-list-shortcodes-endpoint.php 4 years ago class.wpcom-json-api-list-terms-endpoint.php 4 years ago class.wpcom-json-api-list-users-endpoint.php 3 years ago class.wpcom-json-api-menus-v1-1-endpoint.php 4 years ago class.wpcom-json-api-post-endpoint.php 3 years ago class.wpcom-json-api-post-v1-1-endpoint.php 3 years ago class.wpcom-json-api-render-embed-endpoint.php 4 years ago class.wpcom-json-api-render-embed-reversal-endpoint.php 4 years ago class.wpcom-json-api-render-endpoint.php 3 years ago class.wpcom-json-api-render-shortcode-endpoint.php 4 years ago class.wpcom-json-api-sharing-buttons-endpoint.php 3 years ago class.wpcom-json-api-site-settings-endpoint.php 3 years ago class.wpcom-json-api-site-settings-v1-2-endpoint.php 3 years ago class.wpcom-json-api-site-settings-v1-3-endpoint.php 3 years ago class.wpcom-json-api-site-settings-v1-4-endpoint.php 3 years ago class.wpcom-json-api-site-user-endpoint.php 4 years ago class.wpcom-json-api-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-comment-endpoint.php 3 years ago class.wpcom-json-api-update-customcss.php 4 years ago class.wpcom-json-api-update-media-endpoint.php 4 years ago class.wpcom-json-api-update-media-v1-1-endpoint.php 4 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 3 years ago class.wpcom-json-api-update-site-homepage-endpoint.php 4 years ago class.wpcom-json-api-update-site-logo-endpoint.php 4 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 4 years ago class.wpcom-json-api-upload-media-endpoint.php 4 years ago class.wpcom-json-api-upload-media-v1-1-endpoint.php 3 years ago
class.wpcom-json-api-post-endpoint.php
758 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 Twitter and 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 case 'twitter':
395 foreach ( $data as $datum ) {
396 $publicize_urls[] = esc_url_raw( "https://twitter.com/{$datum['user_id']}/status/{$datum['post_id']}" );
397 }
398 break;
399 case 'fb':
400 foreach ( $data as $datum ) {
401 $publicize_urls[] = esc_url_raw( "https://www.facebook.com/permalink.php?story_fbid={$datum['post_id']}&id={$datum['user_id']}" );
402 }
403 break;
404 }
405 }
406 }
407 $response[ $key ] = (array) $publicize_urls;
408 break;
409 case 'tags':
410 $response[ $key ] = array();
411 $terms = wp_get_post_tags( $post->ID );
412 foreach ( $terms as $term ) {
413 if ( ! empty( $term->name ) ) {
414 $response[ $key ][ $term->name ] = $this->format_taxonomy( $term, 'post_tag', 'display' );
415 }
416 }
417 $response[ $key ] = (object) $response[ $key ];
418 break;
419 case 'categories':
420 $response[ $key ] = array();
421 $terms = wp_get_object_terms( $post->ID, 'category', array( 'fields' => 'all' ) );
422 foreach ( $terms as $term ) {
423 if ( ! empty( $term->name ) ) {
424 $response[ $key ][ $term->name ] = $this->format_taxonomy( $term, 'category', 'display' );
425 }
426 }
427 $response[ $key ] = (object) $response[ $key ];
428 break;
429 case 'attachments':
430 $response[ $key ] = array();
431 $_attachments = get_posts(
432 array(
433 'post_parent' => $post->ID,
434 'post_status' => 'inherit',
435 'post_type' => 'attachment',
436 'posts_per_page' => 100,
437 )
438 );
439 foreach ( $_attachments as $attachment ) {
440 $response[ $key ][ $attachment->ID ] = $this->get_attachment( $attachment );
441 }
442 $response[ $key ] = (object) $response[ $key ];
443 break;
444 /** (array|false) */
445 case 'metadata':
446 $metadata = array();
447 foreach ( (array) has_meta( $post_id ) as $meta ) {
448 // Don't expose protected fields.
449 $show = false;
450 if ( WPCOM_JSON_API_Metadata::is_public( $meta['meta_key'] ) ) {
451 $show = true;
452 }
453 if ( current_user_can( 'edit_post_meta', $post_id, $meta['meta_key'] ) ) {
454 $show = true;
455 }
456
457 if (
458 in_array( $meta['meta_key'], Jetpack_SEO_Posts::POST_META_KEYS_ARRAY, true ) &&
459 ! Jetpack_SEO_Utils::is_enabled_jetpack_seo()
460 ) {
461 $show = false;
462 }
463
464 if ( ! $show ) {
465 continue;
466 }
467
468 $metadata[] = array(
469 'id' => $meta['meta_id'],
470 'key' => $meta['meta_key'],
471 'value' => maybe_unserialize( $meta['meta_value'] ),
472 );
473 }
474
475 if ( ! empty( $metadata ) ) {
476 $response[ $key ] = $metadata;
477 } else {
478 $response[ $key ] = false;
479 }
480 break;
481 case 'meta':
482 $response[ $key ] = (object) array(
483 'links' => (object) array(
484 'self' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ),
485 'help' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'help' ),
486 'site' => (string) $this->links->get_site_link( $this->api->get_blog_id_for_output() ),
487 'replies' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'replies/' ),
488 'likes' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'likes/' ),
489 ),
490 );
491 break;
492 case 'current_user_can':
493 $response[ $key ] = $capabilities;
494 break;
495 case 'capabilities':
496 $response[ $key ] = $capabilities;
497 break;
498
499 }
500 }
501
502 unset( $GLOBALS['post'] );
503 return $response;
504 }
505
506 /**
507 *
508 * Get the post content for display.
509 *
510 * No Blog ID parameter. No Post ID parameter. Depends on globals.
511 * Expects setup_postdata() to already have been run.
512 *
513 * @return string|false
514 */
515 public function get_the_post_content_for_display() {
516 global $pages, $page;
517
518 $old_pages = $pages;
519 $old_page = $page;
520
521 $content = join( "\n\n", $pages );
522 $content = preg_replace( '/<!--more(.*?)?-->/', '', $content );
523 $pages = array( $content ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
524 $page = 1; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
525
526 ob_start();
527 the_content();
528 $return = ob_get_clean();
529
530 $pages = $old_pages; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
531 $page = $old_page; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
532
533 return $return;
534 }
535
536 /**
537 * Gets the blog post.
538 *
539 * @param int $blog_id - the blog ID.
540 * @param int $post_id - the post ID.
541 * @param string $context - the context.
542 * @return array|bool|WP_Error Post
543 */
544 public function get_blog_post( $blog_id, $post_id, $context = 'display' ) {
545 $blog_id = $this->api->get_blog_id( $blog_id );
546 if ( ! $blog_id || is_wp_error( $blog_id ) ) {
547 return $blog_id;
548 }
549 switch_to_blog( $blog_id );
550 $post = $this->get_post_by( 'ID', $post_id, $context );
551 restore_current_blog();
552 return $post;
553 }
554
555 /**
556 * Supporting featured media in post endpoints. Currently on for wpcom blogs
557 * since it's calling WPCOM_JSON_API_Read_Endpoint methods which presently
558 * rely on wpcom specific functionality.
559 *
560 * @param WP_Post $post - the WP Post object.
561 * @return object list of featured media
562 */
563 public static function find_featured_media( &$post ) {
564
565 if ( class_exists( 'WPCOM_JSON_API_Read_Endpoint' ) ) {
566 return WPCOM_JSON_API_Read_Endpoint::find_featured_worthy_media( (array) $post );
567 } else {
568 return (object) array();
569 }
570 }
571
572 /**
573 * Win8 Gallery shortcode.
574 *
575 * @param array $attr - the attribute.
576 */
577 public function win8_gallery_shortcode( $attr ) {
578 global $post;
579
580 static $instance = 0;
581 ++$instance;
582
583 // @todo - find out if this is a bug, intentionally unused, or can be removed.
584 $output = ''; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
585
586 // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
587 if ( isset( $attr['orderby'] ) ) {
588 $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
589 if ( ! $attr['orderby'] ) {
590 unset( $attr['orderby'] );
591 }
592 }
593
594 $atts = shortcode_atts(
595 array(
596 'order' => 'ASC',
597 'orderby' => 'menu_order ID',
598 'id' => $post->ID,
599 'include' => '',
600 'exclude' => '',
601 'slideshow' => false,
602 ),
603 $attr,
604 'gallery'
605 );
606 $id = ! empty( $atts['id'] ) ? (int) $atts['id'] : 0;
607
608 // Custom image size and always use it.
609 add_image_size( 'win8app-column', 480 );
610 $size = 'win8app-column';
611
612 if ( 'RAND' === $atts['order'] ) {
613 $orderby = 'none';
614 } else {
615 $orderby = $atts['orderby'];
616 }
617
618 if ( ! empty( $atts['include'] ) ) {
619 $include = preg_replace( '/[^0-9,]+/', '', $atts['include'] );
620 $_attachments = get_posts(
621 array(
622 'include' => $include,
623 'post_status' => 'inherit',
624 'post_type' => 'attachment',
625 'post_mime_type' => 'image',
626 'order' => $atts['order'],
627 'orderby' => $orderby,
628 )
629 );
630 $attachments = array();
631 foreach ( $_attachments as $key => $val ) {
632 $attachments[ $val->ID ] = $_attachments[ $key ];
633 }
634 } elseif ( ! empty( $atts['exclude'] ) ) {
635 $exclude = preg_replace( '/[^0-9,]+/', '', $atts['exclude'] );
636 $attachments = get_children(
637 array(
638 'post_parent' => $id,
639 'exclude' => $exclude,
640 'post_status' => 'inherit',
641 'post_type' => 'attachment',
642 'post_mime_type' => 'image',
643 'order' => $atts['order'],
644 'orderby' => $orderby,
645 )
646 );
647 } else {
648 $attachments = get_children(
649 array(
650 'post_parent' => $id,
651 'post_status' => 'inherit',
652 'post_type' => 'attachment',
653 'post_mime_type' => 'image',
654 'order' => $atts['order'],
655 'orderby' => $orderby,
656 )
657 );
658 }
659
660 if ( ! empty( $attachments ) ) {
661 foreach ( $attachments as $id => $attachment ) {
662 $link = isset( $attr['link'] ) && 'file' === $attr['link']
663 ? wp_get_attachment_link( $id, $size, false, false )
664 : wp_get_attachment_link( $id, $size, true, false );
665 // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
666 if ( $captiontag && trim( $attachment->post_excerpt ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
667 $output .= "<div class='wp-caption aligncenter'>$link
668 <p class='wp-caption-text'>" . wptexturize( $attachment->post_excerpt ) . '</p>
669 </div>';
670 } else {
671 $output .= $link . ' ';
672 }
673 // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
674 }
675 }
676 }
677
678 /**
679 * Returns attachment object.
680 *
681 * @param object - $attachment attachment row.
682 *
683 * @return object
684 */
685 public function get_attachment( $attachment ) {
686 $metadata = wp_get_attachment_metadata( $attachment->ID );
687
688 $result = array(
689 'ID' => (int) $attachment->ID,
690 'URL' => (string) wp_get_attachment_url( $attachment->ID ),
691 'guid' => (string) $attachment->guid,
692 'mime_type' => (string) $attachment->post_mime_type,
693 'width' => (int) isset( $metadata['width'] ) ? $metadata['width'] : 0,
694 'height' => (int) isset( $metadata['height'] ) ? $metadata['height'] : 0,
695 );
696
697 if ( isset( $metadata['duration'] ) ) {
698 $result['duration'] = (int) $metadata['duration'];
699 }
700
701 return (object) apply_filters( 'get_attachment', $result );
702 }
703
704 /**
705 * Get post-specific user capabilities
706 *
707 * @param WP_Post $post - the WP_Post object.
708 *
709 * @return array - array of post-level permissions; 'publish_post', 'delete_post', 'edit_post'
710 */
711 public function get_current_user_capabilities( $post ) {
712 return array(
713 'publish_post' => current_user_can( 'publish_post', $post->ID ),
714 'delete_post' => current_user_can( 'delete_post', $post->ID ),
715 'edit_post' => current_user_can( 'edit_post', $post->ID ),
716 );
717 }
718
719 /**
720 * Get post ID by name
721 *
722 * Attempts to match name on post title and page path
723 *
724 * @param string $name - the name of the post.
725 *
726 * @return int|object Post ID on success, WP_Error object on failure
727 **/
728 protected function get_post_id_by_name( $name ) {
729 $name = sanitize_title( $name );
730
731 if ( ! $name ) {
732 return new WP_Error( 'invalid_post', 'Invalid post', 400 );
733 }
734
735 $posts = get_posts(
736 array(
737 'name' => $name,
738 'numberposts' => 1,
739 'post_type' => $this->_get_whitelisted_post_types(),
740 )
741 );
742
743 if ( ! $posts || ! isset( $posts[0]->ID ) || ! $posts[0]->ID ) {
744 $page = get_page_by_path( $name );
745
746 if ( ! $page ) {
747 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
748 }
749
750 $post_id = $page->ID;
751 } else {
752 $post_id = (int) $posts[0]->ID;
753 }
754
755 return $post_id;
756 }
757 }
758