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

Bundle template images into theme assets and make their urls relative #213

Merged
merged 13 commits into from
Feb 17, 2023
Merged
Changes from 6 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
311 changes: 298 additions & 13 deletions admin/class-create-block-theme-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,184 @@ function get_theme_templates( $export_type, $new_slug ) {

}

function is_absolute_url( $url ) {
return isset( parse_url( $url )[ 'host' ] );
}

function make_relative_image_url ( $absolute_url ) {
return '<?php echo esc_url( get_stylesheet_directory_uri() ); ?>/assets/images/'. basename( $absolute_url );
}

function make_html_images_local ( $html ) {
if ( empty( $html ) ) {
return $html;
}
$doc = new DOMDocument();
@$doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
$img_tags = $doc->getElementsByTagName( 'img' );
// replace all images that have absolute urls
foreach ( $img_tags as $tag ) {
$image_url = $tag->getAttribute( 'src' );
if ( $this->is_absolute_url( $image_url ) ) {
$img_src = $tag->getAttribute( 'src' );
$html = str_replace( $img_src, $this->make_relative_image_url( $img_src ), $html );
}
}
// also replace background images with absolute urls (used in cover blocks)
$div_tags = $doc->getElementsByTagName( 'div' );
foreach ( $div_tags as $tag ) {
$style = $tag->getAttribute( 'style' );
if ( $style ) {
preg_match_all('#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#', $style, $match);
$urls = $match[0];
foreach ( $urls as $url ) {
if ( $this->is_absolute_url( $url ) ) {
$html = str_replace( $url, $this->make_relative_image_url( $url ), $html );
}
}
}
}
return $html;
}

function make_image_block_local ( $block ) {
if ( 'core/image' === $block[ 'blockName' ] ) {
$inner_html = $this->make_html_images_local( $block[ 'innerHTML' ] );
$block['innerHTML'] = $inner_html;
$block['innerContent'] = array ( $inner_html );
}
return $block;
}

function make_cover_block_local ( $block ) {
if ( 'core/cover' === $block[ 'blockName' ] ) {
$inner_html = $this->make_html_images_local( $block[ 'innerHTML' ] );
$inner_content = [];
foreach ( $block['innerContent'] as $content ) {
$content_html = $this->make_html_images_local( $content );
$inner_content[] = $content_html;
}
$block['innerHTML'] = $inner_html;
$block['innerContent'] = $inner_content;
if ( isset ( $block['attrs']['url'] ) && $this->is_absolute_url( $block['attrs']['url'] ) ) {
$block['attrs']['url'] = $this->make_relative_image_url( $block['attrs']['url'] );
}
}
return $block;
}

function make_mediatext_block_local ( $block ) {
if ( 'core/media-text' === $block[ 'blockName' ] ) {
$inner_html = $this->make_html_images_local( $block[ 'innerHTML' ] );
$inner_content = [];
foreach ( $block['innerContent'] as $content ) {
$content_html = $this->make_html_images_local( $content );
$inner_content[] = $content_html;
}
$block['innerHTML'] = $inner_html;
$block['innerContent'] = $inner_content;
if ( isset ( $block['attrs']['mediaLink'] ) && $this->is_absolute_url( $block['attrs']['mediaLink'] ) ) {
$block['attrs']['mediaLink'] = $this->make_relative_image_url( $block['attrs']['mediaLink'] );
}
}
return $block;
}

function make_media_blocks_local ( $nested_blocks ) {
$new_blocks = [];
foreach ( $nested_blocks as $block ) {
$inner_blocks = $block['innerBlocks'];
$block = $this->make_image_block_local( $block );
$block = $this->make_cover_block_local( $block );
$block = $this->make_mediatext_block_local( $block );

// recursive call for inner blocks
if ( !empty ( $block['innerBlocks'] ) ) {
$block['innerBlocks'] = $this->make_media_blocks_local( $inner_blocks );
}
$new_blocks[] = $block;
}
return $new_blocks;
}

