Skip to content

Commit 832ce88

Browse files
committed
separating out the code for ThemeGeneratorService
1 parent f7f823b commit 832ce88

File tree

3 files changed

+269
-224
lines changed

3 files changed

+269
-224
lines changed

bootstrap.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,12 @@ function () {
8080
delete_transient( 'nfd_site_capabilities' );
8181
}
8282
);
83+
84+
// Register AJAX handlers for image processing
85+
add_action(
86+
'init',
87+
function () {
88+
\NewfoldLabs\WP\Module\Onboarding\Services\ThemeGeneratorService::register_ajax_handlers();
89+
}
90+
);
8391
}

includes/Services/SiteGenService.php

Lines changed: 2 additions & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use NewfoldLabs\WP\Module\Onboarding\Data\Services\SitePagesService;
66
use NewfoldLabs\WP\Module\Onboarding\Data\Services\SiteGenService as LegacySiteGenService;
7-
use NewfoldLabs\WP\Module\Onboarding\Data\Services\ThemeGeneratorService;
7+
use NewfoldLabs\WP\Module\Onboarding\Services\ThemeGeneratorService;
88
use NewfoldLabs\WP\Module\Onboarding\Services\ReduxStateService;
99

1010
/**
@@ -40,69 +40,6 @@ class SiteGenService {
4040
public function __construct() {
4141
$this->input_data = ReduxStateService::get( 'input' );
4242
$this->sitegen_data = ReduxStateService::get( 'sitegen' );
43-
44-
// Register AJAX handler for immediate async processing
45-
add_action( 'wp_ajax_sitegen_process_images_async', array( $this, 'handle_ajax_image_processing' ) );
46-
add_action( 'wp_ajax_nopriv_sitegen_process_images_async', array( $this, 'handle_ajax_image_processing' ) );
47-
}
48-
49-
/**
50-
* Handle AJAX request for immediate async image processing.
51-
*/
52-
public function handle_ajax_image_processing() {
53-
// Verify nonce for security
54-
if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'sitegen_async_images' ) ) {
55-
wp_die( 'Security check failed' );
56-
}
57-
58-
$post_id = intval( $_POST['post_id'] ?? 0 );
59-
$content = sanitize_textarea_field( $_POST['content'] ?? '' );
60-
61-
if ( ! $post_id || ! $content ) {
62-
wp_die( 'Invalid parameters' );
63-
}
64-
65-
// Process images
66-
$updated_content = self::sideload_images_and_replace_grammar( $content, $post_id );
67-
if ( $updated_content !== $content ) {
68-
wp_update_post(
69-
array(
70-
'ID' => $post_id,
71-
'post_content' => $updated_content,
72-
)
73-
);
74-
}
75-
76-
wp_die( 'Success' );
77-
}
78-
79-
80-
81-
/**
82-
* Process homepage images immediately in background (alternative to cron).
83-
* This method dispatches an async request that doesn't block the main request.
84-
*
85-
* @param int $post_id The post ID to process images for.
86-
* @param string $content The content containing images.
87-
*/
88-
public function process_homepage_images_immediate_async( $post_id, $content ) {
89-
// Use wp_remote_post to make an async request to the same site
90-
$admin_url = admin_url( 'admin-ajax.php' );
91-
$nonce = wp_create_nonce( 'sitegen_async_images' );
92-
93-
wp_remote_post(
94-
$admin_url,
95-
array(
96-
'timeout' => 0.01, // Very short timeout to not block
97-
'blocking' => false, // Non-blocking request
98-
'body' => array(
99-
'action' => 'sitegen_process_images_async',
100-
'post_id' => $post_id,
101-
'content' => $content,
102-
'nonce' => $nonce,
103-
),
104-
)
105-
);
10643
}
10744

