Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TBD] feat: template cloud integration #2455

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions inc/class-main.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function init() {
}

add_filter( 'otter_blocks_about_us_metadata', array( $this, 'about_page' ) );

add_action( 'parse_query', array( $this, 'pagination_support' ) );
}

Expand Down Expand Up @@ -83,6 +83,8 @@ public function autoload_classes() {
'\ThemeIsle\GutenbergBlocks\Integration\Form_Email',
'\ThemeIsle\GutenbergBlocks\Server\Form_Server',
'\ThemeIsle\GutenbergBlocks\Server\Prompt_Server',
'\ThemeIsle\GutenbergBlocks\Template_Cloud',
'\ThemeIsle\GutenbergBlocks\Server\Template_Cloud_Server',
);

$classnames = apply_filters( 'otter_blocks_autoloader', $classnames );
Expand Down Expand Up @@ -532,13 +534,13 @@ public function generate_svg_attachment_metadata( $metadata, $attachment_id ) {

/**
* Disable canonical redirect to make Posts pagination feature work.
*
*
* @param \WP_Query $request The query object.
*/
public function pagination_support( $request ) {
if (
true === $request->is_singular &&
-1 === $request->current_post &&
true === $request->is_singular &&
-1 === $request->current_post &&
true === $request->is_paged &&
(
! empty( $request->query_vars['page'] ) ||
Expand Down
342 changes: 342 additions & 0 deletions inc/class-template-cloud.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
<?php
/**
* Template Cloud.
*
* @package ThemeIsle
*/

namespace ThemeIsle\GutenbergBlocks;

/**
* Class Template Cloud
*/
class Template_Cloud {
const SOURCES_SETTING_KEY = 'themeisle_template_cloud_sources';

const API_ENDPOINT_SUFFIX = 'ti-template-cloud/v1/patterns';

/**
* Initialize the module.
*
* @return void
*/
public function instance() {
add_action( 'init', array( $this, 'register_cloud_resources' ) );
}

/**
* Register categories and patterns.
*
* @return void
*/
public function register_cloud_resources() {
$this->register_pattern_categories();
$this->register_patterns();
}

/**
* Register the pattern categories.
*
* @return void
*/
private function register_pattern_categories() {
$sources = $this->get_pattern_sources();

if ( empty( $sources ) ) {
return;
}

foreach ( $sources as $source ) {
$slug = $this->slug_from_name( $source['name'] );

if ( ! \WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $slug ) ) {
register_block_pattern_category( $slug, [ 'label' => $source['name'] ] );
}
}
}

/**
* Register the patterns.
*
* @return void
*/
private function register_patterns() {
$cloud_data = $this->get_cloud_data();

if ( empty( $cloud_data ) ) {
return;
}

$all_patterns = [];

foreach ( $cloud_data as $source_data ) {
$patterns_for_source = [];

if ( ! is_array( $source_data ) || ! isset( $source_data['patterns'], $source_data['category'] ) ) {
continue;
}

$patterns = $source_data['patterns'];
$category = $source_data['category'];

// Make sure we don't have duplicates.
foreach ( $patterns as $pattern ) {
if ( isset( $patterns_for_source[ $pattern['id'] ] ) ) {
continue;
}

$pattern['categories'] = [ 'otter-blocks', 'otter-blocks-tc', $category ];

$patterns_for_source[ $pattern['id'] ] = $pattern;
}

$all_patterns = array_merge( $all_patterns, $patterns_for_source );
}

foreach ( $all_patterns as $pattern ) {
if ( ! isset( $pattern['slug'] ) ) {
continue;
}


register_block_pattern(
'otter-blocks/' . $pattern['slug'],
$pattern
);
}
}

/**
* Get all the cloud data for each source.
*
* @return array|array[]
*/
private function get_cloud_data() {
$sources = self::get_pattern_sources();

if ( empty( $sources ) ) {
return [];
}

return array_map(
function ( $source ) {
return [
'category' => $this->slug_from_name( $source['name'] ),
'patterns' => $this->get_patterns_for_key( $source['key'] ),
];
},
$sources
);
}

/**
* Get patterns for a certain access key.
*
* @param string $access_key The access key.
*
* @return array
*/
private function get_patterns_for_key( $access_key ) {
$patterns = get_transient( self::get_cache_key( $access_key ) );

if ( ! $patterns ) {
self::sync_sources();
}

$patterns = get_transient( self::get_cache_key( $access_key ) );

if ( ! $patterns ) {
return [];
}

$patterns = json_decode( $patterns, true );

return is_array( $patterns ) ? $patterns : array();
}

/**
* Get the slug from a name.
*
* @param string $name The name to slugify.
*
* @return string
*/
private function slug_from_name( $name ) {
return 'ti-tc-' . sanitize_key( str_replace( ' ', '-', $name ) );
}

/**
* Get the pattern sources.
*
* @return array
*/
public static function get_pattern_sources() {
return get_option( self::SOURCES_SETTING_KEY, [] );
}

/**
* Save the pattern sources.
*
* @param array $new_sources The new sources.
*
* @return bool
*/
public static function save_pattern_sources( $new_sources ) {
return update_option( self::SOURCES_SETTING_KEY, array_values( $new_sources ) );
}

/**
* Get the cache key for the patterns.
*
* @param string $key The key to use for connection.
*
* @return string
*/
public static function get_cache_key( $key ) {
return 'ti_tc_patterns_' . $key;
}

/**
* Save patterns for a certain access key.
*
* @param string $access_key The access key.
* @param array $patterns The patterns to save.
*
* @return bool
*/
public static function save_patterns_for_key( $access_key, $patterns ) {
return set_transient( self::get_cache_key( $access_key ), wp_json_encode( $patterns ), DAY_IN_SECONDS );
}

/**
* Delete patterns for a certain access key.
*
* @param string $access_key The access key.
*
* @return bool
*/
public static function delete_patterns_by_key( $access_key ) {
return delete_transient( self::get_cache_key( $access_key ) );
}

/**
* Sync sources.
*/
public static function sync_sources() {
$sources = self::get_pattern_sources();

if ( empty( $sources ) ) {
return [ 'success' => true ];
}

$errors = array();



foreach ( $sources as $source ) {
$url = trailingslashit( $source['url'] ) . self::API_ENDPOINT_SUFFIX;
$args = array(
'sslverify' => false,
'headers' => array(
'X-API-KEY' => $source['key'],
),
);

if ( function_exists( 'vip_safe_wp_remote_get' ) ) {
$response = vip_safe_wp_remote_get( $url, '', 3, 1, 20, $args );
} else {
$response = wp_remote_get( $url, $args ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.wp_remote_get_wp_remote_get
}

if ( is_wp_error( $response ) ) {
$errors[] = sprintf(
/* translators: 1: source name, 2: error message */
__( 'Error with %1$s: %2$s', 'otter-blocks' ),
$source['name'],
$response->get_error_message()
);

continue;
}

$code = wp_remote_retrieve_response_code( $response );

if ( 200 !== $code ) {
$errors[] = sprintf(
/* translators: 1: source name, 2: response code */
__( 'Error with %1$s: Invalid response code %2$s', 'otter-blocks' ),
$source['name'],
$code
);

continue;
}

$body = wp_remote_retrieve_body( $response );

if ( empty( $body ) ) {
$errors[] = sprintf(
/* translators: %s: source name */
__( 'Error with %s: Empty response', 'otter-blocks' ),
$source['name']
);

continue;
}

$decoded_body = json_decode( $body, true );

if ( ! is_array( $decoded_body ) ) {
$errors[] = sprintf(
/* translators: %s: source name */
__( 'Error with %s: Invalid response', 'otter-blocks' ),
$source['name']
);

continue;
}

if ( ! isset( $decoded_body['success'], $decoded_body['data'], $decoded_body['key_name'] ) || ! $decoded_body['success'] ) {
$errors[] = sprintf(
/* translators: %s: source name */
__( 'Error with %s: No patterns found', 'otter-blocks' ),
$source['name']
);

continue;
}

// Update key name if that has changed.
if ( $decoded_body['key_name'] !== $source['name'] ) {
self::update_source_name( $source['key'], $decoded_body['key_name'] );
}

self::save_patterns_for_key( $source['key'], $decoded_body['data'] );
}

return [
'success' => true,
'errors' => $errors,
];
}

/**
* Update Source Name on sync.
*
* @param string $key The key to use for connection.
* @param string $new_name The new name to use.
*
* @return void
*/
public static function update_source_name( $key, $new_name ) {
$sources = self::get_pattern_sources();

foreach ( $sources as $idx => $source ) {
if ( $source['key'] === $key ) {
$sources[ $idx ]['name'] = $new_name;
}
}

self::save_pattern_sources( $sources );
}
}
Loading
Loading