function get_media_absolute_urls_from_blocks ( $flatten_blocks ) {
$media = [];
foreach ( $flatten_blocks as $block ) {
if ( 'core/image' === $block[ 'blockName' ] || 'core/cover' === $block[ 'blockName' ] ) {
$doc = new DOMDocument();
@$doc->loadHTML( $block['innerHTML'], LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );

// Get the media urls from img tags
$tags = $doc->getElementsByTagName( 'img' );
$block_has_external_images = false;
foreach ($tags as $tag) {
$image_url = $tag->getAttribute( 'src' );
if ($this->is_absolute_url( $image_url )) {
$media[] = $tag->getAttribute( 'src' );
}
}
// Get the media urls from div style tags (used in cover blocks)
$div_tags = $doc->getElementsByTagName( 'div' );
foreach ( $div_tags as $tag ) {
$style = $tag->getAttribute( 'style' );
if ( $style ) {
preg_match_all('#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#', $style, $match);
$urls = $match[0];
foreach ( $urls as $url ) {
if ( $this->is_absolute_url( $url ) ) {
$media[] = $url;
}
}
}
}
}
}
return $media;
}

// find all the media files used in the templates and add them to the zip
function make_template_images_local ( $template ) {
$new_content = $template->content;
$template_blocks = parse_blocks( $template->content );
$flatten_blocks = _flatten_blocks( $template_blocks );

$blocks = $this->make_media_blocks_local( $template_blocks );
$blocks = serialize_blocks ( $blocks );

$template->content = $this->clean_serialized_markup ( $blocks );
$template->media = $this->get_media_absolute_urls_from_blocks ( $flatten_blocks );
return $template;
}

function clean_serialized_markup ( $markup ) {
$markup = str_replace( '%20', ' ', $markup );
$markup = str_replace( '&lt;', '<', $markup );
$markup = str_replace( '&gt;', '>', $markup );
$markup = str_replace( '\u003c', '<', $markup );
$markup = str_replace( '\u003e', '>', $markup );
return $markup;
}

function pattern_from_template ( $template ) {
$theme_slug = wp_get_theme()->get( 'TextDomain' );
$pattern_slug = $theme_slug . '/' . $template->slug;
$pattern_content = (
'<?php
/**
* Title: '. $template->slug .'
* Slug: ' . $pattern_slug. '
* Categories: hidden
* Inserter: no
*/
?>
'. $template->content
);
return array (
'slug' => $pattern_slug,
'content' => $pattern_content
);
}

