diff --git a/composer.json b/composer.json index e10f0b9..83789f9 100644 --- a/composer.json +++ b/composer.json @@ -24,12 +24,12 @@ "require": { "newfold-labs/wp-module-installer": "^1.1", "newfold-labs/wp-module-patterns": "^0.1.14", - "newfold-labs/wp-module-ai": "^1.1.5", + "newfold-labs/wp-module-ai": "^1.1.6", "wp-forge/wp-upgrade-handler": "^1.0", "mustache/mustache": "^2.14", "newfold-labs/wp-module-data": "^2.4.18", - "newfold-labs/wp-module-coming-soon": "^1.2.0", - "newfold-labs/wp-module-performance": "^1.3.0" + "newfold-labs/wp-module-coming-soon": "^1.2.3", + "newfold-labs/wp-module-performance": "^1.4.0" }, "require-dev": { "newfold-labs/wp-php-standards": "^1.2" diff --git a/composer.lock b/composer.lock index d59b924..d7053c4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,104 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "778e891a53d3c414fe0ca1d505c0d973", + "content-hash": "998138ef441dc42e81a583d7175c7251", "packages": [ + { + "name": "doctrine/inflector", + "version": "1.4.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector", + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/1.4.4" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2021-04-16T17:34:40+00:00" + }, { "name": "mustache/mustache", "version": "v2.14.2", @@ -58,16 +154,16 @@ }, { "name": "newfold-labs/wp-module-ai", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/newfold-labs/wp-module-ai.git", - "reference": "c8b776496904213476a7b79f0b431aac5837e1b3" + "reference": "de39aa47b11d68c763087ac26cca674068d47161" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/newfold-labs/wp-module-ai/zipball/c8b776496904213476a7b79f0b431aac5837e1b3", - "reference": "c8b776496904213476a7b79f0b431aac5837e1b3", + "url": "https://api.github.com/repos/newfold-labs/wp-module-ai/zipball/de39aa47b11d68c763087ac26cca674068d47161", + "reference": "de39aa47b11d68c763087ac26cca674068d47161", "shasum": "" }, "require": { @@ -96,23 +192,23 @@ ], "description": "A module for providing artificial intelligence capabilities.", "support": { - "source": "https://github.com/newfold-labs/wp-module-ai/tree/1.1.5", + "source": "https://github.com/newfold-labs/wp-module-ai/tree/1.1.6", "issues": "https://github.com/newfold-labs/wp-module-ai/issues" }, - "time": "2024-02-27T15:16:54+00:00" + "time": "2024-02-29T10:39:41+00:00" }, { "name": "newfold-labs/wp-module-coming-soon", - "version": "1.2.0", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/newfold-labs/wp-module-coming-soon.git", - "reference": "74a6eab836e1d339f3650c68e89fd51b574e46bb" + "reference": "335bfe833ebdc072de55ed54cd6eebe0a210e43f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/newfold-labs/wp-module-coming-soon/zipball/74a6eab836e1d339f3650c68e89fd51b574e46bb", - "reference": "74a6eab836e1d339f3650c68e89fd51b574e46bb", + "url": "https://api.github.com/repos/newfold-labs/wp-module-coming-soon/zipball/335bfe833ebdc072de55ed54cd6eebe0a210e43f", + "reference": "335bfe833ebdc072de55ed54cd6eebe0a210e43f", "shasum": "" }, "require": { @@ -150,10 +246,64 @@ ], "description": "Coming Soon module for WordPress sites.", "support": { - "source": "https://github.com/newfold-labs/wp-module-coming-soon/tree/1.2.0", + "source": "https://github.com/newfold-labs/wp-module-coming-soon/tree/1.2.3", "issues": "https://github.com/newfold-labs/wp-module-coming-soon/issues" }, - "time": "2024-01-31T17:46:37+00:00" + "time": "2024-02-29T19:54:02+00:00" + }, + { + "name": "newfold-labs/wp-module-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/newfold-labs/wp-module-context.git", + "reference": "0d852f83f353f1631309e5ae7da9cb1e046bc984" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/newfold-labs/wp-module-context/zipball/0d852f83f353f1631309e5ae7da9cb1e046bc984", + "reference": "0d852f83f353f1631309e5ae7da9cb1e046bc984", + "shasum": "" + }, + "require": { + "wp-forge/helpers": "^2.0" + }, + "require-dev": { + "newfold-labs/wp-php-standards": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "NewfoldLabs\\WP\\Context\\": "includes" + }, + "files": [ + "includes/functions.php", + "bootstrap.php" + ] + }, + "scripts": { + "fix": [ + "vendor/bin/phpcbf . --standard=phpcs.xml" + ], + "lint": [ + "vendor/bin/phpcs . --standard=phpcs.xml -s" + ] + }, + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Evan Mullins", + "homepage": "https://evanmullins.com" + } + ], + "description": "Newfold module to determine context for various brands and platforms.", + "support": { + "source": "https://github.com/newfold-labs/wp-module-context/tree/1.0.0", + "issues": "https://github.com/newfold-labs/wp-module-context/issues" + }, + "time": "2024-02-22T18:22:13+00:00" }, { "name": "newfold-labs/wp-module-data", @@ -298,19 +448,20 @@ }, { "name": "newfold-labs/wp-module-performance", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/newfold-labs/wp-module-performance.git", - "reference": "4ac17a7ad77bb39cd90ebbb5cb207ede5336dbac" + "reference": "3d11c8da5928cc29899876bf9b1ea41b76cfc8cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/newfold-labs/wp-module-performance/zipball/4ac17a7ad77bb39cd90ebbb5cb207ede5336dbac", - "reference": "4ac17a7ad77bb39cd90ebbb5cb207ede5336dbac", + "url": "https://api.github.com/repos/newfold-labs/wp-module-performance/zipball/3d11c8da5928cc29899876bf9b1ea41b76cfc8cd", + "reference": "3d11c8da5928cc29899876bf9b1ea41b76cfc8cd", "shasum": "" }, "require": { + "newfold-labs/wp-module-context": "^1.0", "wp-forge/collection": "^1.0", "wp-forge/wp-htaccess-manager": "^1.0", "wpscholar/url": "^1.2" @@ -336,10 +487,10 @@ ], "description": "A module for managing caching functionality.", "support": { - "source": "https://github.com/newfold-labs/wp-module-performance/tree/1.3.0", + "source": "https://github.com/newfold-labs/wp-module-performance/tree/1.4.0", "issues": "https://github.com/newfold-labs/wp-module-performance/issues" }, - "time": "2023-12-04T23:27:28+00:00" + "time": "2024-02-27T20:09:07+00:00" }, { "name": "wp-forge/collection", @@ -378,6 +529,50 @@ }, "time": "2022-08-26T17:42:31+00:00" }, + { + "name": "wp-forge/helpers", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/wp-forge/helpers.git", + "reference": "28ebc09a3390dbff427270a4ed2b93395e8b9b78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wp-forge/helpers/zipball/28ebc09a3390dbff427270a4ed2b93395e8b9b78", + "reference": "28ebc09a3390dbff427270a4ed2b93395e8b9b78", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.3", + "ext-mbstring": "*" + }, + "type": "library", + "autoload": { + "files": [ + "includes/functions.php" + ], + "psr-4": { + "WP_Forge\\Helpers\\": "includes" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Micah Wood", + "email": "micah@wpscholar.com" + } + ], + "description": "A collection of helpers for WordPress and PHP development.", + "support": { + "issues": "https://github.com/wp-forge/helpers/issues", + "source": "https://github.com/wp-forge/helpers/tree/2.0" + }, + "time": "2022-01-06T13:10:47+00:00" + }, { "name": "wp-forge/wp-htaccess-manager", "version": "1.0", diff --git a/includes/Services/SiteGenService.php b/includes/Services/SiteGenService.php index 8e47cf3..809cd5b 100644 --- a/includes/Services/SiteGenService.php +++ b/includes/Services/SiteGenService.php @@ -133,6 +133,10 @@ public static function instantiate_site_meta( $site_info, $identifier, $skip_cac * @return boolean */ public static function complete( $active_homepage, $homepage_data ) { + /* Replace dalle images */ + + $active_homepage['content'] = self::sideload_images_and_replace_grammar( $active_homepage['content'], $active_homepage['generatedImages'] ); + $show_pages_on_front = \get_option( Options::get_option_name( 'show_on_front', false ) ); // Check if default homepage is posts. @@ -140,7 +144,7 @@ public static function complete( $active_homepage, $homepage_data ) { \update_option( Options::get_option_name( 'show_on_front', false ), 'page' ); } - // Setting page title from sitemap option + // Setting page title from sitemap option. $title = $active_homepage['title']; $prompt = self::get_prompt(); $site_info = array( 'site_description' => $prompt ); @@ -194,7 +198,11 @@ public static function complete( $active_homepage, $homepage_data ) { if ( $data['isFavorite'] && $data['slug'] !== $active_homepage['slug'] ) { self::generate_child_theme( $data ); } + if ( $data['slug'] === $active_homepage['slug'] ) { + $homepage_data[ $active_homepage['slug'] ] = $active_homepage; + } } + self::sync_flow_data( $homepage_data ); ThemeGeneratorService::activate_theme( $active_homepage['slug'] ); @@ -473,13 +481,14 @@ public static function process_homepages_response( $homepage_slug = 'version-' . $version_number; $processed_homepages[ $homepage_slug ] = array( - 'slug' => $homepage_slug, - 'title' => __( 'Version ', 'wp-module-onboarding' ) . $version_number, - 'isFavorite' => false, - 'content' => $data['content'], - 'header' => $data['header'], - 'footer' => $data['footer'], - 'color' => $selected_palette, + 'slug' => $homepage_slug, + 'title' => __( 'Version ', 'wp-module-onboarding' ) . $version_number, + 'isFavorite' => false, + 'content' => $data['content'], + 'header' => $data['header'], + 'footer' => $data['footer'], + 'color' => $selected_palette, + 'generatedImages' => $data['generatedImages'], ); ++$version_number; } @@ -915,12 +924,12 @@ public static function instantiate_sitegen_hooks() { */ public static function set_site_title_and_tagline( $site_details ) { - // Updates the Site Title + // Updates the Site Title. if ( ( ! empty( $site_details['site_title'] ) ) ) { \update_option( Options::get_option_name( 'blog_name', false ), $site_details['site_title'] ); } - // Updates the Site Desc (Tagline) + // Updates the Site Desc (Tagline). if ( ( ! empty( $site_details['tagline'] ) ) ) { \update_option( Options::get_option_name( 'blog_description', false ), $site_details['tagline'] ); } @@ -989,4 +998,160 @@ public static function get_nav_link_grammar_from_post_data( $id, $name, $url ) { return "<!-- wp:navigation-link {\"label\":\"$name\",\"type\":\"page\",\"id\":$id,\"url\":\"$url\",\"kind\":\"post-type\"} /-->"; } + + /** + * Uploads images to the WordPress media library as attachments. + * + * This function takes an array of image URLs, downloads them, and + * uploads them to the WordPress media library, returning the URLs + * of the newly uploaded images. + * + * @param array $image_urls An array of image URLs to upload. + * @return array|false An array of WordPress attachment URLs on success, false on failure. + * @throws Exception If there is an error during the upload process. + */ + public static function upload_images_to_wp_media_library( $image_urls ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + require_once ABSPATH . 'wp-admin/includes/media.php'; + require_once ABSPATH . 'wp-admin/includes/image.php'; + + $uploaded_image_urls = array(); + try { + foreach ( $image_urls as $image_url ) { + // Check if the URL is valid. + if ( ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) { + continue; + } + + // Fetch the image via remote get. + $response = wp_remote_get( $image_url ); + if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { + continue; + } + + // Reading the headers from the image url to determine. + $headers = wp_remote_retrieve_headers( $response ); + $content_type = $headers['content-type'] ?? ''; + $image_data = wp_remote_retrieve_body( $response ); + if ( empty( $content_type ) || empty( $image_data ) ) { + continue; + } + + // Determine the file extension based on MIME type. + $file_extension = ''; + switch ( $content_type ) { + case 'image/jpeg': + $file_extension = '.jpg'; + break; + case 'image/png': + $file_extension = '.png'; + break; + case 'image/gif': + $file_extension = '.gif'; + break; + case 'image/webp': + $file_extension = '.webp'; + break; + default: + error_log( 'Unsupported MIME type: ' . $content_type ); + continue; + } + // create upload directory. + $upload_dir = wp_upload_dir(); + + // xtract a filename from the URL. + $parsed_url = parse_url( $image_url ); + $path_parts = pathinfo( $parsed_url['path'] ); + // filename to be added in directory. + $original_filename = $path_parts['filename'] . $file_extension; + + // to ensure the filename is unique within the upload directory. + $filename = wp_unique_filename( $upload_dir['path'], $original_filename ); + $filepath = $upload_dir['path'] . '/' . $filename; + + // Saving the image to the uploads directory. + file_put_contents( $filepath, $image_data ); + + // Create an attachment post for the image, metadata needed for WordPress media library. + // guid -for url, post_title for cleaned up name, post content is empty as this is an attachment. + // post_status inherit is for visibility. + $attachment = array( + 'guid' => $upload_dir['url'] . '/' . $filename, + 'post_mime_type' => $content_type, + 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ), + 'post_content' => '', + 'post_status' => 'inherit', + ); + + $attach_id = wp_insert_attachment( $attachment, $filepath ); + + // Generate and assign metadata for the attachment.. + $attach_data = wp_generate_attachment_metadata( $attach_id, $filepath ); + wp_update_attachment_metadata( $attach_id, $attach_data ); + + // Add the WordPress attachment URL to the list.. + if ( $attach_id ) { + $attachment_url = wp_get_attachment_url( $attach_id ); + if ( ! $attachment_url ) { + error_log( 'Failed to retrieve attachment URL for attachment ID: ' . $attach_id ); + $attachment_url = null; + } + $uploaded_image_urls[ $image_url ] = $attachment_url; + } + } + } catch ( Exception $e ) { + error_log( $e->getMessage() ); + } + + return $uploaded_image_urls; + } + + /** + * Replace the uploaded images in the block grammar. + * + * This function takes a block of content and an array of new image URLs, uploads the images + * to the WordPress media library, and then replaces the old image URLs in the content + * with the new ones. + * + * @param array $content The block grammar containing the old image URLs. + * @param array $generated_image_urls An array of new image URLs to replace the old ones in the content. + */ + public static function sideload_images_and_replace_grammar( $content, $generated_image_urls ) { + + if ( ! isset( $generated_image_urls ) || ! is_array( $generated_image_urls ) ) { + return; + } + // Upload the images in the 'generatedImages' array to WordPress media library. + $url_mapping = self::upload_images_to_wp_media_library( $generated_image_urls ); + + foreach ( $url_mapping as $old_url => $new_url ) { + if ( null === $new_url ) { + continue; + } + // escaping any special characters in the old URL to avoid breaking the regex. + $escaped_old_url = preg_quote( $old_url, '/' ); + + $escaped_old_url_regex_double_quote = '/"' . $escaped_old_url . '.*?"/m'; + $content = preg_replace( $escaped_old_url_regex_double_quote, '"' . $new_url . '"', $content ); + + $escaped_old_url_regex_parenthesis = '/\(' . $escaped_old_url . '.*?\)/m'; + $content = preg_replace( $escaped_old_url_regex_parenthesis, '(' . $new_url . ')', $content ); + } + + // Update the content with new image URLs. + return $content; + } + + /** + * Syncs flow data with new updates. + * + * This function is responsible for updating the flow data with new home page data changes. + * + * @param array $updated_data The new data to be integrated into the existing flow data. + */ + public static function sync_flow_data( $updated_data ) { + $data = FlowService::read_data_from_wp_option( false ); + $data['sitegen']['homepages']['data'] = $updated_data; + FlowService::update_data_in_wp_option( $data ); + } }