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

Add classes to HTML elements via Plugin #713

Closed
hack3r3d opened this issue Jan 6, 2025 · 7 comments
Closed

Add classes to HTML elements via Plugin #713

hack3r3d opened this issue Jan 6, 2025 · 7 comments

Comments

@hack3r3d
Copy link

hack3r3d commented Jan 6, 2025

I'm running PicoCMS 2.1.4.

I need to hook into pico with a plugin or something to add classes to certain html elements. So for instance, for , I want to add some tailwind classes to them, like blockquote. Same for other elements since tailwind zeros everything out.

I figured I could hook into onContentParsed or onContentLoaded and do some sort of str_replace. I'd prefer to deal with a Dom, but I'm not sure that's an option.

I've read through the documentation and looked at examples. I can't figure it out. Maybe I'm solving this incorrectly, open to suggestions.

@marcus-at-localhost
Copy link

marcus-at-localhost commented Jan 6, 2025

I use it in onPageRendered to have access to the whole page HTML, but you can also do it in on ContentParsed.

I leave all the comments and debug statements in, so you have a start to debug that stuff, because DOMDocument can be tricky.

<?php
class Plugin extends AbstractPicoPlugin
{
	public function onPageRendered(&$output)
	{

		$dom = new DOMDocument();
		$dom->recover = true;
		//$dom->substituteEntities = true;
		$dom->formatOutput = true;
		$dom->preserveWhiteSpace = false;

		// set error level
		// uncomment to suspress warnings on malformed HTML like embedded SVG, duplicate ids
		// and raw entities like & instead of &amp;
		$internalErrors = libxml_use_internal_errors(true);
		// check when LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD is used.
		$dom->loadHTML($output /*, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD*/);

		// collect the suspressed warnings/errors and print them out
		#$errors = libxml_get_errors();
		#var_dump($errors);

		// Restore error level
		libxml_use_internal_errors($internalErrors);

        // Using DOMXPath
        $xpath = new DOMXPath($dom);
        $elements = $xpath->query('//div[@class="content"]');
        foreach ($elements as $element) {
            $currentClasses = $element->getAttribute('class');
            $element->setAttribute('class', $currentClasses . ' mx-auto max-w-7xl px-4 sm:px-6 lg:px-8');
        }

        // Using direct DOM
        $paragraphs = $dom->getElementsByTagName('p');
        foreach ($paragraphs as $p) {
            $currentClasses = $p->getAttribute('class');
            $p->setAttribute('class', $currentClasses . ' text-gray-500 leading-relaxed mb-4');
        }

		$output = $dom->saveHTML();
	}
}

I still like using PHPQuery for complex mainpulation which simplifies the DOM manipulation by using jquery's API instead of XPath.
The problem is, it#s an old, unmaintained library and this (https://packagist.org/packages/carriongrow/php-query-single) seems to be one of the few that contains several fixes to make it work with PHP 8.x - so use it if you know how to debug that stuff ;-)

Edit: remove return from method.

@hack3r3d
Copy link
Author

hack3r3d commented Jan 6, 2025

Thank you so much. I think I'm close but I'm missing something. I have a plugin working in that it implements onPageRendered, it seems to update the dom correctly, but pico never gets the updated dom.

` public function onPageRendered(&$output)
{
$output = preg_replace("/&(?!\S+;)/", "&", $output);
$dom = new DOMDocument();
$dom->recover = true;
// $dom->substituteEntities = true;
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;

	$internalErrors = libxml_use_internal_errors(true);
	// // check when LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD is used.
	$dom->loadHTML($output /*, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD*/);

	$errors = libxml_get_errors();
	var_dump($errors);

	// Restore error level
    libxml_use_internal_errors(false);

    $as = $dom->getElementsByTagName('a');
    foreach ($as as $a) {
        $a->setAttribute('class', 'text-teal-900');
    }

	return $dom->saveHTML();
}`

I had a couple of html issues that I resolved, but now $errors is empty.

If I examine the $dom in this method, it has the text-teal-900 class added to all anchor tags, but in the rendered page, the class isn't there.

This image shows the class added to the dom.
Screenshot 2025-01-06 at 4 37 30 PM

This shows the html output from pico without the class on the same anchor.
Screenshot 2025-01-06 at 4 38 05 PM

I'm doing something wrong and struggling to troubleshoot this. It's been a LONG time since I messed with PHP and DomDocuments.

@marcus-at-localhost
Copy link

@hack3r3d - I made a mistake in my example (and fixed it there). The method doesn't return anything, since $output is passed into the method as a reference (&$output).

change
return $dom->saveHTML();
to
$output = $dom->saveHTML();

@hack3r3d
Copy link
Author

hack3r3d commented Jan 7, 2025

Ah, yes, references. My php skills are rusty. That's what happens when they make you a manager.

Every time I think, "Maybe I should move to something other than Pico." I find a way to make it work.

Thank you so much.

@marcus-at-localhost
Copy link

@hack3r3d Pico is great for its simplicity - the plugin system is genius. Unfortunately, the development stalled, and it's a bit confusing, once you want to extend the markdown part, since the Parsedown library is in some weird beta state and Twig template engine 1.x is not PHP 8.x compatible anymore and needs to be updated as well. Oh well. I'd say it's a good way to get back into php :) Good luck!

@hack3r3d
Copy link
Author

hack3r3d commented Jan 7, 2025

Where is the work happening, or not happening, to modernize Pico? I might be able to help.

Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in two days if no further activity occurs. Thank you for your contributions! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants