537 lines
13 KiB
PHP
537 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* The Libraries class file.
|
|
*
|
|
* @package GenerateBlocks\Pattern_Library
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly.
|
|
}
|
|
|
|
/**
|
|
* Class for handling with libraries.
|
|
*
|
|
* @since 1.9.0
|
|
*/
|
|
class GenerateBlocks_Libraries extends GenerateBlocks_Singleton {
|
|
/**
|
|
* Initialize all hooks.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init() {
|
|
add_filter( 'query_vars', [ $this, 'add_query_vars' ] );
|
|
add_action( 'init', [ $this, 'rewrite_endpoints' ] );
|
|
add_action( 'template_include', [ $this, 'template_viewer' ] );
|
|
add_filter( 'show_admin_bar', [ $this, 'hide_admin_bar' ] );
|
|
add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_assets' ] );
|
|
}
|
|
|
|
/**
|
|
* Enqueue block editor assets.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function enqueue_block_editor_assets() {
|
|
$assets = generateblocks_get_enqueue_assets( 'pattern-library' );
|
|
|
|
wp_enqueue_script(
|
|
'generateblocks-pattern-library',
|
|
GENERATEBLOCKS_DIR_URL . 'dist/pattern-library.js',
|
|
$assets['dependencies'],
|
|
$assets['version'],
|
|
true
|
|
);
|
|
|
|
wp_set_script_translations(
|
|
'generateblocks-pattern-library',
|
|
'generateblocks'
|
|
);
|
|
|
|
wp_localize_script(
|
|
'generateblocks-pattern-library',
|
|
'generateBlocksPatternLibrary',
|
|
array(
|
|
'patternPreviewUrl' => site_url() . '?gb-template-viewer=1',
|
|
'defaultOpenLibrary' => apply_filters(
|
|
'generateblocks_default_open_pattern_library',
|
|
'gb_default_pro_library'
|
|
),
|
|
'defaultOpenCategory' => apply_filters(
|
|
'generateblocks_default_open_pattern_category',
|
|
''
|
|
),
|
|
)
|
|
);
|
|
|
|
wp_enqueue_style(
|
|
'generateblocks-pattern-library',
|
|
GENERATEBLOCKS_DIR_URL . 'dist/pattern-library.css',
|
|
array( 'wp-components' ),
|
|
GENERATEBLOCKS_VERSION
|
|
);
|
|
}
|
|
|
|
/**
|
|
* The default id.
|
|
*
|
|
* @var string The default library id.
|
|
*/
|
|
protected $default_library_id = 'gb_default_free_library';
|
|
|
|
/**
|
|
* Returns all the registered libraries.
|
|
*
|
|
* @param bool $enabled_only Filter disabled libraries.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_all( bool $enabled_only = true ): array {
|
|
// Get saved library data.
|
|
$saved_libraries = get_option( 'generateblocks_pattern_libraries', [] );
|
|
|
|
if ( ! is_array( $saved_libraries ) ) {
|
|
$saved_libraries = [];
|
|
}
|
|
|
|
// Create library instances for any remote sites that provide the complete set of data.
|
|
$remote_libraries = array_map(
|
|
[ $this, 'create' ],
|
|
array_filter(
|
|
$saved_libraries,
|
|
function( $saved_library ) {
|
|
return is_array( $saved_library ) &&
|
|
isset( $saved_library['isLocal'] ) &&
|
|
! rest_sanitize_boolean( $saved_library['isLocal'] ) &&
|
|
! empty( $saved_library['id'] ) &&
|
|
is_scalar( $saved_library['id'] ) &&
|
|
! empty( $saved_library['domain'] ) &&
|
|
is_string( $saved_library['domain'] );
|
|
}
|
|
)
|
|
);
|
|
|
|
// Allow other libraries to be added.
|
|
$libraries = apply_filters(
|
|
'generateblocks_pattern_libraries',
|
|
$remote_libraries
|
|
);
|
|
|
|
if ( ! is_array( $libraries ) ) {
|
|
$libraries = [];
|
|
}
|
|
|
|
$libraries = array_filter(
|
|
$libraries,
|
|
function( $library ) {
|
|
return $this->is_valid_library( $library );
|
|
}
|
|
);
|
|
|
|
// Add our default library at the start of the list.
|
|
if ( ! self::exists( $libraries, $this->default_library_id ) ) {
|
|
$default_library = self::get_default();
|
|
$libraries = array_merge( array( $default_library ), $libraries );
|
|
}
|
|
|
|
// Loop our libraries and set their status based on their saved value.
|
|
foreach ( $libraries as $key => $library ) {
|
|
$saved_data = array_filter(
|
|
$saved_libraries,
|
|
function( $saved_library ) use ( $library ) {
|
|
if ( ! is_array( $saved_library ) || ! isset( $saved_library['id'] ) ) {
|
|
return false;
|
|
}
|
|
|
|
return $saved_library['id'] === $library->id;
|
|
}
|
|
);
|
|
|
|
$saved_data = array_values( $saved_data );
|
|
|
|
if ( isset( $saved_data[0]['isEnabled'] ) ) {
|
|
$library->setStatus( $this->normalize_boolean_value( $saved_data[0]['isEnabled'] ) );
|
|
}
|
|
}
|
|
|
|
return array_filter(
|
|
$libraries,
|
|
function( GenerateBlocks_Library_DTO $library ) use ( $enabled_only ) {
|
|
if ( $enabled_only ) {
|
|
return $library->is_enabled;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns a single library by id.
|
|
*
|
|
* @param string $id The id.
|
|
*
|
|
* @return GenerateBlocks_Library_DTO|null
|
|
*/
|
|
public function get_one( string $id ): ?GenerateBlocks_Library_DTO {
|
|
$libraries = self::get_all( false );
|
|
|
|
return array_reduce(
|
|
$libraries,
|
|
function( $result, GenerateBlocks_Library_DTO $library ) use ( $id ) {
|
|
if ( $id === $library->id ) {
|
|
return $library;
|
|
}
|
|
|
|
return $result;
|
|
},
|
|
null
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Creates a library from array.
|
|
*
|
|
* @param array $data The library in array format.
|
|
*
|
|
* @return GenerateBlocks_Library_DTO
|
|
*/
|
|
public function create( array $data ): GenerateBlocks_Library_DTO {
|
|
$data = wp_parse_args(
|
|
$data,
|
|
array(
|
|
'id' => '',
|
|
'name' => '',
|
|
'domain' => '',
|
|
'publicKey' => '',
|
|
'isEnabled' => false,
|
|
'isDefault' => false,
|
|
'isLocal' => false,
|
|
)
|
|
);
|
|
|
|
return ( new GenerateBlocks_Library_DTO() )
|
|
->set( 'id', $this->normalize_string_value( $data['id'] ) )
|
|
->set( 'name', $this->normalize_string_value( $data['name'] ) )
|
|
->set( 'domain', $this->normalize_string_value( $data['domain'] ) )
|
|
->set( 'public_key', $this->normalize_string_value( $data['publicKey'] ) )
|
|
->set( 'is_enabled', $this->normalize_boolean_value( $data['isEnabled'] ) )
|
|
->set( 'is_default', $this->normalize_boolean_value( $data['isDefault'] ) )
|
|
->set( 'is_local', $this->normalize_boolean_value( $data['isLocal'] ) );
|
|
}
|
|
|
|
/**
|
|
* Normalize values that are expected to be strings.
|
|
*
|
|
* @param mixed $value The value to normalize.
|
|
* @return string
|
|
*/
|
|
private function normalize_string_value( $value ): string {
|
|
if ( ! is_scalar( $value ) ) {
|
|
return '';
|
|
}
|
|
|
|
return (string) $value;
|
|
}
|
|
|
|
/**
|
|
* Normalize values that are expected to be booleans.
|
|
*
|
|
* @param mixed $value The value to normalize.
|
|
* @return bool
|
|
*/
|
|
private function normalize_boolean_value( $value ): bool {
|
|
if ( ! is_scalar( $value ) ) {
|
|
return false;
|
|
}
|
|
|
|
return rest_sanitize_boolean( $value );
|
|
}
|
|
|
|
/**
|
|
* Check that a library has values safe to access through the DTO.
|
|
*
|
|
* @param mixed $library The library object to validate.
|
|
* @return bool
|
|
*/
|
|
private function is_valid_library( $library ): bool {
|
|
if ( ! $library instanceof GenerateBlocks_Library_DTO ) {
|
|
return false;
|
|
}
|
|
|
|
$data = $library->serialize();
|
|
|
|
if ( empty( $data['id'] ) || ! is_scalar( $data['id'] ) ) {
|
|
return false;
|
|
}
|
|
|
|
foreach ( array( 'name', 'domain', 'publicKey' ) as $key ) {
|
|
if ( isset( $data[ $key ] ) && ! is_scalar( $data[ $key ] ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
foreach ( array( 'isEnabled', 'isDefault', 'isLocal' ) as $key ) {
|
|
if ( isset( $data[ $key ] ) && ! is_scalar( $data[ $key ] ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Return the default library.
|
|
*
|
|
* @return GenerateBlocks_Library_DTO
|
|
*/
|
|
protected function get_default(): GenerateBlocks_Library_DTO {
|
|
$use_legacy_pattern_library = generateblocks_use_v1_blocks();
|
|
$domain = 'https://patterns.generatepress.com';
|
|
$public_key = 'betRRDVi8W0Td2eKAS52oVkG4HxqEj9r';
|
|
|
|
if (
|
|
$use_legacy_pattern_library ||
|
|
apply_filters( 'generateblocks_force_v1_pattern_library', false )
|
|
) {
|
|
$domain = 'https://patterns.generateblocks.com';
|
|
$public_key = 'GxroZpidKoLZ2ofWNJdXtanAK9ZozWKo';
|
|
}
|
|
|
|
return ( new GenerateBlocks_Library_DTO() )
|
|
->set( 'id', $this->default_library_id )
|
|
->set( 'name', __( 'Free', 'generateblocks' ) )
|
|
->set( 'domain', $domain )
|
|
->set( 'public_key', $public_key )
|
|
->set( 'is_enabled', true )
|
|
->set( 'is_default', true );
|
|
}
|
|
|
|
/**
|
|
* Checks if exists the library.
|
|
*
|
|
* @param array $libraries Array of libraries.
|
|
* @param string $id The library id.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function exists( array $libraries, string $id ): bool {
|
|
return array_reduce(
|
|
$libraries,
|
|
function( $result, GenerateBlocks_Library_DTO $library ) use ( $id ) {
|
|
if ( $id === $library->id ) {
|
|
return true;
|
|
}
|
|
|
|
return $result;
|
|
},
|
|
false
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get our cached library data by collection.
|
|
*
|
|
* @param string $cache_key The key to look up.
|
|
* @param array $query_args Args to filter the results with.
|
|
* @param string $collection The collection to check.
|
|
*/
|
|
public static function get_cached_data( $cache_key = '', $query_args = [], $collection = '' ) {
|
|
if ( ! $cache_key ) {
|
|
return [];
|
|
}
|
|
|
|
if ( 'patterns' !== $collection ) {
|
|
return get_transient( $cache_key );
|
|
}
|
|
|
|
$cached_data = [];
|
|
$has_cache = false;
|
|
$index = 0;
|
|
|
|
while ( true ) {
|
|
$option_key = $cache_key . '_' . $index;
|
|
$chunk = get_transient( $option_key );
|
|
|
|
if ( false === $chunk ) {
|
|
// No more chunks found, exit the loop.
|
|
break;
|
|
}
|
|
|
|
// Merge the chunk into the cached data.
|
|
$cached_data += $chunk;
|
|
$has_cache = true;
|
|
|
|
// Increment the index for the next iteration.
|
|
$index++;
|
|
}
|
|
|
|
// If we have no cache, return false.
|
|
// This allows empty arrays to be cached.
|
|
if ( ! $has_cache ) {
|
|
return false;
|
|
}
|
|
|
|
if ( ! empty( $query_args['categoryId'] ) ) {
|
|
$cached_data = array_filter(
|
|
$cached_data,
|
|
function( $data ) use ( $query_args ) {
|
|
if ( ! isset( $data['categories'] ) || ! is_array( $data['categories'] ) ) {
|
|
return false;
|
|
}
|
|
|
|
return in_array( $query_args['categoryId'], $data['categories'] );
|
|
}
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $query_args['search'] ) ) {
|
|
$cached_data = array_filter(
|
|
$cached_data,
|
|
function( $data ) use ( $query_args ) {
|
|
if ( ! is_array( $data ) ) {
|
|
return false;
|
|
}
|
|
|
|
foreach ( $data as $key => $value ) {
|
|
if ( is_string( $value ) && stripos( $value, $query_args['search'] ) !== false ) {
|
|
return true;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
|
|
$cached_data = array_values( $cached_data );
|
|
return $cached_data;
|
|
}
|
|
|
|
/**
|
|
* Set the collection cache expiry.
|
|
*/
|
|
public static function get_cache_expiry() {
|
|
return 86400;
|
|
}
|
|
|
|
/**
|
|
* Set our cached data. This function will split our patterns into chunks.
|
|
*
|
|
* @param array $data The data to cache.
|
|
* @param string $cache_key The key to set.
|
|
* @param string $collection The collection to check.
|
|
*/
|
|
public static function set_cached_data( $data = [], $cache_key = '', $collection = '' ) {
|
|
if ( ! $cache_key ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! is_array( $data ) ) {
|
|
return;
|
|
}
|
|
|
|
$expiration = self::get_cache_expiry();
|
|
|
|
if ( 'patterns' === $collection ) {
|
|
self::delete_cached_data( $cache_key, $collection );
|
|
|
|
if ( ! empty( $data ) ) {
|
|
$chunks = array_chunk( $data, 20, true );
|
|
|
|
foreach ( $chunks as $index => $chunk ) {
|
|
$option_key = $cache_key . '_' . $index;
|
|
set_transient( $option_key, $chunk, $expiration );
|
|
}
|
|
} else {
|
|
set_transient( $cache_key . '_0', $data, $expiration );
|
|
}
|
|
} else {
|
|
set_transient( $cache_key, $data, $expiration );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete cached library data by collection.
|
|
*
|
|
* @param string $cache_key The key to delete.
|
|
* @param string $collection The collection to delete.
|
|
*/
|
|
public static function delete_cached_data( $cache_key = '', $collection = '' ) {
|
|
if ( ! $cache_key ) {
|
|
return;
|
|
}
|
|
|
|
if ( 'patterns' !== $collection ) {
|
|
delete_transient( $cache_key );
|
|
return;
|
|
}
|
|
|
|
$index = 0;
|
|
|
|
while ( false !== get_transient( $cache_key . '_' . $index ) ) {
|
|
delete_transient( $cache_key . '_' . $index );
|
|
$index++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds GB custom query variables.
|
|
*
|
|
* @param array $vars The variables.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function add_query_vars( array $vars ): array {
|
|
$vars[] = 'gb-template-viewer';
|
|
return $vars;
|
|
}
|
|
|
|
/**
|
|
* Adds GB custom rewrite endpoints.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function rewrite_endpoints(): void {
|
|
add_rewrite_endpoint( 'gb-template-viewer', EP_ROOT );
|
|
}
|
|
|
|
/**
|
|
* Register the template viewer template.
|
|
*
|
|
* @param string $template The current template.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function template_viewer( string $template ): string {
|
|
if ( false !== get_query_var( 'gb-template-viewer', false ) ) {
|
|
return GENERATEBLOCKS_DIR . 'includes/pattern-library/templates/gb-template-viewer.php';
|
|
}
|
|
|
|
return $template;
|
|
}
|
|
|
|
/**
|
|
* Hide the admin bar if we are on the template viewer.
|
|
*
|
|
* @param bool $show_admin_bar Whether to show the admin bar.
|
|
* @return bool
|
|
*/
|
|
public function hide_admin_bar( $show_admin_bar ) {
|
|
if ( ! isset( $GLOBALS['wp_query'] ) ) {
|
|
return $show_admin_bar;
|
|
}
|
|
|
|
if ( false !== get_query_var( 'gb-template-viewer', false ) ) {
|
|
$show_admin_bar = false;
|
|
}
|
|
|
|
return $show_admin_bar;
|
|
}
|
|
}
|
|
|
|
GenerateBlocks_Libraries::get_instance()->init();
|