PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.3
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.3
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
← All changes | includes/core/rest-api/Controllers/class-templatelibrary-controller.php +160 -6 3.10.6 → 3.13.3 View file →
@@ -10,8 +10,9 @@
10 10 use WP_Error;
11 11 use WP_REST_Request;
12 12 use WP_REST_Response;
13 13 use WP_REST_Server;
14 +use WPFunnels\Wpfnl;
14 15 use WPFunnels\Wpfnl_functions;
15 16 use WPFunnels\lms\helper\Wpfnl_lms_learndash_functions;
16 17
17 18 /**
@@ -187,10 +188,54 @@
187 188 ),
188 189 )
189 190 );
190 191
192 + /*
193 + * Building a funnel out of a template, and clearing what the library
194 + * has cached. The template library screen is React (see
195 + * src/admin/pages/FunnelTemplates) and talks REST; the Vue library
196 + * still embedded in the funnel canvas and Store Checkout posts the same
197 + * work to admin-ajax, so both routes here hand straight over to the
198 + * handlers those calls already run rather than restating them.
199 + */
191 200 register_rest_route(
192 201 $this->namespace,
202 + '/' . $this->rest_base . 'import-funnel',
203 + array(
204 + array(
205 + 'methods' => WP_REST_Server::CREATABLE,
206 + 'callback' => array( $this, 'import_funnel' ),
207 + 'permission_callback' => array( $this, 'edit_items_permissions_check' ),
208 + ),
209 + )
210 + );
211 +
212 + register_rest_route(
213 + $this->namespace,
214 + '/' . $this->rest_base . 'finish-import',
215 + array(
216 + array(
217 + 'methods' => WP_REST_Server::CREATABLE,
218 + 'callback' => array( $this, 'finish_import' ),
219 + 'permission_callback' => array( $this, 'edit_items_permissions_check' ),
220 + ),
221 + )
222 + );
223 +
224 + register_rest_route(
225 + $this->namespace,
226 + '/' . $this->rest_base . 'sync',
227 + array(
228 + array(
229 + 'methods' => WP_REST_Server::CREATABLE,
230 + 'callback' => array( $this, 'sync_library' ),
231 + 'permission_callback' => array( $this, 'edit_items_permissions_check' ),
232 + ),
233 + )
234 + );
235 +
236 + register_rest_route(
237 + $this->namespace,
193 238 '/' . $this->rest_base . 'get_template_type_id',
194 239 array(
195 240 array(
196 241 'methods' => WP_REST_Server::READABLE,
@@ -217,8 +262,111 @@
217 262 * @param $request
218 263 *
219 264 * @return WP_REST_Response
220 265 */
266 + /**
267 + * Makes sure the current user may build a funnel from a template.
268 + *
269 + * @param WP_REST_Request $request Full data about the request.
270 + *
271 + * @return WP_Error|boolean
272 + * @since 3.13.5
273 + */
274 + public function edit_items_permissions_check( $request ) {
275 + if ( ! Wpfnl_functions::wpfnl_rest_check_manager_permissions( 'templates', 'edit' ) ) {
276 + return new WP_Error( 'wpfunnels_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wpfnl' ), array( 'status' => rest_authorization_required_code() ) );
277 + }
278 + return true;
279 + }
280 +
281 +
282 + /**
283 + * Create a funnel from a library template.
284 + *
285 + * First of the three calls that import a template: this creates the funnel
286 + * post and answers with its id, the steps are then created one by one
287 + * against the step controller, and `finish_import()` below closes the
288 + * import off.
289 + *
290 + * @param WP_REST_Request $request Full data about the request.
291 + *
292 + * @return WP_REST_Response The importer's own response, carrying `funnelID`.
293 + * @since 3.13.5
294 + */
295 + public function import_funnel( $request ) {
296 + $payload = $this->get_import_payload( $request );
297 +
298 + return rest_ensure_response( Wpfnl::$instance->template_manager->import_funnel( $payload ) );
299 + }
300 +
301 +
302 + /**
303 + * Close off a template import.
304 + *
305 + * Answers with the `redirectLink` the caller should follow — where the
306 + * funnel wants to be opened depends on what was imported, so the server
307 + * decides it.
308 + *
309 + * @param WP_REST_Request $request Full data about the request.
310 + *
311 + * @return WP_REST_Response The importer's own response.
312 + * @since 3.13.5
313 + */
314 + public function finish_import( $request ) {
315 + $payload = $this->get_import_payload( $request );
316 +
317 + return rest_ensure_response( Wpfnl::$instance->template_manager->after_funnel_creation( $payload ) );
318 + }
319 +
320 +
321 + /**
322 + * Drop everything the library has cached, so the next listing is fetched
323 + * fresh from the template server.
324 + *
325 + * @param WP_REST_Request $request Full data about the request.
326 + *
327 + * @return WP_REST_Response
328 + * @since 3.13.5
329 + */
330 + public function sync_library( $request ) {
331 + $settings = Wpfnl::$instance->module_manager->get_admin_modules( 'settings' );
332 +
333 + if ( ! $settings ) {
334 + return rest_ensure_response( array( 'success' => false ) );
335 + }
336 +
337 + return rest_ensure_response( $settings->clear_templates_data( array() ) );
338 + }
339 +
340 +
341 + /**
342 + * The request body as the importer expects to read it.
343 + *
344 + * The importer was written against `wp_ajax_helper`, which handed it a
345 + * plain array; REST params are the same shape, so this only unwraps them.
346 + *
347 + * @param WP_REST_Request $request Full data about the request.
348 + *
349 + * @return array Payload for the importer.
350 + * @since 3.13.5
351 + */
352 + private function get_import_payload( $request ) {
353 + $payload = $request->get_json_params();
354 +
355 + if ( ! is_array( $payload ) ) {
356 + $payload = $request->get_params();
357 + }
358 +
359 + // `source` names which registered source to import through, and there
360 + // is only one the library offers.
361 + if ( empty( $payload['source'] ) ) {
362 + $payload['source'] = 'remote';
363 + }
364 +
365 + return $payload;
366 + }
367 +
368 +
221 369 public function get_templates( $request ) {
222 370 $type_param = isset( $_GET['type'] ) ? sanitize_key( $_GET['type'] ) : 'wc';
223 371 $store_checkout_param = isset( $_GET['store_checkout'] ) ? sanitize_key( $_GET['store_checkout'] ) : 'no';
224 372
@@ -286,9 +434,9 @@
286 434 // bail if there is an error
287 435 if ( is_wp_error( $response ) || ! is_array( $response ) || ! isset( $response['body'] ) ) {
288 436 return array(
289 437 'success' => false,
290 - 'message' => $response->get_error_message(),
438 + 'message' => is_wp_error( $response ) ? $response->get_error_message() : __( 'Unexpected response from the template server.', 'wpfnl' ),
291 439 'data' => $response,
292 440 );
293 441 }
294 442
@@ -322,10 +470,13 @@
322 470 public static function get_funnels( $type = false, $isStep = false, $args = array(), $force_update = false, $builder = false ) {
323 471 $builder_type = $builder ? $builder : Wpfnl_functions::get_builder_type();
324 472 $cache_key = 'wpfunnels_remote_template_data_' . $type . '_' . $builder_type . '_' . WPFNL_VERSION;
325 473 $data = get_transient( $cache_key );
326 - $data = false; // Disable cache to make sure we are always getting the latest templates. We can remove this line once we are sure there is no issue with the API response time.
327 - if ( $data ) {
474 +
475 + // A cached miss is stored as an empty array, which is falsy, so check
476 + // against false explicitly or a failed fetch would be retried on every
477 + // single request. An explicit refresh always goes out to the network.
478 + if ( false !== $data && ! $force_update ) {
328 479 return;
329 480 }
330 481 if ( $type && ( $force_update || false === $data ) ) {
331 482 if ( false === $data ) {
@@ -330,9 +481,12 @@
330 481 if ( $type && ( $force_update || false === $data ) ) {
331 482 if ( false === $data ) {
332 483 $data = array();
333 484 }
334 - $timeout = ( $force_update ) ? 40 : 55;
485 + // Keep the blocking request well inside the web server's FastCGI/proxy
486 + // timeout: this runs during an admin REST request, and up to four of
487 + // these calls can happen back to back.
488 + $timeout = ( $force_update ) ? 30 : 15;
335 489
336 490 $template_url = self::$all_funnels_api_url;
337 491 if ( 'oxygen' === $builder_type ) {
338 492 $template_url = 'https://oxygentemplates.getwpfunnels.com/wp-json/wpfunnels/v1/get_all_funnels/';
@@ -369,9 +523,9 @@
369 523 )
370 524 );
371 525
372 526 if ( ! is_array( $template_data ) || ! $template_data['success'] ) {
373 - set_transient( $cache_key, array(), 24 * HOUR_IN_SECONDS );
527 + set_transient( $cache_key, array(), 15 * MINUTE_IN_SECONDS );
374 528 return false;
375 529 }
376 530 }
377 531
@@ -441,9 +595,9 @@
441 595 )
442 596 );
443 597
444 598 if ( ! is_array( $categories_data ) || ! $categories_data['success'] ) {
445 - set_transient( $cache_key, array(), 24 * HOUR_IN_SECONDS );
599 + set_transient( $cache_key, array(), 15 * MINUTE_IN_SECONDS );
446 600 return false;
447 601 }
448 602 }
449 603