10845
/**
@@ -144,7 +81,7 @@ public function publish_homepage( string $selected_sitegen_homepage ) {
14481
}
14582

14683
// Process images immediately in background (non-blocking)
147-
$this->process_homepage_images_immediate_async( $post_id, $content );
84+
ThemeGeneratorService::process_homepage_images_immediate_async( $post_id, $content );
14885

14986
// Add the homepage to the site navigation.
15087
$this->add_page_to_navigation( $post_id, $title, get_permalink( $post_id ) );
@@ -243,163 +180,4 @@ public function get_site_type() {
243180
public function get_locale() {
244181
return ! empty( $this->input_data['locale'] ) ? $this->input_data['locale'] : 'en_US';
245182
}
246-
247-
/**
248-
* Uploads images to the WordPress media library as attachments.
249-
*
250-
* This function takes an array of image URLs, downloads them, and
251-
* uploads them to the WordPress media library, returning the URLs
252-
* of the newly uploaded images.
253-
*
254-
* @param array $image_urls An array of image URLs to upload.
255-
* @param int $post_id The post ID to attach the images to.
256-
* @return array|false An array of WordPress attachment URLs on success, false on failure.
257-
* @throws Exception If there is an error during the upload process.
258-
*/
259-
public static function upload_images_to_wp_media_library( $image_urls, $post_id ) {
260-
require_once ABSPATH . 'wp-admin/includes/media.php';
261-
require_once ABSPATH . 'wp-admin/includes/image.php';
262-
263-
global $wp_filesystem;
264-
ThemeGeneratorService::connect_to_filesystem();
265-
266-
$uploaded_image_urls = array();
267-
try {
268-
foreach ( $image_urls as $image_url ) {
269-
// Check if the URL is valid.
270-
if ( ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) {
271-
continue;
272-
}
273-
274-
// Fetch the image via remote get with timeout and a retry attempt.
275-
$attempt = 0;
276-
$max_attempts = 2;
277-
while ( $attempt < $max_attempts ) {
278-
$response = wp_remote_get( $image_url, array( 'timeout' => 15 ) );
279-
if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
280-
break;
281-
}
282-
++$attempt;
283-
}
284-
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
285-
continue;
286-
}
287-
// Reading the headers from the image url to determine.
288-
$headers = wp_remote_retrieve_headers( $response );
289-
$content_type = $headers['content-type'] ?? '';
290-
$image_data = wp_remote_retrieve_body( $response );
291-
if ( empty( $content_type ) || empty( $image_data ) ) {
292-
continue;
293-
}
294-
// Determine the file extension based on MIME type.
295-
$file_extension = '';
296-
switch ( $content_type ) {
297-
case 'image/jpeg':
298-
$file_extension = '.jpg';
299-
break;
300-
case 'image/png':
301-
$file_extension = '.png';
302-
break;
303-
case 'image/gif':
304-
$file_extension = '.gif';
305-
break;
306-
case 'image/webp':
307-
$file_extension = '.webp';
308-
break;
309-
}
310-
311-
if ( '' === $file_extension ) {
312-
continue;
313-
}
314-
// create upload directory.
315-
$upload_dir = wp_upload_dir();
316-
// xtract a filename from the URL.
317-
$parsed_url = wp_parse_url( $image_url );
318-
$path_parts = pathinfo( $parsed_url['path'] );
319-
// filename to be added in directory.
320-
$original_filename = $path_parts['filename'] . $file_extension;
321-
322-
// to ensure the filename is unique within the upload directory.
323-
$filename = wp_unique_filename( $upload_dir['path'], $original_filename );
324-
$filepath = $upload_dir['path'] . '/' . $filename;
325-
326-
$wp_filesystem->put_contents( $filepath, $image_data );
327-
328-
// Create an attachment post for the image, metadata needed for WordPress media library.
329-
// guid -for url, post_title for cleaned up name, post content is empty as this is an attachment.
330-
// post_status inherit is for visibility.
331-
$attachment = array(
332-
'guid' => $upload_dir['url'] . '/' . $filename,
333-
'post_mime_type' => $content_type,
334-
'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
335-
'post_content' => '',
336-
'post_status' => 'inherit',
337-
'post_parent' => $post_id, // Attach to the specified post
338-
);
339-
$attach_id = wp_insert_attachment( $attachment, $filepath );
340-
341-
// Generate and assign metadata for the attachment.
342-
$attach_data = wp_generate_attachment_metadata( $attach_id, $filepath );
343-
wp_update_attachment_metadata( $attach_id, $attach_data );
344-
345-
// Add the WordPress attachment URL to the list.
346-
if ( $attach_id ) {
347-
$attachment_url = wp_get_attachment_url( $attach_id );
348-
if ( ! $attachment_url ) {
349-
$attachment_url = null;
350-
}
351-
$uploaded_image_urls[ $image_url ] = $attachment_url;
352-
}
353-
}
354-
} catch ( \Exception $e ) {
355-
// Log error.
356-
}
357-
358-
return $uploaded_image_urls;
359-
}
360-
361-
/**
362-
* Extract image URLs from content and upload them to WordPress media library.
363-
*
364-
* This function extracts image URLs from img tags in the content, uploads the images
365-
* to the WordPress media library, and then replaces the old image URLs in the content
366-
* with the new ones.
367-
*
368-
* @param string $content The content containing img tags with image URLs.
369-
* @param int $post_id The post ID to attach the images to.
370-
* @return string The updated content with new image URLs.
371-
*/
372-
public static function sideload_images_and_replace_grammar( $content, $post_id ) {
373-
// Extract image URLs from img tags in the content
374-
$image_urls = array();
375-
preg_match_all( '/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $content, $matches );
376-
377-
if ( ! empty( $matches[1] ) ) {
378-
$image_urls = array_unique( $matches[1] );
379-
}
380-
381-
if ( empty( $image_urls ) ) {
382-
return $content;
383-
}
384-
385-
// Upload the images to WordPress media library.
386-
$url_mapping = self::upload_images_to_wp_media_library( $image_urls, $post_id );
387-
388-
foreach ( $url_mapping as $old_url => $new_url ) {
389-
if ( null === $new_url ) {
390-
continue;
391-
}
392-
// escaping any special characters in the old URL to avoid breaking the regex.
393-
$escaped_old_url = preg_quote( $old_url, '/' );
394-
395-
$escaped_old_url_regex_double_quote = '/"' . $escaped_old_url . '.*?"/m';
396-
$content = preg_replace( $escaped_old_url_regex_double_quote, '"' . $new_url . '"', $content );
397-
398-
$escaped_old_url_regex_parenthesis = '/\(' . $escaped_old_url . '.*?\)/m';
399-
$content = preg_replace( $escaped_old_url_regex_parenthesis, '(' . $new_url . ')', $content );
400-
}
401-
402-
// Update the content with new image URLs.
403-
return $content;
404-
}
405183
}

0 commit comments

Comments
 (0)