diff --git a/example/shopify/register.php b/example/shopify/register.php index 6d22a473..e10379c5 100644 --- a/example/shopify/register.php +++ b/example/shopify/register.php @@ -7,6 +7,7 @@ use RemoteDataBlocks\Config\ShopifySearchProductsQuery; use RemoteDataBlocks\Editor\ConfigurationLoader; use RemoteDataBlocks\Logging\LoggerManager; +use RemoteDataBlocks\REST\DatasourceCRUD; use function add_action; require_once __DIR__ . '/inc/interactivity-store/interactivity-store.php'; @@ -17,7 +18,7 @@ require_once __DIR__ . '/inc/queries/class-shopify-search-products-query.php'; function register_shopify_block() { - $block_name = 'Shopify Product'; + $block_name = 'hardcode example'; $access_token = \RemoteDataBlocks\Example\get_access_token( 'shopify' ); if ( empty( $access_token ) ) { @@ -37,10 +38,37 @@ function register_shopify_block() { 'image_url' => plugins_url( '../../assets/shopify_logo_black.png', __FILE__ ), ]; + $block_pattern = file_get_contents( __DIR__ . '/inc/patterns/product-teaser.html' ); + + register_blocks_for_shopify_data_source( $config, $block_pattern ); + + register_block_type( __DIR__ . '/build/blocks/shopify-cart' ); + register_block_type( __DIR__ . '/build/blocks/shopify-cart-button' ); + + // Register blocks for dynamic data sources + // @TODO: These core example integrations should probably be moved into the parent plugin. + foreach ( DatasourceCRUD::get_data_sources( REMOTE_DATA_BLOCKS_SHOPIFY_SERVICE ) as $config ) { + // quick hack to transform data to our experimental format, which is all array based + $config = array_map( + function ( $value ) { + return is_object( $value ) ? (array) $value : $value; + }, + (array) $config + ); + register_blocks_for_shopify_data_source( $config, $block_pattern ); + } +} +add_action( 'register_remote_data_blocks', __NAMESPACE__ . '\\register_shopify_block' ); + + + +function register_blocks_for_shopify_data_source( array $config, string $block_pattern ): void { $shopify_datasource = new HttpDatasource( $config ); $shopify_search_products_query = new ShopifySearchProductsQuery( $shopify_datasource ); $shopify_get_product_query = new ShopifyGetProductQuery( $shopify_datasource ); + $block_name = 'Shopify (' . $shopify_datasource->get_friendly_name() . ')'; + ConfigurationLoader::register_block( $block_name, $shopify_get_product_query ); ConfigurationLoader::register_search_query( $block_name, $shopify_search_products_query ); @@ -48,10 +76,5 @@ function register_shopify_block() { ConfigurationLoader::register_query( $block_name, new ShopifyAddToCartMutation( $shopify_datasource ) ); ConfigurationLoader::register_query( $block_name, new ShopifyRemoveFromCartMutation( $shopify_datasource ) ); - $block_pattern = file_get_contents( __DIR__ . '/inc/patterns/product-teaser.html' ); ConfigurationLoader::register_block_pattern( $block_name, 'remote-data-blocks/shopify-product-teaser', $block_pattern, [ 'title' => 'Shopify Product Teaser' ] ); - - register_block_type( __DIR__ . '/build/blocks/shopify-cart' ); - register_block_type( __DIR__ . '/build/blocks/shopify-cart-button' ); -} -add_action( 'register_remote_data_blocks', __NAMESPACE__ . '\\register_shopify_block' ); +} \ No newline at end of file diff --git a/inc/editor/configuration-loader/configuration-loader.php b/inc/editor/configuration-loader/configuration-loader.php index c6cd0b13..03e9ba99 100644 --- a/inc/editor/configuration-loader/configuration-loader.php +++ b/inc/editor/configuration-loader/configuration-loader.php @@ -6,12 +6,8 @@ use Error; use RemoteDataBlocks\Config\QueryContext; -use RemoteDataBlocks\Config\ShopifyDatasource; -use RemoteDataBlocks\Config\ShopifyGetProductQuery; -use RemoteDataBlocks\Config\ShopifySearchProductsQuery; use RemoteDataBlocks\Logging\Logger; use RemoteDataBlocks\Logging\LoggerManager; -use RemoteDataBlocks\REST\DatasourceCRUD; use function add_action; use function do_action; @@ -249,33 +245,4 @@ public static function unregister_all(): void { self::$configurations = []; } - - private static function register_blocks_for_dynamic_data_sources(): void { - $data_sources_from_config = DatasourceCRUD::get_data_sources(); - - foreach ( $data_sources_from_config as $_source ) { - switch ( $_source->service ) { - case 'shopify': - $datasource = new ShopifyDatasource( $_source->token, $_source->store ); - $datasource->set_uuid( $_source->uuid ); - $datasource->set_slug( $_source->slug ); - self::register_blocks_for_shopify_data_source( $datasource ); - break; - default: - break; - } - } - } - - private static function register_blocks_for_shopify_data_source( ShopifyDatasource $datasource ): void { - $block_name = 'Shopify ' . $datasource->get_store_name(); - - $shopify_get_product_query = new ShopifyGetProductQuery( $datasource ); - self::register_block( $block_name, $shopify_get_product_query ); - self::$logger->debug( sprintf( 'Registered "%s" block for dynamic data source - %s', $block_name, $datasource->get_slug() ) ); - - $shopify_search_products_query = new ShopifySearchProductsQuery( $datasource ); - self::register_search_query( $block_name, $shopify_search_products_query ); - self::$logger->debug( sprintf( 'Registered "%s" _search query_ block for dynamic data source - %s', $block_name, $datasource->get_slug() ) ); - } } diff --git a/inc/rest/datasource-crud/datasource-crud.php b/inc/rest/datasource-crud/datasource-crud.php index 4be49627..c169f6ec 100644 --- a/inc/rest/datasource-crud/datasource-crud.php +++ b/inc/rest/datasource-crud/datasource-crud.php @@ -4,6 +4,26 @@ use WP_Error; +/** + * Handles CRUD operations for remote data sources. + * + * This class manages the configuration of remote data sources for the Remote Data Blocks plugin. + * It provides methods for validating, creating, reading, updating, and deleting data source entries. + * + * Core data structure: + * The class uses a WordPress option to store an array of data source objects. Each object represents + * a remote data source with the following structure: + * { + * uuid: string, // Unique identifier for the data source + * slug: string, // URL-friendly name for the data source + * service: string, // Type of service (e.g., 'airtable', 'shopify') + * token: string, // Authentication token for the service + * // Additional fields specific to each service type + * } + * + * The array of these objects is stored in the WordPress options table under the key defined + * by CONFIG_OPTION_NAME. + */ class DatasourceCRUD { const CONFIG_OPTION_NAME = 'remote_data_blocks_config'; const DATA_SOURCE_TYPES = [ 'airtable', 'shopify' ]; @@ -70,13 +90,22 @@ private static function validate_airtable_source( $source ) { return new WP_Error( 'invalid_table', __( 'Invalid table. Must have id and name fields.', 'remote-data-blocks' ) ); } - return (object) [ + return [ 'uuid' => $source->uuid, 'token' => sanitize_text_field( $source->token ), 'service' => 'airtable', 'base' => $source->base, 'table' => $source->table, 'slug' => sanitize_text_field( $source->slug ), + // quick hack to transform data to our experimental format + 'friendly_name' => sanitize_text_field( $source->slug ), + 'uid' => hash( 'sha256', $source->slug ), + 'endpoint' => 'https://api.airtable.com/v0/' . $source->base['id'] . '/' . $source->table['id'], + 'request_headers' => [ + 'Authorization' => 'Bearer ' . $source->token, + 'Content-Type' => 'application/json', + ], + 'image_url' => null, ]; } @@ -85,12 +114,21 @@ public static function validate_shopify_source( $source ) { return new WP_Error( 'missing_token', __( 'Missing token.', 'remote-data-blocks' ) ); } - return (object) [ + return [ 'uuid' => $source->uuid, 'token' => sanitize_text_field( $source->token ), 'service' => 'shopify', 'store' => sanitize_text_field( $source->store ), 'slug' => sanitize_text_field( $source->slug ), + // quick hack totransform data to our experimental format + 'friendly_name' => sanitize_text_field( $source->slug ), + 'uid' => hash( 'sha256', $source->slug ), + 'endpoint' => 'https://' . $source->store . '.myshopify.com/api/2024-04/graphql.json', + 'request_headers' => [ + 'Content-Type' => 'application/json', + 'X-Shopify-Storefront-Access-Token' => $source->token, + ], + 'image_url' => plugins_url( '../../assets/shopify_logo_black.png', __FILE__ ), ]; } @@ -158,8 +196,16 @@ public static function get_config() { return (array) get_option( self::CONFIG_OPTION_NAME, [] ); } - public static function get_data_sources() { - return self::get_config() ?? []; + public static function get_data_sources( string $service = '' ) { + $data_sources = self::get_config(); + + if ( $service ) { + return array_filter( $data_sources, function ( $config ) use ( $service ) { + return $config->service === $service; + } ); + } + + return $data_sources; } public static function get_item_by_uuid( $data_sources, string $uuid ) { diff --git a/remote-data-blocks.php b/remote-data-blocks.php index 918c8861..803e8e36 100644 --- a/remote-data-blocks.php +++ b/remote-data-blocks.php @@ -22,6 +22,11 @@ define( 'REMOTE_DATA_BLOCKS__REST_NAMESPACE', 'remote-data-blocks/v1' ); +// Datasource services +define( 'REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE', 'airtable' ); +define( 'REMOTE_DATA_BLOCKS_GITHUB_SERVICE', 'github' ); +define( 'REMOTE_DATA_BLOCKS_SHOPIFY_SERVICE', 'shopify' ); + // Autoloader require_once __DIR__ . '/inc/autoloader.php'; require_once __DIR__ . '/vendor/autoload.php';