/**
* Add block templates and parts to the zip.
*
Expand All @@ -567,7 +745,6 @@ function get_theme_templates( $export_type, $new_slug ) {
* all = all templates no matter what
*/
function add_templates_to_zip( $zip, $export_type, $new_slug ) {

$theme_templates = $this->get_theme_templates( $export_type, $new_slug );

if ( $theme_templates->templates ) {
Expand All @@ -579,16 +756,59 @@ function add_templates_to_zip( $zip, $export_type, $new_slug ) {
}

foreach ( $theme_templates->templates as $template ) {
$template_data = $this->make_template_images_local( $template );

// If there are images in the template, add it as a pattern
if ( count( $template_data->media ) > 0 ) {
$pattern = $this->pattern_from_template( $template_data );
$template_data->content = '<!-- wp:pattern {"slug":"'. $pattern[ 'slug' ] .'"} /-->';

// Add pattern to zip
$zip->addFromString(
'patterns/' . $template_data->slug . '.php',
$pattern[ 'content' ]
);

// Add image assets to zip
foreach ( $template_data->media as $media ) {
$download_file = file_get_contents( $media );
$zip->addFromString( 'assets/images/' . basename( $media ), $download_file );
}
}

// Add template to zip
$zip->addFromString(
'templates/' . $template->slug . '.html',
$template->content
'templates/' . $template_data->slug . '.html',
$template_data->content
);

}

foreach ( $theme_templates->parts as $template_part ) {
$template_data = $this->make_template_images_local( $template_part );

// If there are images in the template, add it as a pattern
if ( count( $template_data->media ) > 0 ) {
$pattern = $this->pattern_from_template( $template_data );
$template_data->content = '<!-- wp:pattern {"slug":"'. $pattern[ 'slug' ] .'"} /-->';

// Add pattern to zip
$zip->addFromString(
'patterns/' . $template_data->slug . '.php',
$pattern[ 'content' ]
);

// Add image assets to zip
foreach ( $template_data->media as $media ) {
$download_file = file_get_contents( $media );
$zip->addFromString( 'assets/images/' . basename( $media ), $download_file );
}
}

// Add template to zip
$zip->addFromString(
'parts/' . $template_part->slug . '.html',
$template_part->content
'parts/' . $template_data->slug . '.html',
$template_data->content
);
}

Expand All @@ -601,27 +821,92 @@ function add_templates_to_local( $export_type ) {
$template_folders = get_block_theme_folders();

// If there is no templates folder, create it.
if ( ! is_dir( get_stylesheet_directory() . '/' . $template_folders['wp_template'] ) ) {
wp_mkdir_p( get_stylesheet_directory() . '/' . $template_folders['wp_template'] );
if ( ! is_dir( get_stylesheet_directory() . DIRECTORY_SEPARATOR . $template_folders['wp_template'] ) ) {
wp_mkdir_p( get_stylesheet_directory() . DIRECTORY_SEPARATOR . $template_folders['wp_template'] );
}

if ( ! is_dir( get_stylesheet_directory() . '/assets/images' ) ) {
wp_mkdir_p( get_stylesheet_directory() . '/assets/images' );
}

foreach ( $theme_templates->templates as $template ) {
$template_data = $this->make_template_images_local( $template );

// If there are images in the template, add it as a pattern
if ( ! empty ( $template_data->media ) ) {
// If there is no templates folder, create it.
if ( ! is_dir( get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'patterns' ) ) {
wp_mkdir_p( get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'patterns' );
}

// If there are external images, add it as a pattern
$pattern = $this->pattern_from_template( $template_data );
$template_data->content = '<!-- wp:pattern {"slug":"'. $pattern[ 'slug' ] .'"} /-->';

// Write the pattern
file_put_contents(
get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'patterns' . DIRECTORY_SEPARATOR . $template_data->slug . '.php',
$pattern[ 'content' ]
);
}

// Write the template content
file_put_contents(
get_stylesheet_directory() . '/' . $template_folders['wp_template'] . '/' . $template->slug . '.html',
$template->content
get_stylesheet_directory() . DIRECTORY_SEPARATOR . $template_folders['wp_template'] . DIRECTORY_SEPARATOR . $template->slug . '.html',
$template_data->content
);

// Write the image assets
foreach ( $template_data->media as $media ) {
$download_file = file_get_contents( $media );
file_put_contents(
get_stylesheet_directory() . DIRECTORY_SEPARATOR .'assets' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . basename( $media ),
$download_file
);
}

}

// If there is no parts folder, create it.
if ( ! is_dir( get_stylesheet_directory() . '/' . $template_folders['wp_template_part'] ) ) {
wp_mkdir_p( get_stylesheet_directory() . '/' . $template_folders['wp_template_part'] );
if ( ! is_dir( get_stylesheet_directory() . DIRECTORY_SEPARATOR . $template_folders['wp_template_part'] ) ) {
wp_mkdir_p( get_stylesheet_directory() . DIRECTORY_SEPARATOR . $template_folders['wp_template_part'] );
}

foreach ( $theme_templates->parts as $template_part ) {
$template_data = $this->make_template_images_local( $template_part );

// If there are images in the template, add it as a pattern
if ( ! empty ( $template_data->media ) ) {
// If there is no templates folder, create it.
if ( ! is_dir( get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'patterns' ) ) {
wp_mkdir_p( get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'patterns' );
}

// If there are external images, add it as a pattern
$pattern = $this->pattern_from_template( $template_data );
$template_data->content = '<!-- wp:pattern {"slug":"'. $pattern[ 'slug' ] .'"} /-->';

// Write the pattern
file_put_contents(
get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'patterns' . DIRECTORY_SEPARATOR . $template_data->slug . '.php',
$pattern[ 'content' ]
);
}

// Write the template content
file_put_contents(
get_stylesheet_directory() . '/' . $template_folders['wp_template_part'] . '/' . $template_part->slug . '.html',
$template_part->content
get_stylesheet_directory() . DIRECTORY_SEPARATOR . $template_folders['wp_template_part'] . DIRECTORY_SEPARATOR . $template_data->slug . '.html',
$template_data->content
);

// Write the image assets
foreach ( $template_data->media as $media ) {
$download_file = file_get_contents( $media );
file_put_contents(
get_stylesheet_directory() . DIRECTORY_SEPARATOR .'assets' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . basename( $media ),
$download_file
);
}
}
}

Expand Down