default_request_headers = apply_filters( 'redux_templates_api_headers', $this->default_request_headers ); add_action( 'rest_api_init', array( $this, 'register_api_hooks' ), 0 ); } /** * Get the filesystem. * * @return Filesystem */ private function get_filesystem() { if ( empty( $this->filesystem ) ) { $this->filesystem = \Redux_Filesystem::get_instance(); } return $this->filesystem; } /** * Process the registered blocks from the library. * * @param array $parameters Array to be returned if no response, or to have data appended to. * * @return array Array of properly processed blocks and supported plugins. */ private function process_registered_blocks( $parameters ) { $data = $this->api_cache_fetch( array(), array(), 'library.json' ); if ( empty( $data ) || ( ! empty( $data ) && ! isset( $data['plugins'] ) ) ) { return $parameters; } $supported = ReduxTemplates\Supported_Plugins::instance(); $supported->init( $data['plugins'] ); $plugins = $supported::get_plugins(); $installed_plugins = array(); if ( ! isset( $parameters['registered_blocks'] ) ) { $parameters['registered_blocks'] = array(); } foreach ( $plugins as $key => $value ) { if ( isset( $value['version'] ) ) { array_push( $installed_plugins, $key . '~' . $value['version'] ); $found_already = array_search( $key, $parameters['registered_blocks'], true ); if ( false !== $found_already ) { unset( $parameters['registered_blocks'][ $found_already ] ); } if ( isset( $value['namespace'] ) && $key !== $value['namespace'] ) { $found = array_search( $value['namespace'], $parameters['registered_blocks'], true ); if ( false !== $found ) { unset( $parameters['registered_blocks'][ $found ] ); } } } } $parameters['registered_blocks'] = array_values( array_merge( $installed_plugins, $parameters['registered_blocks'] ) ); return $parameters; } /** * Process the dependencies. * * @param array $data Data array. * @param string $key Key param. * * @return array Data array with dependencies outlined. */ private function process_dependencies( $data, $key ) { foreach ( $data[ $key ] as $kk => $pp ) { $debug = false; // Add debug if statement if key matches here. if ( isset( $pp['dependencies'] ) ) { foreach ( $pp['dependencies'] as $dep ) { if ( isset( $data['plugins'][ $dep ] ) ) { if ( isset( $data['plugins'][ $dep ]['no_plugin'] ) || 'core' === $dep ) { continue; } if ( isset( $data['plugins'][ $dep ]['free_slug'] ) ) { if ( isset( $data['plugins'][ $data['plugins'][ $dep ]['free_slug'] ] ) ) { $plugin = $data['plugins'][ $data['plugins'][ $dep ]['free_slug'] ]; if ( ! isset( $plugin['is_pro'] ) ) { if ( ! isset( $data[ $key ][ $kk ]['proDependenciesMissing'] ) ) { $data[ $key ][ $kk ]['proDependenciesMissing'] = array(); } $data[ $key ][ $kk ]['proDependenciesMissing'][] = $dep; } if ( ! isset( $data[ $key ][ $kk ]['proDependencies'] ) ) { $data[ $key ][ $kk ]['proDependencies'] = array(); } $data[ $key ][ $kk ]['proDependencies'][] = $dep; } } else { if ( ! isset( $data['plugins'][ $dep ]['version'] ) ) { if ( ! isset( $data[ $key ][ $kk ]['installDependenciesMissing'] ) ) { $data[ $key ][ $kk ]['installDependenciesMissing'] = array(); } $data[ $key ][ $kk ]['installDependenciesMissing'][] = $dep; } if ( ! isset( $data[ $key ][ $kk ]['installDependencies'] ) ) { $data[ $key ][ $kk ]['installDependencies'] = array(); } $data[ $key ][ $kk ]['installDependencies'][] = $dep; } } } } // Print the debug here if the key exists. Use `print_r( $data[ $key ][ $kk ] );exit();`. } return $data; } /** * Get the last cache time. * * @param string $abs_path Absolute path to a file. * * @return string|bool Last modified time. */ private function get_cache_time( $abs_path ) { $filesystem = $this->get_filesystem(); $last_modified = false; if ( $filesystem->file_exists( $abs_path ) ) { $last_modified = filemtime( $abs_path ); } return $last_modified; } /** * Fetch from the cache if had. * * @param array $parameters Absolute path to a file. * @param array $config Absolute path to a file. * @param string $path URL path perform a request to a file. * @param bool $cache_only Set to only fetch from the local cache. * * @return array Response and possibly the template if recovered. */ public function api_cache_fetch( $parameters, $config, $path, $cache_only = false ) { $filesystem = $this->get_filesystem(); $this->cache_folder = trailingslashit( $filesystem->cache_folder ) . 'templates/'; if ( ! $filesystem->file_exists( $this->cache_folder ) ) { $filesystem->mkdir( $this->cache_folder ); } if ( strpos( $path, $this->cache_folder ) === false ) { $path = $this->cache_folder . $path; } if ( ! $filesystem->file_exists( dirname( $path ) ) ) { $filesystem->mkdir( dirname( $path ) ); } $last_modified = file_exists( $path ) ? $this->get_cache_time( $path ) : false; $use_cache = true; if ( isset( $parameters['no_cache'] ) ) { $use_cache = false; } if ( ! empty( $last_modified ) ) { $config['headers']['Redux-Cache-Time'] = $last_modified; if ( time() > $last_modified + $this->cache_time ) { $use_cache = false; } } if ( $cache_only ) { $use_cache = true; } $data = array(); if ( file_exists( $path ) && $use_cache ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors $data = @json_decode( $filesystem->get_contents( $path ), true ); } // If somehow we got an invalid response, let's not persist it. if ( isset( $data['message'] ) && false !== strpos( $data['message'], 'meta http-equiv="refresh" content="0;URL=' ) ) { $data = false; } if ( $cache_only ) { return $data; } if ( ! $use_cache && isset( $config['headers']['Redux-Cache-Time'] ) ) { unset( $config['headers']['Redux-Cache-Time'] ); } if ( empty( $data ) ) { if ( isset( $parameters['registered_blocks'] ) ) { $config['headers']['Redux-Registered-Blocks'] = implode( ',', $parameters['registered_blocks'] ); } $results = $this->api_request( $config ); if ( ! empty( $results ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors $data = @json_decode( $results, true ); if ( isset( $data['use_cache'] ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors $data = @json_decode( $filesystem->get_contents( $path ), true ); $data['cache'] = 'used'; } else { if ( empty( $data ) ) { $data = array( 'message' => $results ); } if ( isset( $data['status'] ) && 'error' === $data['status'] ) { wp_send_json_error( array( 'message' => $data['message'] ) ); } $filesystem->put_contents( $path, wp_json_encode( $data ) ); } } else { wp_send_json_error( array( 'message' => __( 'API fetch failure.', 'redux-framework' ) ) ); } } if ( empty( $data ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors $data = @json_decode( $filesystem->get_contents( $path ), true ); if ( $data ) { $data['status'] = 'error'; $data['message'] = __( 'Fetching failed, used a cached version.', 'redux-framework' ); } else { $data = array( 'message' => 'Error Fetching', ); } } else { if ( ! $use_cache ) { $data['cache'] = 'cleared'; } } return $data; } /** * Get library index. Support for library, collections, pages, sections all in a single request. * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function get_index( \WP_REST_Request $request ) { $parameters = $request->get_params(); $attributes = $request->get_attributes(); $type = $request->get_route(); $type = explode( '/', $type ); $type = end( $type ); if ( empty( $type ) ) { wp_send_json_error( 'No type specified.' ); } $config = array( 'path' => 'library/', ); $test_path = dirname( __FILE__ ) . '/library.json'; if ( file_exists( $test_path ) ) { $data = json_decode( ReduxTemplates\Init::get_local_file_contents( $test_path ), true ); } else { $parameters['no_cache'] = 1; $data = $this->api_cache_fetch( $parameters, $config, 'library/' ); } if ( isset( $data['plugins'] ) ) { $supported = ReduxTemplates\Supported_Plugins::instance(); $supported->init( $data['plugins'] ); $data['plugins'] = $supported::get_plugins(); $data['plugins']['redux-framework']['version'] = \Redux_Core::$version; if ( \Redux_Helpers::mokama() ) { if ( class_exists( 'Redux_Pro' ) ) { $data['plugins']['redux-framework']['is_pro'] = \Redux_Pro::$version; } else { $data['plugins']['redux-framework']['is_pro'] = \Redux_Core::$version; } } $data = $this->process_dependencies( $data, 'sections' ); $data = $this->process_dependencies( $data, 'pages' ); } if ( class_exists( 'WP_Patterns_Registry' ) ) { $patterns = \WP_Patterns_Registry::get_instance()->get_all_registered(); foreach ( $patterns as $k => $p ) { $id = 'wp_block_pattern_' . $k; $data['sections'][ $id ] = array( 'name' => $p['title'], 'categories' => array( 'WP Block Patterns' ), 'source' => 'wp_block_patterns', 'id' => $id, ); } } wp_send_json_success( $data ); } /** * Filter an array recursively. * * @param array $input Array to filter. * * @return array Filtered array. */ private function array_filter_recursive( $input ) { foreach ( $input as &$value ) { if ( is_array( $value ) ) { $value = $this->array_filter_recursive( $value ); } } return array_filter( $input ); } /** * Method for transmitting a template the user is sharing remotely. * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function share_template( \WP_REST_Request $request ) { $parameters = $request->get_params(); $attributes = $request->get_attributes(); $parameters = $this->process_registered_blocks( $parameters ); if ( empty( $parameters ) ) { wp_send_json_error( 'No template data found.' ); } $config = array( 'path' => 'template_share/', 'uid' => get_current_user_id(), 'editor_content' => isset( $parameters['editor_content'] ) ? (string) $parameters['editor_content'] : '', 'editor_blocks' => isset( $parameters['editor_blocks'] ) ? $parameters['editor_blocks'] : '', 'postID' => isset( $parameters['postID'] ) ? (string) sanitize_text_field( $parameters['postID'] ) : '', 'title' => isset( $parameters['title'] ) ? (string) sanitize_text_field( $parameters['title'] ) : 'The Title', 'type' => isset( $parameters['type'] ) ? (string) sanitize_text_field( $parameters['type'] ) : 'page', 'categories' => isset( $parameters['categories'] ) ? (string) sanitize_text_field( $parameters['categories'] ) : '', 'description' => isset( $parameters['description'] ) ? (string) sanitize_text_field( $parameters['description'] ) : '', 'headers' => array( 'Redux-Registered-Blocks' => isset( $parameters['registered_blocks'] ) ? (string) sanitize_text_field( implode( ',', $parameters['registered_blocks'] ) ) : '', ), ); $config = $this->array_filter_recursive( $config ); if ( ! isset( $config['title'] ) ) { wp_send_json_error( array( 'messages' => 'A title is required.' ) ); } if ( ! isset( $config['type'] ) ) { wp_send_json_error( array( 'messages' => 'A type is required.' ) ); } $response = $this->api_request( $config ); // phpcs:ignore WordPress.PHP.NoSilencedErrors $data = @json_decode( $response, true ); if ( 'success' === $data['status'] && isset( $data['url'] ) ) { wp_send_json_success( array( 'url' => $data['url'] ) ); } wp_send_json_error( $data ); } /** * Run an API request. * * @param array $data Array related to an API request. * * @return string API response string. */ public function api_request( $data ) { $api_url = $this->api_base_url; if ( isset( $data['path'] ) ) { if ( 'library/' === $data['path'] ) { $api_url = 'https://files.redux.io/library.json'; $request = wp_remote_get( $api_url, array( 'timeout' => $this->timeout ) ); if ( is_wp_error( $request ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => $request->get_error_messages(), 'message_types' => 'error', ) ); } if ( 404 === wp_remote_retrieve_response_code( $request ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'Error fetching library, URL not found. Please try again', 'message_types' => 'error', ) ); } return $request['body']; } $api_url = $api_url . $data['path']; } if ( isset( $data['_locale'] ) ) { unset( $data['_locale'] ); } $headers = array(); if ( isset( $data['headers'] ) ) { $headers = $data['headers']; unset( $data['headers'] ); } if ( isset( $data['p'] ) ) { $headers['Redux-P'] = $data['p']; unset( $data['p'] ); } if ( isset( $data['path'] ) ) { $headers['Redux-Path'] = $data['path']; unset( $data['path'] ); } $headers['Redux-Slug'] = \Redux_Helpers::get_hash(); $headers = wp_parse_args( $headers, $this->default_request_headers ); $headers['Content-Type'] = 'application/json; charset=utf-8'; $headers = array_filter( $headers ); if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { $headers['Redux-User-Agent'] = (string) sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ); } $headers['Redux-SiteURL'] = get_site_url( get_current_blog_id() ); $post_args = array( 'timeout' => $this->timeout, 'body' => wp_json_encode( $data ), 'method' => 'POST', 'data_format' => 'body', 'redirection' => 5, 'headers' => $headers, ); $request = wp_remote_post( $api_url, $post_args ); // Handle redirects. if ( ! is_wp_error( $request ) && isset( $request['http_response'] ) && $request['http_response'] instanceof \WP_HTTP_Requests_Response && method_exists( $request['http_response'], 'get_response_object' ) && strpos( $request['http_response']->get_response_object()->url, 'files.redux.io' ) !== false ) { if ( isset( $data['no_redirect'] ) ) { return $request['http_response']->get_response_object()->url; } else { $request = wp_remote_get( $request['http_response']->get_response_object()->url, array( 'timeout' => $this->timeout ) ); } } if ( is_wp_error( $request ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => $request->get_error_messages(), 'message_types' => 'error', ) ); } if ( 404 === wp_remote_retrieve_response_code( $request ) ) { return false; } return $request['body']; } /** * Fetch a single template. * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function get_template( \WP_REST_Request $request ) { $parameters = $request->get_params(); $attributes = $request->get_attributes(); $parameters = $this->process_registered_blocks( $parameters ); if ( in_array( $parameters['type'], array( 'sections', 'pages' ), true ) ) { $parameters['type'] = substr_replace( $parameters['type'], '', - 1 ); } $config = array( 'path' => 'template/', 'id' => sanitize_text_field( $parameters['id'] ), 'type' => (string) sanitize_text_field( $parameters['type'] ), 'source' => isset( $parameters['source'] ) ? $parameters['source'] : '', ); $template_response = $this->check_template_response( $parameters ); if ( 'wp_block_patterns' === $config['source'] && class_exists( 'WP_Patterns_Registry' ) ) { $patterns = \WP_Patterns_Registry::get_instance()->get_all_registered(); $id = explode( '_', $config['id'] ); $id = end( $id ); if ( isset( $patterns[ $id ] ) ) { $response = array( 'template' => $patterns[ $id ]['content'] ); } } else { $cache_path = $config['type'] . DIRECTORY_SEPARATOR . $config['id'] . '.json'; $parameters['no_cache'] = 1; $response = $this->api_cache_fetch( $parameters, $config, $cache_path ); if ( false === $response ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'Error fetching template. Please try again', 'message_types' => 'error', ) ); } $response = wp_parse_args( $response, $template_response ); } if ( ! empty( $response ) && isset( $response['message'] ) ) { $response['template'] = $response['message']; unset( $response['message'] ); } wp_send_json_success( $response ); } /** * Check template reponse. * * @param array $parameters Parameters array. * * @return array * @since 4.0.0 */ public function check_template_response( $parameters ) { $response = array(); if ( ! \Redux_Helpers::mokama() ) { if ( \Redux_Functions_Ex::activated() ) { $response['left'] = 999; } else { $count = ReduxTemplates\Init::left( $parameters['uid'] ); $count = intval( $count ) - 1; if ( 0 === $count ) { $response['left'] = $count; update_user_meta( $parameters['uid'], '_redux_templates_counts', -1 ); } elseif ( $count < 0 ) { wp_send_json_error( array( 'message' => 'Please activate Redux', 'left' => 0, ) ); } else { update_user_meta( $parameters['uid'], '_redux_templates_counts', $count ); } $response['left'] = $count; } } return $response; } /** * Check template reponse. * * @param array $parameters Parameters array. * * @since 4.0.0 */ public function activate_redux( $parameters ) { if ( \Redux_Functions_Ex::activated() ) { $response['left'] = 999; } else { \Redux_Core::$insights->optin(); if ( \Redux_Functions_Ex::activated() ) { $response['left'] = 999; } else { $count = get_user_meta( get_current_user_id(), '_redux_templates_counts', true ); if ( false === $count ) { $count = Init::$default_left; update_user_meta( get_current_user_id(), '_redux_templates_counts', $count ); } $response = array( 'left' => $count, ); } } if ( 999 === $response['left'] ) { wp_send_json_success( $response ); } wp_send_json_error( $response ); } /** * Fetch a single template. * * @param array $data Data array. * * @return array * @since 4.0.0 */ public function request_verify( $data = array() ) { $config = array( 'Redux-Version' => REDUXTEMPLATES_VERSION, 'Redux-Multisite' => is_multisite(), 'Redux-Mokama' => \Redux_Helpers::mokama(), 'Redux-Insights' => \Redux_Core::$insights->tracking_allowed(), ); // TODO - Update this with the EDD key or developer key. $config['Redux-API-Key'] = ''; if ( ! empty( \Redux_Core::$pro_loaded ) && \Redux_Core::$pro_loaded ) { $config['Redux-Pro'] = \Redux_Core::$pro_loaded; } $data = wp_parse_args( $data, $config ); return $data; } /** * Get all saved blocks (reusable blocks). * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function get_saved_blocks( \WP_REST_Request $request ) { $args = array( 'post_type' => 'wp_block', 'post_status' => 'publish', ); $r = wp_parse_args( null, $args ); $get_posts = new \WP_Query(); $wp_blocks = $get_posts->query( $r ); wp_send_json_success( $wp_blocks ); } /** * Delete a single saved (reusable) block * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function delete_saved_block( \WP_REST_Request $request ) { $parameters = $request->get_params(); $attributes = $request->get_attributes(); if ( ! isset( $parameters['block_id'] ) ) { return wp_send_json_error( array( 'status' => 'error', 'message' => 'Missing block_id.', ) ); } $block_id = (int) sanitize_text_field( wp_unslash( $parameters['block_id'] ) ); $deleted_block = wp_delete_post( $block_id ); wp_send_json_success( $deleted_block ); } /** * Record that the user has used the welcome guide. * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function welcome_guide( \WP_REST_Request $request ) { $parameters = $request->get_params(); $attributes = $request->get_attributes(); if ( ! isset( $parameters['uid'] ) ) { return wp_send_json_error( array( 'status' => 'error', 'message' => 'User ID required.', ) ); } update_user_meta( $parameters['uid'], '_redux_welcome_guide', '1' ); wp_send_json_success( array( 'status' => 'success' ) ); } /** * Method used to register all rest endpoint hooks. * * @since 4.0.0 */ public function register_api_hooks() { $hooks = array( 'library' => array( 'callback' => 'get_index', ), 'pages' => array( 'callback' => 'get_index', ), 'sections' => array( 'callback' => 'get_index', ), 'collections' => array( 'callback' => 'get_index', ), 'feedback' => array( 'callback' => 'send_feedback', ), 'suggestion' => array( 'callback' => 'send_suggestion', ), 'template' => array( 'callback' => 'get_template', ), 'share' => array( 'method' => 'POST', 'callback' => 'share_template', ), 'get_saved_blocks' => array( 'callback' => 'get_saved_blocks', ), 'delete_saved_block' => array( 'method' => 'POST', 'callback' => 'delete_saved_block', ), 'activate' => array( 'method' => 'GET', 'callback' => 'activate_redux', ), 'plugin-install' => array( 'method' => 'GET', 'callback' => 'plugin_install', ), 'license' => array( 'method' => 'GET', 'callback' => 'license', ), 'license-validate' => array( 'method' => 'GET', 'callback' => 'validate_license', ), 'license-activate' => array( 'method' => 'GET', 'callback' => 'activate_license', ), 'license-deactivate' => array( 'method' => 'GET', 'callback' => 'deactivate_license', ), 'get-pro-url' => array( 'method' => 'GET', 'callback' => 'get_pro_url', ), 'opt_out' => array( 'method' => 'GET', 'callback' => 'opt_out_account', ), 'welcome' => array( 'method' => 'POST', 'callback' => 'welcome_guide', ), 'nps' => array( 'method' => 'POST', 'callback' => 'send_nps', ), ); $fs = \Redux_Filesystem::get_instance(); foreach ( $hooks as $route => $data ) { $methods = array( 'GET', 'POST' ); if ( isset( $data['method'] ) ) { $methods = explode( ',', $data['method'] ); } foreach ( $methods as $method ) { $args = array( 'methods' => $method, 'callback' => array( $this, $data['callback'] ), 'args' => array(), ); if ( defined( 'REDUX_PLUGIN_FILE' ) && ! $fs->file_exists( trailingslashit( dirname( REDUX_PLUGIN_FILE ) ) . 'local_developer.txt' ) ) { $args['permission_callback'] = function () { return current_user_can( 'install_plugins' ); }; } else { $args['permission_callback'] = '__return_true'; } register_rest_route( 'redux/v1/templates', $route, $args ); } } } /** * Install plugin endpoint. * * @param \WP_REST_Request $request WP Rest request. * * @since 4.0.0 */ public function plugin_install( \WP_REST_Request $request ) { $data = $request->get_params(); if ( empty( $data['slug'] ) ) { wp_send_json_error( array( 'error' => __( 'Slug not specified.', 'redux-framework' ), ) ); } $slug = (string) sanitize_text_field( $data['slug'] ); if ( ! empty( $data['redux_pro'] ) ) { if ( \Redux_Helpers::mokama() || 'redux-pro' === $slug ) { $config = array( 'path' => 'installer/', 'slug' => $slug, 'no_redirect' => true, ); $parameters['no_cache'] = 1; if ( 'redux-pro' === $slug ) { $lic_status = get_option( 'redux_pro_license_status', false ); if ( 'valid' !== $lic_status && 'active' !== $lic_status ) { $status = array( 'error' => __( 'Redux Pro license not active, please activate.', 'redux-framework' ), ); } else { $array = array( 'edd_action' => 'get_version', ); $request = $this->do_license_request( $array ); if ( isset( $request['download_link'] ) ) { $status = ReduxTemplates\Installer::run( $slug, $request['download_link'] ); } else { $status = array( 'error' => __( 'Invalid license key.', 'redux-framework' ), ); delete_option( 'redux_pro_license_status' ); } } } else { $response = $this->api_cache_fetch( $parameters, $config, false, false ); if ( isset( $response['message'] ) && false !== strpos( $response['message'], 'redux.io' ) ) { $status = ReduxTemplates\Installer::run( $slug, $response['message'] ); } else { if ( isset( $response['error'] ) && ! empty( $response['error'] ) ) { $status = array( 'error' => $response['error'], ); } else { $status = array( 'error' => __( 'A valid Redux Pro subscription is required.', 'redux-framework' ), ); } } } } else { $status = array( 'error' => __( 'A valid Redux Pro subscription is required.', 'redux-framework' ), ); } } else { $status = ReduxTemplates\Installer::run( $slug ); } if ( isset( $status['error'] ) ) { wp_send_json_error( $status ); } if ( 'otter-blocks' === $slug ) { update_option( 'themeisle_blocks_settings_default_block', false ); } wp_send_json_success( $status ); } /** * Check the license key. * * @since 4.1.18 * @return bool|array */ protected function check_license_key() { $lic = get_option( 'redux_pro_license_key' ); if ( empty( $lic ) ) { delete_option( 'redux_pro_license_status' ); return array( 'success' => 'false', 'message' => 'No license found.', 'message_types' => 'error', ); } return true; } /** * Run the license API calls. * * @param \WP_REST_Request $request WP Rest request. * @since 4.1.18 */ public function license( \WP_REST_Request $request ) { $data = $request->get_params(); if ( ! isset( $data['key'] ) || ( isset( $data['key'] ) && empty( $data['key'] ) ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'License key not provided or empty.', 'message_types' => 'error', ) ); } $array = array( 'edd_action' => 'check_license', 'license' => $data['key'], ); $response = $this->do_license_request( $array ); if ( isset( $response['license'] ) && in_array( $response['license'], array( 'valid', 'site_inactive', 'inactive' ), true ) ) { if ( 'valid' === $response['license'] ) { wp_send_json_success( array( 'status' => 'success' ) ); } else { if ( 0 === $response['data']['activations_left'] ) { delete_option( 'redux_pro_license_key' ); wp_send_json_error( array( 'status' => 'error', 'message' => __( 'You have reached your activation limits for Redux Pro', 'redux-framework' ), ) ); } update_option( 'redux_pro_license_key', $data['key'] ); $array = array( 'edd_action' => 'activate_license', ); $response = $this->do_license_request( $array ); if ( isset( $response['license'] ) && 'valid' === $response['license'] ) { \Redux_Functions_Ex::set_activated(); wp_send_json_success( $response ); } } } wp_send_json_error( array( 'status' => 'error', 'msg' => __( 'Invalid license key.', 'redux-framework' ), 'response' => $response, ) ); } /** * Validate a license key. * * @param \WP_REST_Request $request WP Rest request. * @since 4.1.18 */ public function validate_license( \WP_REST_Request $request ) { $data = $request->get_params(); if ( ! isset( $data['key'] ) || ( isset( $data['key'] ) && empty( $data['key'] ) ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'License key not provided or empty.', 'message_types' => 'error', ) ); } $array = array( 'edd_action' => 'check_license', 'license' => $data['key'], ); $response = $this->do_license_request( $array ); if ( isset( $response['license'] ) && in_array( $response['key'], array( 'valid', 'site_inactive' ), true ) ) { update_option( 'redux_pro_license_status', $data['key'] ); wp_send_json_success( $response ); } else { wp_send_json_error( $response ); } } /** * Activate a license key. * * @param \WP_REST_Request $request WP Rest request. * @since 4.1.18 */ public function activate_license( \WP_REST_Request $request ) { $check = $this->check_license_key(); if ( is_array( $check ) ) { wp_send_json_error( $check ); } $lic = get_option( 'redux_pro_license_key' ); if ( empty( $lic ) ) { delete_option( 'redux_pro_license_status' ); wp_send_json_error( array( 'success' => 'false', 'message' => 'No license found.', 'message_types' => 'error', ) ); } $array = array( 'edd_action' => 'activate_license', ); $request = $this->do_license_request( $array ); if ( isset( $request['license'] ) && 'valid' === $request['license'] ) { wp_send_json_success( $request ); } wp_send_json_error( array( 'success' => 'false', 'message' => 'License is not valid.', 'message_types' => 'error', ) ); } /** * Deactivate a license key. * * @since 4.1.18 */ public function deactivate_license() { $check = $this->check_license_key(); if ( is_array( $check ) ) { wp_send_json_error( $check ); } $lic = get_option( 'redux_pro_license_key' ); if ( empty( $lic ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'No license found.', 'message_types' => 'error', ) ); } $array = array( 'edd_action' => 'deactivate_license', ); $request = $this->do_license_request( $array ); if ( isset( $request['license'] ) && 'deactivated' === $request['license'] ) { delete_option( 'redux_pro_license_key' ); wp_send_json_success( $request ); } wp_send_json_error( array( 'success' => 'false', 'message' => 'License is not valid.', 'message_types' => 'error', ) ); } /** * Get the Redux Pro download URL. * * @since 4.1.18 */ public function get_pro_url() { $lic_status = get_option( 'redux_pro_license_status', 'inactive' ); if ( 'valid' !== $lic_status && 'active' !== $lic_status ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'License not active, please activate.', 'message_types' => 'error', ) ); } $array = array( 'edd_action' => 'get_version', ); $request = $this->do_license_request( $array ); if ( isset( $request['download_link'] ) ) { wp_send_json_success( $request['download_link'] ); } wp_send_json_error( array( 'success' => 'false', 'message' => 'Could not recover Pro download URL.', 'message_types' => 'error', ) ); } /** * Run the license API calls. * * @param array $args Array of args. * @since 4.1.18 * @return mixed */ private function do_license_request( $args ) { $defaults = array( 'item_name' => 'Redux Pro', 'url' => network_site_url(), 'license' => get_option( 'redux_pro_license_key' ), ); $args = wp_parse_args( $args, $defaults ); if ( ! isset( $args['edd_action'] ) || ( isset( $args['edd_action'] ) && empty( $args['edd_action'] ) ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'Missing edd_action.', 'message_types' => 'error', ) ); } if ( 'check_license' !== $args['edd_action'] ) { $check = $this->check_license_key(); if ( is_array( $check ) ) { wp_send_json_error( $check ); } } $url = add_query_arg( $args, $this->license_base_url ); $request = wp_remote_get( $url, array( 'timeout' => $this->timeout ) ); if ( is_wp_error( $request ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => $request->get_error_messages(), 'message_types' => 'error', ) ); } if ( 404 === wp_remote_retrieve_response_code( $request ) ) { wp_send_json_error( array( 'success' => 'false', 'message' => 'Our API appears to be down... please try again later.', 'message_types' => 'error', ) ); } $data = json_decode( $request['body'], true ); if ( isset( $data['license'] ) ) { update_option( 'redux_pro_license_status', $data['license'] ); } return $data; } /** * Send the NPS value. * * @param \WP_REST_Request $request WP Rest request. * @since 4.1.19 */ public function send_nps( \WP_REST_Request $request ) { $data = $request->get_params(); if ( empty( $data['nps'] ) ) { wp_send_json_error( array( 'error' => __( 'NPS not specified.', 'redux-framework' ), ) ); } $nps = (string) sanitize_text_field( $data['nps'] ); $the_request = array( 'path' => 'nps', 'nps' => $nps, ); $response = $this->api_request( $the_request ); if ( false === $response ) { wp_send_json_error( array( 'message' => __( 'Could not record score.', 'redux-framework' ), ) ); } wp_send_json_success( json_decode( $response ) ); } }