Created
November 19, 2021 23:58
-
-
Save westonruter/c385a90aaf9f69157bb8a41c974d8150 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Sabberworm\CSS\Parser; | |
use Sabberworm\CSS\RuleSet\DeclarationBlock; | |
$dom = new DOMDocument(); | |
$dom->loadHTML( | |
' | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<style> | |
img#nod { | |
aspect-ratio: 1 / 1; | |
width: 100%; | |
} | |
</style> | |
</head> | |
<body> | |
<img id="nod" src="https://media.giphy.com/media/xSM46ernAUN3y/giphy.gif"> | |
</body> | |
</html> | |
' | |
); | |
$xpath = new DOMXPath( $dom ); | |
$img_query = $xpath->query( | |
' | |
//img[ | |
starts-with( | |
@src, | |
"https://media.giphy.com/media/" | |
) | |
and | |
contains( @src, ".gif" ) | |
] | |
' | |
); | |
foreach ( $img_query as $img ) { | |
/** @var DOMElement $img */ | |
$video = $dom->createElement( 'video' ); | |
// Capture and remove ID so it can be added to replacement. | |
// IMPORTANT: Thus must be done separately from copying the other attributes. | |
$id = $img->getAttribute( 'id' ); | |
if ( $id ) { | |
$img->removeAttribute( 'id' ); | |
$video->setAttribute( 'id', $id ); | |
} | |
foreach ( $img->attributes as $attribute ) { | |
$video->setAttribute( $attribute->nodeName, $attribute->nodeValue ); | |
} | |
foreach ( [ 'autoplay', 'loop', 'muted', 'playsinline' ] as $boolean_attribute ) { | |
$video->setAttributeNode( $dom->createAttribute( $boolean_attribute ) ); | |
} | |
// Replace gif with mp4. | |
$video->setAttribute( | |
'src', | |
preg_replace( | |
':/giphy(-.+?)?\.gif:', | |
'/giphy.mp4', | |
$img->getAttribute( 'src' ) | |
) | |
); | |
// Finally, swap out the img with the video. | |
$img->parentNode->replaceChild( $video, $img ); | |
} | |
echo "# The document prior to style processing:\n"; | |
echo $dom->saveHTML() . "\n"; | |
foreach ( $xpath->query( '//style' ) as $style ) { | |
/** @var DOMElement $style */ | |
$parser = new Parser( $style->textContent ); | |
$parsed = $parser->parse(); | |
foreach ( $parsed->getAllDeclarationBlocks() as $declaration_block ) { | |
/** @var DeclarationBlock $declaration_block */ | |
$ids = []; | |
foreach ( $declaration_block->getSelectors() as $selector ) { | |
// This ID extractor is admittedly rudimentary. | |
if ( preg_match( '/#([a-z0-9_-]+)/', $selector, $matches ) ) { | |
$ids[] = $matches[1]; | |
} else { | |
// If we couldn't parse an ID out, then skip the whole block. | |
continue 2; | |
} | |
} | |
// Now inline the declaration blocks as style attributes. | |
foreach ( $ids as $id ) { | |
$element = $dom->getElementById( $id ); | |
if ( ! $element ) { | |
continue; | |
} | |
$styles = []; | |
foreach ( $declaration_block->getRules() as $rule ) { | |
$styles[] = (string) $rule; | |
} | |
if ( $element->hasAttribute( 'style' ) ) { | |
$styles[] = $element->getAttribute( 'style' ); | |
} | |
$element->setAttribute( 'style', implode( '', $styles ) ); | |
} | |
$parsed->remove( $declaration_block ); | |
} | |
// Update the stylesheet to remove the inlined style rules. | |
$css_text = $parsed->render(); | |
if ( ! $css_text ) { | |
$style->parentNode->removeChild( $style ); | |
} else { | |
$style->textContent = $parsed->render(); | |
} | |
} | |
echo "# The nod element as returned by getElementById:\n"; | |
$element = $dom->getElementById( 'nod' ); | |
if ( $element ) { | |
echo $dom->saveHTML( $dom->getElementById( 'nod' ) ) . "\n"; | |
} else { | |
echo "NULL\n"; | |
} | |
echo "\n"; | |
echo "# The element with the 'nod' ID as queried by XPath:\n"; | |
echo $dom->saveHTML( $xpath->query( '//*[ @id = "nod" ]' )->item( 0 ) ) . "\n"; | |
echo "\n"; | |
echo "# The entire document:\n"; | |
echo $dom->saveHTML(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment