# wpfunnels/3.13.3/includes/core/rest-api/Controllers/class-templatelibrary-controller.php

WPFunnels – Funnel Builder for WooCommerce with Checkout &amp; One Click Upsell, version 3.13.3. 850 lines.

- Page: https://pluginprobe.com/plugins/wpfunnels/3.13.3/code/includes/core/rest-api/Controllers/class-templatelibrary-controller.php
- Raw: https://pluginprobe.com/plugins/wpfunnels/3.13.3/raw/includes/core/rest-api/Controllers/class-templatelibrary-controller.php
- Modified: 2026-09-30T09:56:46+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/wpfunnels/3.13.3/code/includes/core/rest-api/Controllers/class-templatelibrary-controller.php#L10-L20`.

```php
<?php
/**
 * Template library controller
 *
 * @package WPFunnels\Rest\Controllers
 */

namespace WPFunnels\Rest\Controllers;

use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use WPFunnels\Wpfnl;
use WPFunnels\Wpfnl_functions;
use WPFunnels\lms\helper\Wpfnl_lms_learndash_functions;

/**
 * Class TemplateLibraryController
 * This class represents the controller for the template library in the WP Funnels plugin
 * It extends the Wpfnl_REST_Controller class
 * 
 * @package WPFunnels\Rest\Controllers
 * @since 	1.0.0
 */
class TemplateLibraryController extends Wpfnl_REST_Controller {

	/**
	 * The URL for the WP Funnels API.
	 *
	 * This variable holds the URL for the WP Funnels API, which is used to retrieve templates.
	 *
	 * @var string
	 */
	public static $funnel_api_url = 'https://templates.getwpfunnels.com/wp-json/wp/v2/wpfunnels/';

	/**
	 * The URL for the WP Funnels API.
	 *
	 * This variable holds the URL for the WP Funnels API, which is used to retrieve templates.
	 *
	 * @var string
	 */
	public static $funnel_categories_api_url = 'https://templates.getwpfunnels.com/wp-json/wp/v2/template_industries/';

	/**
	 * The URL for the WP Funnels API.
	 *
	 * This variable holds the URL for the WP Funnels API, which is used to retrieve templates.
	 *
	 * @var string
	 */
	public static $funnel_steps_api_url = 'https://templates.getwpfunnels.com/wp-json/wp/v2/wpfunnel_steps/';

	/**
	 * The URL for the WP Funnels API.
	 *
	 * This variable holds the URL for the WP Funnels API, which is used to retrieve templates.
	 *
	 * @var string
	 */
	public static $all_funnels_api_url = 'https://templates.getwpfunnels.com/wp-json/wpfunnels/v1/get_all_funnels/';


	/**
	 * Endpoint namespace.
	 *
	 * @var string
	 */
	protected $namespace = 'wpfunnels/v1';

	/**
	 * Route base.
	 *
	 * @var string
	 */
	protected $rest_base = 'templates/';


	/**
	 * Get remote funnel api url
	 *
	 * @return string
	 * @since  2.2.8
	 */
	private static function get_remote_funnel_api_url() {
		if ( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
			return 'https://oxygentemplates.getwpfunnels.com/wp-json/wp/v2/wpfunnels/';
		} elseif ( 'bricks' === Wpfnl_functions::get_builder_type() ) {
			return 'https://brickstemplates.getwpfunnels.com/wp-json/wp/v2/wpfunnels/';
		}
		return self::$funnel_api_url;
	}


	/**
	 * Get remote funnel builders categories url
	 *
	 * @return string
	 *
	 * @since 2.2.8
	 */
	private static function get_remote_funnel_categories_api_url() {
		if ( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
			return 'https://oxygentemplates.getwpfunnels.com/wp-json/wp/v2/template_industries/';
		} elseif ( 'bricks' === Wpfnl_functions::get_builder_type() ) {
			return 'https://brickstemplates.getwpfunnels.com/wp-json/wp/v2/template_industries/';
		}
		return self::$funnel_categories_api_url;
	}


	/**
	 * Get remote funnel steps categories url
	 *
	 * @return string
	 *
	 * @since 2.2.8
	 */
	private static function get_remote_funnel_steps_api_url() {
		if ( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
			return 'https://oxygentemplates.getwpfunnels.com/wp-json/wp/v2/wpfunnel_steps/';
		} elseif ( 'bricks' === Wpfnl_functions::get_builder_type() ) {
			return 'https://brickstemplates.getwpfunnels.com/wp-json/wp/v2/wpfunnel_steps/';
		}
		return self::$funnel_steps_api_url;
	}


	/**
	 * Get all templates API url
	 *
	 * @return string
	 * @since  2.2.8
	 */
	private static function get_all_templates_api_url() {
		if ( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
			return 'https://oxygentemplates.getwpfunnels.com/wp-json/wpfunnels/v1/get_all_funnels/';
		} elseif ( 'bricks' === Wpfnl_functions::get_builder_type() ) {
			return 'https://brickstemplates.getwpfunnels.com/wp-json/wpfunnels/v1/get_all_funnels/';
		}
		return self::$all_funnels_api_url;
	}


	/**
	 * Check user permission
	 *
	 * @param $request
	 *
	 * @return bool|WP_Error
	 */
	public function update_items_permissions_check( $request ) {
		$permission = current_user_can( 'wpf_manage_funnels' );
		if ( ! Wpfnl_functions::wpfnl_rest_check_manager_permissions( 'templates' ) ) {
			return new WP_Error( 'wpfunnels_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wpfnl' ), array( 'status' => rest_authorization_required_code() ) );
		}
		return true;
	}


	/**
	 * Makes sure the current user has access to READ the settings APIs.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 *
	 * @return WP_Error|boolean
	 * @since  3.0.0
	 */
	public function get_items_permissions_check( $request ) {
		if ( ! Wpfnl_functions::wpfnl_rest_check_manager_permissions( 'templates' ) ) {
			return new WP_Error( 'wpfunnels_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'wpfnl' ), array( 'status' => rest_authorization_required_code() ) );
		}
		return true;
	}



	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . 'get_templates',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_templates' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
				),
			)
		);

		/*
		 * Building a funnel out of a template, and clearing what the library
		 * has cached. The template library screen is React (see
		 * src/admin/pages/FunnelTemplates) and talks REST; the Vue library
		 * still embedded in the funnel canvas and Store Checkout posts the same
		 * work to admin-ajax, so both routes here hand straight over to the
		 * handlers those calls already run rather than restating them.
		 */
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . 'import-funnel',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'import_funnel' ),
					'permission_callback' => array( $this, 'edit_items_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . 'finish-import',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'finish_import' ),
					'permission_callback' => array( $this, 'edit_items_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . 'sync',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'sync_library' ),
					'permission_callback' => array( $this, 'edit_items_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . 'get_template_type_id',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_template_type_id' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),

				),
			)
		);

	}


	/**
	 * Prepare a single setting object for response.
	 *
	 * @param $request
	 *
	 * @return WP_REST_Response
	 */
	/**
	 * Prepare a single setting object for response.
	 *
	 * @param $request
	 *
	 * @return WP_REST_Response
	 */
	/**
	 * Makes sure the current user may build a funnel from a template.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 *
	 * @return WP_Error|boolean
	 * @since  3.13.5
	 */
	public function edit_items_permissions_check( $request ) {
		if ( ! Wpfnl_functions::wpfnl_rest_check_manager_permissions( 'templates', 'edit' ) ) {
			return new WP_Error( 'wpfunnels_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wpfnl' ), array( 'status' => rest_authorization_required_code() ) );
		}
		return true;
	}


	/**
	 * Create a funnel from a library template.
	 *
	 * First of the three calls that import a template: this creates the funnel
	 * post and answers with its id, the steps are then created one by one
	 * against the step controller, and `finish_import()` below closes the
	 * import off.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 *
	 * @return WP_REST_Response The importer's own response, carrying `funnelID`.
	 * @since  3.13.5
	 */
	public function import_funnel( $request ) {
		$payload = $this->get_import_payload( $request );

		return rest_ensure_response( Wpfnl::$instance->template_manager->import_funnel( $payload ) );
	}


	/**
	 * Close off a template import.
	 *
	 * Answers with the `redirectLink` the caller should follow — where the
	 * funnel wants to be opened depends on what was imported, so the server
	 * decides it.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 *
	 * @return WP_REST_Response The importer's own response.
	 * @since  3.13.5
	 */
	public function finish_import( $request ) {
		$payload = $this->get_import_payload( $request );

		return rest_ensure_response( Wpfnl::$instance->template_manager->after_funnel_creation( $payload ) );
	}


	/**
	 * Drop everything the library has cached, so the next listing is fetched
	 * fresh from the template server.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 *
	 * @return WP_REST_Response
	 * @since  3.13.5
	 */
	public function sync_library( $request ) {
		$settings = Wpfnl::$instance->module_manager->get_admin_modules( 'settings' );

		if ( ! $settings ) {
			return rest_ensure_response( array( 'success' => false ) );
		}

		return rest_ensure_response( $settings->clear_templates_data( array() ) );
	}


	/**
	 * The request body as the importer expects to read it.
	 *
	 * The importer was written against `wp_ajax_helper`, which handed it a
	 * plain array; REST params are the same shape, so this only unwraps them.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 *
	 * @return array Payload for the importer.
	 * @since  3.13.5
	 */
	private function get_import_payload( $request ) {
		$payload = $request->get_json_params();

		if ( ! is_array( $payload ) ) {
			$payload = $request->get_params();
		}

		// `source` names which registered source to import through, and there
		// is only one the library offers.
		if ( empty( $payload['source'] ) ) {
			$payload['source'] = 'remote';
		}

		return $payload;
	}


	public function get_templates( $request ) {
		$type_param = isset( $_GET['type'] ) ? sanitize_key( $_GET['type'] ) : 'wc';
		$store_checkout_param = isset( $_GET['store_checkout'] ) ? sanitize_key( $_GET['store_checkout'] ) : 'no';

		// Map frontend goal types to API template types.
		// 'store_checkout' (improve-checkout goal) passes through as-is.
		// 'sales' / 'order-value' goals send 'wc'; keep backward-compat mapping here too.
		$type_map = array(
			'sales' => 'wc',
			'lead'  => 'lead',
		);
		$funnel_template_type = isset( $type_map[ $type_param ] ) ? $type_map[ $type_param ] : $type_param;

		$step                 = isset( $_GET['step'] ) ? $_GET['step'] : false;
		$builder              = isset( $_GET['builder'] ) ? $_GET['builder'] : false;
		if( 'yes' === $store_checkout_param ) {
			$funnel_template_type = 'store_checkout';
		}
		
		$templates            = $this->get_funnels_data( $funnel_template_type, $step, array(), false, $builder );
		$templates			  = $this->prepare_custom_step($templates);
		$templates['success'] = true;
		return $this->prepare_item_for_response( $templates, $request );
	}


	/**
	 * Prepares custom steps.
	 * Allow user to create custom step from landing page.
	 * 
	 * @param array $templates The templates to prepare.
	 * @return array
	 * 
	 * @since  3.4.15
	 */
	public function prepare_custom_step($templates){
		if( is_array( $templates ) ){
			if( isset( $templates['steps'] ) && is_array( $templates['steps'] ) ){
				foreach( $templates['steps'] as $key => $step ){
					if( is_array( $step ) && isset( $step['step_type'] ) && 'landing' === $step['step_type'] ){
						$custom_step = $step;
						$custom_step['step_type'] = 'custom';
						if( isset( $custom_step['title'] ) ){
							$custom_step['title'] = str_ireplace('Landing', '', $custom_step['title']);
						}
						$templates['steps'][] = $custom_step;
					}
				}
			}
		}
		return $templates;
	}



	/**
	 * Send http request
	 *
	 * @param $url
	 * @param $args
	 *
	 * @return array
	 */
	public static function remote_get( $url, $args ) {
		$response = wp_remote_get( $url, $args );
		// bail if there is an error
		if ( is_wp_error( $response ) || ! is_array( $response ) || ! isset( $response['body'] ) ) {
			return array(
				'success' => false,
				'message' => is_wp_error( $response ) ? $response->get_error_message() : __( 'Unexpected response from the template server.', 'wpfnl' ),
				'data'    => $response,
			);
		}

		// Decode the results.
		$results = json_decode( $response['body'], true );

		// bail if there is no result found
		if ( ! is_array( $results ) ) {
			return new \WP_Error( 'unexpected_data_format', 'Data was not returned in the expected format.' );
		}

		return array(
			'success' => true,
			'message' => 'Data successfully retrieved',
			'data'    => json_decode( wp_remote_retrieve_body( $response ), true ),
		);
	}


	/**
	 * Get all funnels of the specific builder
	 *
	 * @param bool  $type
	 * @param bool  $isStep
	 * @param array $args
	 * @param bool  $force_update
	 * @param bool  $builder
	 *
	 * @return bool|mixed|void
	 */
	public static function get_funnels( $type = false, $isStep = false, $args = array(), $force_update = false, $builder = false ) {
		$builder_type = $builder ? $builder : Wpfnl_functions::get_builder_type();
		$cache_key    = 'wpfunnels_remote_template_data_' . $type . '_' . $builder_type . '_' . WPFNL_VERSION;
		$data         = get_transient( $cache_key );

		// A cached miss is stored as an empty array, which is falsy, so check
		// against false explicitly or a failed fetch would be retried on every
		// single request. An explicit refresh always goes out to the network.
		if ( false !== $data && ! $force_update ) {
			return;
		}
		if ( $type && ( $force_update || false === $data ) ) {
			if ( false === $data ) {
				$data = array();
			}
			// Keep the blocking request well inside the web server's FastCGI/proxy
			// timeout: this runs during an admin REST request, and up to four of
			// these calls can happen back to back.
			$timeout = ( $force_update ) ? 30 : 15;
			
			$template_url = self::$all_funnels_api_url;
			if ( 'oxygen' === $builder_type ) {
				$template_url = 'https://oxygentemplates.getwpfunnels.com/wp-json/wpfunnels/v1/get_all_funnels/';
			} elseif ( 'bricks' === $builder_type ) {
				$template_url = 'https://brickstemplates.getwpfunnels.com/wp-json/wpfunnels/v1/get_all_funnels/';
			}
			
			// get all templates
			$params = array(
				'per_page'      => 100,
				'offset'        => 0,
				'builder'       => $builder_type,
				'template_type' => $type,
				'template_url'  => $template_url,
			);
			if( !defined('QUBELY_VERSION') ){
				$params['gutenberg_type'] = 'wpf_native_gutenberg';
			}
			$url    = add_query_arg( $params, $template_url );

			$template_data = self::remote_get(
				$url,
				array(
					'timeout' => $timeout,
				)
			);
			
			if ( ! is_array( $template_data ) || ! $template_data['success'] ) {
				$url    = add_query_arg( $params, WPFNL_MIDDLEMAN_TEMPLATE_URL );
				$template_data = self::remote_get(
					$url,
					array(
						'timeout' => $timeout,
					)
				);

				if ( ! is_array( $template_data ) || ! $template_data['success'] ) {
					set_transient( $cache_key, array(), 15 * MINUTE_IN_SECONDS );
					return false;
				}
			}
			
			// get all steps
			$steps = array();
			$templates = array();
			if ( $template_data['data'] ) {
				foreach ( $template_data['data'] as $key => $template ) {
					
					$i              = 0;
					$thankyou_count = 0;
					if( isset($template['page_builder']) && 'gutenberg' === $template['page_builder'] ){
						if( !defined('QUBELY_VERSION') && 'wpf_native_gutenberg' !== $template['gutenberg_type'] ){
							continue;
						}
					}
					if( isset($template['is_store_checkout']) && $template['is_store_checkout'] && 'store_checkout' !== $type ) {
						continue;
					}

					foreach ( $template['steps'] as $_step ) {
						if ( $thankyou_count && 'thankyou' === $_step['step_type'] ) {
							continue;
						}
						if ( 0 == $i ) {
							$template_data['data'][ $key ]['link'] = $_step['link'];
						}
						$_step['funnel_name']   = $template['title'];
						$_step['template_type'] = isset( $template['templateType'] ) ? ( 'free' === $template['templateType'] ? 'free' : 'pro' ) : 'free';
						$steps[]                = $_step;
						if ( 'thankyou' === $_step['step_type'] ) {
							$thankyou_count++;
						}
						$i++;
					}
					array_push($templates, $template_data['data'][ $key ]);
				}
			}

			// fetch the funnel categories from the remote server
			$cat_url = self::$funnel_categories_api_url;
			if ( 'oxygen' === $builder_type ) {
				$cat_url = 'https://oxygentemplates.getwpfunnels.com/wp-json/wp/v2/template_industries/';
			} elseif ( 'bricks' === $builder_type ) {
				$cat_url = 'https://brickstemplates.getwpfunnels.com/wp-json/wp/v2/template_industries/';
			}

			$params          = array(
				'per_page' => 100,
				'category_url' => $cat_url,
			);

			$url             = add_query_arg( $params, $cat_url );
			$categories_data = self::remote_get(
				$url,
				array(
					'timeout' => $timeout,
				)
			);
			
			if ( ! is_array( $categories_data ) || ! $categories_data['success'] ) {
				$url    = add_query_arg( $params, WPFNL_MIDDLEMAN_TEMPLATE_CATEGORY_URL );
				$categories_data = self::remote_get(
					$url,
					array(
						'timeout' => $timeout,
					)
				);
				
				if ( ! is_array( $categories_data ) || ! $categories_data['success'] ) {
					set_transient( $cache_key, array(), 15 * MINUTE_IN_SECONDS );
					return false;
				}
			}
			
			$data['templates']  = $templates;
			$data['steps']      = $steps;
			$data['categories'] = $categories_data['data'];
			update_option( WPFNL_TEMPLATES_OPTION_KEY . '_' . $type . '_' . $builder_type, $data, 'no' );
			set_transient( $cache_key, $data, 24 * HOUR_IN_SECONDS );
			return false;
		}
	}



	/**
	 * Get funnel templates data
	 *
	 * @param array $args
	 * @param bool  $force_update
	 *
	 * @return array|mixed|void
	 * @since  1.0.0
	 */
	public function get_funnels_data( $type = false, $step = false, $args = array(), $force_update = false, $builder = false ) {

		self::get_funnels( $type, $step, $args, $force_update, $builder );
		$builder_type = $builder ? $builder : Wpfnl_functions::get_builder_type();
		$template_data = get_option( WPFNL_TEMPLATES_OPTION_KEY . '_' . $type . '_' . $builder_type );
		
		// Fallback for backward compatibility if data is not found with builder
		if ( empty( $template_data ) && !$builder ) {
			$template_data = get_option( WPFNL_TEMPLATES_OPTION_KEY . '_' . $type );
		}

		if ( empty( $template_data ) ) {
			return array();
		}
		return $template_data;
	}


	/**
	 * Get step from template library site by step ID
	 *
	 * @param $step_id
	 * @param bool    $force_update
	 *
	 * @return array
	 * @since  1.0.0
	 */
	public static function get_step( $step_id, $force_update = false ) {
		$timeout = ( $force_update ) ? 25 : 8;

		$params = array(
			'_fields' => 'id,title,link,slug,featured_media,post_meta,rawData,steps,divi_content,featured_image,steps_order,builder,industry,is_pro,type,step_type,funnel_id,funnel_name,_qubely_css,_qubely_interaction_json,__qubely_available_blocks',
			'url'     => self::get_remote_funnel_steps_api_url() . $step_id,
		);

		$url      = add_query_arg( $params, self::get_remote_funnel_steps_api_url() . $step_id );
		$api_args = array(
			'timeout' => $timeout,
		);
		$response = ( new TemplateLibraryController() )->remote_get( $url, $api_args );

		if ( is_array($response) && isset( $response['success'] ) ) {
			$step = $response['data'];
			return array(
				'title'        => ( isset( $step['title']['rendered'] ) ) ? $step['title']['rendered'] : '',
				'post_meta'    => ( isset( $step['post_meta'] ) ) ? $step['post_meta'] : '',
				'data'         => $step,
				'content'      => isset( $response['data']['content']['rendered'] ) ? $response['data']['content']['rendered'] : '',
				'rawData'      => isset( $response['data']['rawData'] ) ? $response['data']['rawData'] : '',
				'divi_content' => isset( $response['data']['divi_content'] ) ? $response['data']['divi_content'] : '',
				'message'      => $response['message'],
				'success'      => $response['success'],
			);
		}

		$url    = add_query_arg( $params, WPFNL_MIDDLEMAN_STEP_URL );
		$response = ( new TemplateLibraryController() )->remote_get( $url, $api_args );
	
		if ( is_array($response) && isset( $response['success'] ) ) {
			$step = $response['data'];
			return array(
				'title'        => ( isset( $step['title']['rendered'] ) ) ? $step['title']['rendered'] : '',
				'post_meta'    => ( isset( $step['post_meta'] ) ) ? $step['post_meta'] : '',
				'data'         => $step,
				'content'      => isset( $response['data']['content']['rendered'] ) ? $response['data']['content']['rendered'] : '',
				'rawData'      => isset( $response['data']['rawData'] ) ? $response['data']['rawData'] : '',
				'divi_content' => isset( $response['data']['divi_content'] ) ? $response['data']['divi_content'] : '',
				'message'      => $response['message'],
				'success'      => $response['success'],
			);
		}

		if ( is_wp_error( $response ) ) {
			return array(
				'title'     => '',
				'post_meta' => array(),
				'message'   => $response->get_error_message(),
				'data'      => array(),
				'success'   => false,
				'content'   => '',
			);
		}

		return array(
			'title'     => '',
			'post_meta' => array(),
			'message'   => isset( $response['message'] ) ? $response['message'] : '',
			'data'      => isset( $response['data'] ) ? $response['data'] : array(),
			'success'   => isset( $response['success'] ) ? $response['success'] : false,
			'content'   => '',
		);
	}




	public static function get_funnel( $funnel_id, $force_update = false ) {
		$timeout = ( $force_update ) ? 25 : 8;
		$params  = array(
			'_fields' => 'id,title,link,slug,featured_media,funnel_data,_funnel_data',
			'url' 	  => self::get_remote_funnel_api_url().$funnel_id,
		);

		$url = add_query_arg( $params, self::get_remote_funnel_api_url() . $funnel_id );

		$api_args = array(
			'timeout' => $timeout,
		);
		$response = ( new TemplateLibraryController() )->remote_get( $url, $api_args );
		
		if (is_array($response) && isset( $response['success'] )) {
			$funnel = $response['data'];
			return array(
				'funnel_id'    => $funnel_id,
				'funnel_data'  => $funnel['funnel_data'] ?? '',
				'_funnel_data' => $funnel['_funnel_data'] ?? '',
				'title'        => ( isset( $funnel['title']['rendered'] ) ) ? $funnel['title']['rendered'] : '',
				'success'      => $response['success'],
			);
		}

		$url    = add_query_arg( $params, WPFNL_MIDDLEMAN_SINGLE_TEMPLATE_URL );
		$response = ( new TemplateLibraryController() )->remote_get( $url, $api_args );
		
		if ( is_array($response) && isset( $response['success'] ) ) {
			$funnel = $response['data'];
			return array(
				'funnel_id'    => $funnel_id,
				'funnel_data'  => $funnel['funnel_data'] ?? '',
				'_funnel_data' => $funnel['_funnel_data'] ?? '',
				'title'        => ( isset( $funnel['title']['rendered'] ) ) ? $funnel['title']['rendered'] : '',
				'success'      => $response['success'],
			);
		}

		if ( is_wp_error( $response ) ) {
			return array(
				'title'     => '',
				'post_meta' => array(),
				'message'   => $response->get_error_message(),
				'data'      => array(),
				'success'   => false,
				'content'   => '',
			);
		}

		return array(
			'title'     => '',
			'post_meta' => array(),
			'message'   => isset( $response['message'] ) ? $response['message'] : '',
			'data'      => isset( $response['data'] ) ? $response['data'] : array(),
			'success'   => isset( $response['success'] ) ? $response['success'] : false,
			'content'   => '',
		);
	}


	/**
	 * Get funnel type id
	 */
	public function get_template_type_id( $request ) {

		$response = array(
			'success' => false,
			'type_id' => '',
		);

		if ( $request['type'] ) {
			$type             = $request['type'];
			$force_update     = false;
			$timeout          = ( $force_update ) ? 40 : 55;
			$teplate_type_url = self::get_remote_funnel_template_type_api_url();
			$response         = self::remote_get(
				$teplate_type_url,
				array(
					'timeout' => $timeout,
				)
			);

			if ( isset( $response['data'] ) && is_array( $response['data'] ) && !empty($response['data'])) {
				foreach ( $response['data'] as $types ) {
					if ( $type === $types['name'] ) {
						$response['success'] = true;
						$response['type_id'] = $types['id'];
					}
				}
			}

			$params  = array(
				'url' 	  => self::get_remote_funnel_template_type_api_url()
			);
			
			$url    = add_query_arg( $params, WPFNL_MIDDLEMAN_TEMPLATE_TYPE_URL );
			$response = ( new TemplateLibraryController() )->remote_get( $url , array(
				'timeout' => $timeout,
			) );

			if ( isset( $response['data'] ) && is_array( $response['data'] ) && !empty($response['data'])) {
				foreach ( $response['data'] as $types ) {
					if ( $type === $types['name'] ) {
						$response['success'] = true;
						$response['type_id'] = $types['id'];
					}
				}
			}


		}
		return rest_ensure_response( $response );
	}


	/**
	 * Prepare a single setting object for response.
	 *
	 * @param object          $item Setting object.
	 * @param WP_REST_Request $request Request object.
	 *
	 * @return WP_REST_Response $response Response data.
	 * @since  1.0.0
	 */
	public function prepare_item_for_response( $item, $request ) {
		$data = $this->add_additional_fields_to_object( $item, $request );
		return rest_ensure_response( $data );
	}
}

```
