PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.7.3
Jetpack – WP Security, Backup, Speed, & Growth v12.7.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 / _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 3 years ago class.jetpack-provision.php 2 years ago connect-button.js 3 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-connection-banner.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-recommendations-banner.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
264 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 }
52 }
53
54 add_action( 'wp_insert_post', 'jetpack_setup_blogging_prompt_response' );
55
56 /**
57 * When a published posts answers a blogging prompt, store the prompt id in the post meta.
58 *
59 * @param int $post_id Post ID.
60 * @param WP_Post $post Post object.
61 * @param bool $update Whether this is an existing post being updated.
62 * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior
63 * to the update for updated posts.
64 */
65 function jetpack_mark_if_post_answers_blogging_prompt( $post_id, $post, $update, $post_before ) {
66 if ( ! $post instanceof WP_Post ) {
67 return;
68 }
69
70 $post_type = isset( $post->post_type ) ? $post->post_type : null;
71 $post_content = isset( $post->post_content ) ? $post->post_content : null;
72
73 if ( 'post' !== $post_type || ! $post_content ) {
74 return;
75 }
76
77 $new_status = isset( $post->post_status ) ? $post->post_status : null;
78 $old_status = $post_before && isset( $post_before->post_status ) ? $post_before->post_status : null;
79
80 // Make sure we are publishing a post, and it's not already published.
81 if ( 'publish' !== $new_status || 'publish' === $old_status ) {
82 return;
83 }
84
85 $blocks = parse_blocks( $post->post_content );
86 foreach ( $blocks as $block ) {
87 if ( 'jetpack/blogging-prompt' === $block['blockName'] ) {
88 $prompt_id = isset( $block['attrs']['promptId'] ) ? absint( $block['attrs']['promptId'] ) : null;
89 $has_prompt_tag = has_tag( 'dailyprompt', $post ) || ( $prompt_id && has_tag( "dailyprompt-{$prompt_id}", $post ) );
90
91 if ( $prompt_id && $has_prompt_tag && count( $blocks ) > 1 ) {
92 update_post_meta( $post->ID, '_jetpack_blogging_prompt_key', $prompt_id );
93 }
94
95 break;
96 }
97 }
98 }
99
100 add_action( 'wp_after_insert_post', 'jetpack_mark_if_post_answers_blogging_prompt', 10, 4 );
101
102 /**
103 * Utility functions.
104 */
105
106 /**
107 * Retrieve a blogging prompt by prompt ID.
108 *
109 * @param int $prompt_id ID of the prompt fetch.
110 * @return stdClass|null Prompt object or null.
111 */
112 function jetpack_get_blogging_prompt_by_id( $prompt_id ) {
113 // Ensure the REST API endpoint we need is loaded.
114 require_once __DIR__ . '/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v3-endpoint-blogging-prompts.php';
115
116 $locale = get_locale();
117 $route = sprintf( '/wpcom/v3/blogging-prompts/%d', $prompt_id );
118
119 $request = new WP_REST_Request( 'GET', $route );
120 $request->set_param( '_locale', $locale );
121 $response = rest_do_request( $request );
122
123 if ( $response->is_error() || WP_Http::OK !== $response->get_status() ) {
124 return null;
125 }
126
127 $prompt = $response->get_data();
128
129 return $prompt;
130 }
131
132 /**
133 * Retrieve daily blogging prompts from the wpcom API and cache them.
134 *
135 * @param int $time Unix timestamp representing the day for which to get blogging prompts.
136 * @return stdClass[]|null Array of blogging prompt objects or null.
137 */
138 function jetpack_get_daily_blogging_prompts( $time = 0 ) {
139 $timestamp = $time ? $time : time();
140
141 // Include prompts from the previous day, just in case someone has an outdated prompt id.
142 $day_before = wp_date( 'Y-m-d', $timestamp - DAY_IN_SECONDS );
143 $locale = get_locale();
144 $transient_key = 'jetpack_blogging_prompt_' . $day_before . '_' . $locale;
145 $daily_prompts = get_transient( $transient_key );
146
147 // Return the cached prompt, if we have it. Otherwise fetch it from the API.
148 if ( false !== $daily_prompts ) {
149 return $daily_prompts;
150 }
151
152 $blog_id = \Jetpack_Options::get_option( 'id' );
153 $path = '/sites/' . rawurldecode( $blog_id ) . '/blogging-prompts?from=' . rawurldecode( $day_before ) . '&number=10&_locale=' . rawurldecode( $locale );
154
155 $args = array(
156 'headers' => array(
157 'Content-Type' => 'application/json',
158 'X-Forwarded-For' => ( new \Automattic\Jetpack\Status\Visitor() )->get_ip( true ),
159 ),
160 // `method` and `url` are needed for using `WPCOM_API_Direct::do_request`
161 // `wpcom_json_api_request_as_user` will generate and overwrite these.
162 'method' => \WP_REST_Server::READABLE,
163 'url' => JETPACK__WPCOM_JSON_API_BASE . '/wpcom/v2' . $path,
164 );
165
166 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
167 // This will load the library, but it may be too late to automatically load any endpoints using WPCOM_API_Direct::register_endpoints.
168 // In that case, call `wpcom_rest_api_v2_load_plugin_files( 'wp-content/rest-api-plugins/endpoints/blogging-prompts.php' )`
169 // on the `init` hook to load the blogging-prompts endpoint before calling this function.
170 require_once WP_CONTENT_DIR . '/lib/wpcom-api-direct/wpcom-api-direct.php';
171 $response = \WPCOM_API_Direct::do_request( $args );
172 } else {
173 $response = \Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user( $path, 'v2', $args, null, 'wpcom' );
174 }
175 $response_status = wp_remote_retrieve_response_code( $response );
176
177 if ( is_wp_error( $response ) || $response_status !== \WP_Http::OK ) {
178 return null;
179 }
180
181 $body = json_decode( wp_remote_retrieve_body( $response ) );
182
183 if ( ! $body || ! isset( $body->prompts ) ) {
184 return null;
185 }
186
187 $prompts = $body->prompts;
188 set_transient( $transient_key, $prompts, DAY_IN_SECONDS );
189
190 return $prompts;
191 }
192
193 /**
194 * Determines if the site has publish posts or plans to publish posts.
195 *
196 * @return bool
197 */
198 function jetpack_has_or_will_publish_posts() {
199 // Lets count the posts.
200 $count_posts_object = wp_count_posts( 'post' );
201 $count_posts = (int) $count_posts_object->publish + (int) $count_posts_object->future + (int) $count_posts_object->draft;
202
203 return $count_posts_object->publish >= 2 || $count_posts >= 100;
204 }
205
206 /**
207 * Determines if the site has a posts page or shows posts on the front page.
208 *
209 * @return bool
210 */
211 function jetpack_has_posts_page() {
212 // The site is set up to be a blog.
213 if ( 'posts' === get_option( 'show_on_front' ) ) {
214 return true;
215 }
216
217 // There is a page set to show posts.
218 $is_posts_page_set = (int) get_option( 'page_for_posts' ) > 0;
219 if ( $is_posts_page_set ) {
220 return true;
221 }
222
223 return false;
224 }
225
226 /**
227 * Determines if site had the "Write" intent set when created.
228 *
229 * @return bool
230 */
231 function jetpack_has_write_intent() {
232 return 'write' === get_option( 'site_intent', '' );
233 }
234
235 /**
236 * Determines if the current screen (in wp-admin) is creating a new post.
237 *
238 * /wp-admin/post-new.php
239 *
240 * @return bool
241 */
242 function jetpack_is_new_post_screen() {
243 global $current_screen;
244
245 if (
246 $current_screen instanceof \WP_Screen &&
247 'add' === $current_screen->action &&
248 'post' === $current_screen->post_type
249 ) {
250 return true;
251 }
252
253 return false;
254 }
255
256 /**
257 * Determines if the site might have a blog.
258 *
259 * @return bool
260 */
261 function jetpack_is_potential_blogging_site() {
262 return jetpack_has_write_intent() || jetpack_has_posts_page() || jetpack_has_or_will_publish_posts();
263 }
264