{"id":6181,"date":"2021-09-05T08:49:11","date_gmt":"2021-09-05T06:49:11","guid":{"rendered":"https:\/\/florianbrinkmann.com\/en\/?p=6181"},"modified":"2021-09-05T08:50:10","modified_gmt":"2021-09-05T06:50:10","slug":"php-css-parser","status":"publish","type":"post","link":"https:\/\/florianbrinkmann.com\/en\/php-css-parser-6181\/","title":{"rendered":"Prepend a class to CSS selectors in PHP"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">For a slider Gutenberg block, I added the option to enter custom CSS into a text field, that should only apply to that one block. Of course, the user should not need to write the selector that way, that it only applies to this specific block \u2013 that should be done in the background before rendering the frontend markup.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To get this done, I searched for a PHP solution for PHP parsing and found the right tool with <strong><a href=\"https:\/\/github.com\/sabberworm\/PHP-CSS-Parser\">PHP CSS Parser<\/a><\/strong>.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">Installation of the tool is done via composer:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">composer require sabberworm\/php-css-parser<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">To modify all selectors in a set of CSS rules in that way, that a unique class name is added in front, only a few lines are necessary. Lucky me, there was an example for that right there in the readme on GitHub (the CSS string exists in <code>$attributes['customCss']<\/code> in the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-meta\">&lt;?php<\/span>\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Sabberworm<\/span>\\<span class=\"hljs-title\">CSS<\/span>\\<span class=\"hljs-title\">Parser<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Generate unique classname.<\/span>\n$unique_block_classname = <span class=\"hljs-string\">'slider_'<\/span> . bin2hex( random_bytes( <span class=\"hljs-number\">6<\/span> ) );\n$css_parser = <span class=\"hljs-keyword\">new<\/span> Parser( $attributes&#91;<span class=\"hljs-string\">'customCss'<\/span>] );\n$css_document = $css_parser-&gt;parse();\n\n<span class=\"hljs-comment\">\/\/ Loop CSS declaration blocks and add classname to selectors.<\/span>\n<span class=\"hljs-keyword\">foreach<\/span> ( $css_document-&gt;getAllDeclarationBlocks() <span class=\"hljs-keyword\">as<\/span> $declaration_block ) {\n\t<span class=\"hljs-keyword\">foreach<\/span> ( $declaration_block-&gt;getSelectors() <span class=\"hljs-keyword\">as<\/span> $selector ) {\n\t\t$selector-&gt;setSelector( <span class=\"hljs-string\">\".$unique_block_classname\"<\/span> .<span class=\"hljs-string\">' '<\/span>. $selector-&gt;getSelector() );\n\t}\n}\n\n<span class=\"hljs-comment\">\/\/ Save modified CSS.<\/span>\n$custom_css = $css_document-&gt;render();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">First, we generate an unique class name and parse the CSS with the <code>parse()<\/code> method of the <code>Parser<\/code> class. Next, we loop over the declarations and inside the declarations over the selectors, to prepend every selector with the generated class:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">$selector-&gt;setSelector( <span class=\"hljs-string\">\".$unique_block_classname\"<\/span> .<span class=\"hljs-string\">' '<\/span>. $selector-&gt;getSelector() );<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">With <code>$css_document->render()<\/code> we store the modified CSS in the <code>$custom_css<\/code> variable in the end.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For a slider Gutenberg block, I added the option to enter custom CSS into a text field, that should only apply to that one block. Of course, the user should not need to write the selector that way, that it only applies to this specific block \u2013 that should be done in the background before [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wpf_show_in_dewp_planet_feed":false,"flobn_post_versions":"","webmentions_disabled_pings":false,"webmentions_disabled":false,"lazy_load_responsive_images_disabled":false,"footnotes":""},"categories":[6],"tags":[],"class_list":["post-6181","post","type-post","status-publish","format-standard","hentry","category-web-development"],"wp-worthy-pixel":{"ignored":false,"public":"72cfdd4cf55e47c29f1da54e458f8d73","server":"vg04.met.vgwort.de","url":"https:\/\/vg04.met.vgwort.de\/na\/72cfdd4cf55e47c29f1da54e458f8d73"},"wp-worthy-type":"normal","_links":{"self":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/6181","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/comments?post=6181"}],"version-history":[{"count":3,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/6181\/revisions"}],"predecessor-version":[{"id":6184,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/6181\/revisions\/6184"}],"wp:attachment":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/media?parent=6181"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/categories?post=6181"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/tags?post=6181"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}