PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.2.4
Jetpack – WP Security, Backup, Speed, & Growth v13.2.4
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 / _inc / blogging-prompts.php
jetpack / _inc Last commit date
blocks 2 years ago build 2 years ago fonts 3 years ago genericons 6 years ago lib 2 years ago social-logos 2 years ago accessible-focus.js 6 years ago blogging-prompts.php 2 years ago class.jetpack-provision.php 2 years ago crowdsignal-shortcode.js 3 years ago crowdsignal-survey.js 6 years ago facebook-embed.js 4 years ago gallery-settings.js 6 years ago genericons.php 5 years ago jetpack-admin.js 3 years ago jetpack-deactivate-dialog.js 6 years ago jetpack-modules.js 3 years ago jetpack-modules.models.js 3 years ago jetpack-modules.views.js 3 years ago jetpack-server-sandbox.php 4 years ago polldaddy-shortcode.js 3 years ago social-logos.php 3 years ago twitter-timeline.js 6 years ago
blogging-prompts.php
269 lines
1 <?php
2 /**
3 * Used by the blogging prompt feature.
4 *
5 * @package automattic/jetpack
6 */
7
8 /**
9 * Hooked functions.
10 */
11
12 /**
13 * Adds the blogging prompt key post meta to the list of allowed post meta to be updated by rest api.
14 *
15 * @param array $keys Array of post meta keys that are allowed public metadata.
16 *
17 * @return array
18 */
19 function jetpack_blogging_prompts_add_meta_data( $keys ) {
20 $keys[] = '_jetpack_blogging_prompt_key';
21 return $keys;
22 }
23
24 add_filter( 'rest_api_allowed_public_metadata', 'jetpack_blogging_prompts_add_meta_data' );
25
26 /**
27 * Sets up a new post as an answer to a blogging prompt.
28 *
29 * When we know a user is explicitly answering a prompt, pre-populate the post meta to mark the post as a prompt response,
30 * in case they decide to remove the block from the post content, preventing they meta from being added later.
31 *
32 * Called on `wp_insert_post` hook.
33 *
34 * @param int $post_id ID of post being inserted.
35 * @return void
36 */
37 function jetpack_setup_blogging_prompt_response( $post_id ) {
38 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Clicking a prompt response link can happen from notifications, Calypso, wp-admin, email, etc and only sets up a response post (tag, meta, prompt text); the user must take action to actually publish the post.
39 $prompt_id = isset( $_GET['answer_prompt'] ) && absint( $_GET['answer_prompt'] ) ? absint( $_GET['answer_prompt'] ) : false;
40
41 if ( ! jetpack_is_new_post_screen() || ! $prompt_id ) {
42 return;
43 }
44
45 // Make sure the prompt exists.
46 $prompt = jetpack_get_blogging_prompt_by_id( $prompt_id );
47
48 if ( $prompt ) {
49 update_post_meta( $post_id, '_jetpack_blogging_prompt_key', $prompt_id );
50 wp_add_post_tags( $post_id, array( 'dailyprompt', "dailyprompt-$prompt_id" ) );
51 if ( array_key_exists( 'bloganuary_id', $prompt ) ) {
52 wp_add_post_tags( $post_id, array( 'bloganuary', $prompt['bloganuary_id'] ) );
53 }
54 }
55 }
56
57 add_action( 'wp_insert_post', 'jetpack_setup_blogging_prompt_response' );
58
59 /**
60 * When a published posts answers a blogging prompt, store the prompt id in the post meta.
61 *
62 * @param int $post_id Post ID.
63 * @param WP_Post $post Post object.
64 * @param bool $update Whether this is an existing post being updated.
65 * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior
66 * to the update for updated posts.
67 */
68 function jetpack_mark_if_post_answers_blogging_prompt( $post_id, $post, $update, $post_before ) {
69 if ( ! $post instanceof WP_Post ) {
70 return;
71 }
72
73 $post_type = isset( $post->post_type ) ? $post->post_type : null;
74 $post_content = isset( $post->post_content ) ? $post->post_content : null;
75
76 if ( 'post' !== $post_type || ! $post_content ) {
77 return;
78 }
79
80 $new_status = isset( $post->post_status ) ? $post->post_status : null;
81 $old_status = $post_before && isset( $post_before->post_status ) ? $post_before->post_status : null;
82
83 // Make sure we are publishing a post, and it's not already published.
84 if ( 'publish' !== $new_status || 'publish' === $old_status ) {
85 return;
86 }
87
88 $blocks = parse_blocks( $post->post_content );
89 foreach ( $blocks as $block ) {
90 if ( 'jetpack/blogging-prompt' === $block['blockName'] ) {
91 $prompt_id = isset( $block['attrs']['promptId'] ) ? absint( $block['attrs']['promptId'] ) : null;
92 $has_prompt_tag = has_tag( 'dailyprompt', $post ) || ( $prompt_id && has_tag( "dailyprompt-{$prompt_id}", $post ) );
93
94 if ( $prompt_id && $has_prompt_tag && count( $blocks ) > 1 ) {
95 update_post_meta( $post->ID, '_jetpack_blogging_prompt_key', $prompt_id );
96 }
97
98 break;
99 }
100 }
101 }
102
103 add_action( 'wp_after_insert_post', 'jetpack_mark_if_post_answers_blogging_prompt', 10, 4 );
104
105 /**
106 * Utility functions.
107 */
108
109 /**
110 * Retrieve a blogging prompt by prompt ID.
111 *
112 * @param int $prompt_id ID of the prompt fetch.
113 * @return stdClass|null Prompt object or null.
114 */
115 function jetpack_get_blogging_prompt_by_id( $prompt_id ) {
116 // Ensure the REST API endpoint we need is loaded.
117 require_once __DIR__ . '/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v3-endpoint-blogging-prompts.php';
118
119 $locale = get_locale();
120 $route = sprintf( '/wpcom/v3/blogging-prompts/%d', $prompt_id );
121
122 $request = new WP_REST_Request( 'GET', $route );
123 $request->set_param( '_locale', $locale );
124 $request->set_param( 'force_year', gmdate( 'Y' ) );
125
126 $response = rest_do_request( $request );
127
128 if ( $response->is_error() || WP_Http::OK !== $response->get_status() ) {
129 return null;
130 }
131
132 $prompt = $response->get_data();
133
134 return $prompt;
135 }
136
137 /**
138 * Retrieve daily blogging prompts from the wpcom API and cache them.
139 *
140 * @param int $time Unix timestamp representing the day for which to get blogging prompts.
141 * @return stdClass[]|null Array of blogging prompt objects or null.
142 */
143 function jetpack_get_daily_blogging_prompts( $time = 0 ) {
144 $timestamp = $time ? $time : time();
145
146 // Include prompts from the previous day, just in case someone has an outdated prompt id.
147 $day_before = wp_date( 'Y-m-d', $timestamp - DAY_IN_SECONDS );
148 $locale = get_locale();
149 $transient_key = 'jetpack_blogging_prompt_' . $day_before . '_' . $locale;
150 $daily_prompts = get_transient( $transient_key );
151
152 // Return the cached prompt, if we have it. Otherwise fetch it from the API.
153 if ( false !== $daily_prompts ) {
154 return $daily_prompts;
155 }
156
157 $blog_id = \Jetpack_Options::get_option( 'id' );
158 $path = '/sites/' . rawurldecode( $blog_id ) . '/blogging-prompts?from=' . rawurldecode( $day_before ) . '&number=10&_locale=' . rawurldecode( $locale );
159
160 $args = array(
161 'headers' => array(
162 'Content-Type' => 'application/json',
163 'X-Forwarded-For' => ( new \Automattic\Jetpack\Status\Visitor() )->get_ip( true ),
164 ),
165 // `method` and `url` are needed for using `WPCOM_API_Direct::do_request`
166 // `wpcom_json_api_request_as_user` will generate and overwrite these.
167 'method' => \WP_REST_Server::READABLE,
168 'url' => JETPACK__WPCOM_JSON_API_BASE . '/wpcom/v2' . $path,
169 );
170
171 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
172 // This will load the library, but it may be too late to automatically load any endpoints using WPCOM_API_Direct::register_endpoints.
173 // In that case, call `wpcom_rest_api_v2_load_plugin_files( 'wp-content/rest-api-plugins/endpoints/blogging-prompts.php' )`
174 // on the `init` hook to load the blogging-prompts endpoint before calling this function.
175 require_once WP_CONTENT_DIR . '/lib/wpcom-api-direct/wpcom-api-direct.php';
176 $response = \WPCOM_API_Direct::do_request( $args );
177 } else {
178 $response = \Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user( $path, 'v2', $args, null, 'wpcom' );
179 }
180 $response_status = wp_remote_retrieve_response_code( $response );
181
182 if ( is_wp_error( $response ) || $response_status !== \WP_Http::OK ) {
183 return null;
184 }
185
186 $body = json_decode( wp_remote_retrieve_body( $response ) );
187
188 if ( ! $body || ! isset( $body->prompts ) ) {
189 return null;
190 }
191
192 $prompts = $body->prompts;
193 set_transient( $transient_key, $prompts, DAY_IN_SECONDS );
194
195 return $prompts;
196 }
197
198 /**
199 * Determines if the site has publish posts or plans to publish posts.
200 *
201 * @return bool
202 */
203 function jetpack_has_or_will_publish_posts() {
204 // Lets count the posts.
205 $count_posts_object = wp_count_posts( 'post' );
206 $count_posts = (int) $count_posts_object->publish + (int) $count_posts_object->future + (int) $count_posts_object->draft;
207
208 return $count_posts_object->publish >= 2 || $count_posts >= 100;
209 }
210
211 /**
212 * Determines if the site has a posts page or shows posts on the front page.
213 *
214 * @return bool
215 */
216 function jetpack_has_posts_page() {
217 // The site is set up to be a blog.
218 if ( 'posts' === get_option( 'show_on_front' ) ) {
219 return true;
220 }
221
222 // There is a page set to show posts.
223 $is_posts_page_set = (int) get_option( 'page_for_posts' ) > 0;
224 if ( $is_posts_page_set ) {
225 return true;
226 }
227
228 return false;
229 }
230
231 /**
232 * Determines if site had the "Write" intent set when created.
233 *
234 * @return bool
235 */
236 function jetpack_has_write_intent() {
237 return 'write' === get_option( 'site_intent', '' );
238 }
239
240 /**
241 * Determines if the current screen (in wp-admin) is creating a new post.
242 *
243 * /wp-admin/post-new.php
244 *
245 * @return bool
246 */
247 function jetpack_is_new_post_screen() {
248 global $current_screen;
249
250 if (
251 $current_screen instanceof \WP_Screen &&
252 'add' === $current_screen->action &&
253 'post' === $current_screen->post_type
254 ) {
255 return true;
256 }
257
258 return false;
259 }
260
261 /**
262 * Determines if the site might have a blog.
263 *
264 * @return bool
265 */
266 function jetpack_is_potential_blogging_site() {
267 return jetpack_has_write_intent() || jetpack_has_posts_page() || jetpack_has_or_will_publish_posts();
268 }
269