Is it adivsable to use DOMDocument on Wordpress content? - wordpress

I'd like to tinker with the content Worpress generates before it gets displayed.
A lot of examples I saw so far use regex to change the content even though it is bad practise and not advisable to parse html with regex.
My idea now is to use DOMDocument to parse and change the HTML. Is that a good idea or can this break the integrity of the content in any way?
Here is some example Wordpress content filter I created (it scales the images down half the size for retina displays):
function fancyContentParser( $content ) {
$dom = new DOMDocument();
$dom->loadHTML($content);
$images = $dom->getElementsByTagName('img');
foreach ($images as $image) {
$width = $image->getAttribute('width')/2;
$height = $image->getAttribute('height')/2;
$style = 'width: '.$width.'px; height: '.$height.'px';
$image->setAttribute('style', $style);
}
return $dom->saveHTML();
}
add_filter( 'the_content', 'fancyContentParser' );

The answers to this question are probably going to be primarily opinion-based...but I don't see anything wrong with it. However, why wouldn't you just change the width and height attributes, rather than overriding them with style?
foreach ($images as $image) {
$image->setAttribute( 'width', $image->getAttribute('width')/2 );
$image->setAttribute( 'height', $image->getAttribute('width')/2 );
}
Additionally, you can likely accomplish this without DOMDocument...and just use CSS (which is what you're proposing in your question by using a style attribute anyways). You can use the transform property:
img {
-webkit-transform: scale(0.5);
transform: scale(0.5);
}

Related

Odd Even Function NOT assigning class to my posts in loop

I am trying to style my odd and even posts in the wordpress loop differently. On multiple websites and forums, I have been seeing this code:
function oddeven_post_class ( $classes ) {
global $current_class;
$classes[] = $current_class;
$current_class = ($current_class == 'odd') ? 'even' : 'odd';
return $classes;
}
add_filter ( 'post_class' , 'oddeven_post_class' );
global $current_class;
$current_class = 'odd';
But this is NOT working. When I inspect, there is no odd or even assigned to my posts.
Live website: http://www.acetronaut.com
It looks like you're trying to mark your posts as odd or even for styling.
Even though it's possible to do it in both php (when you're iterating through your posts) and in JavaScript, relying on DOM structure, I personally prefer to do it where styling should be done: in CSS, especially since it has a special selector for this purpose: nth-child().
In your case, here's a CSS sample that will change the appearance of your odd posts, on front page:
.acetronaut-rem-fi:nth-child(2n) .acetronaut-post-content-rem {
background-color: #212121;
color: white;
}
.acetronaut-rem-fi:nth-child(2n) .acetronaut-post-content-rem * {
color: white;
}
The "key" part is :nth-child(2n).
And here's how this should render:

How to Add Bootstrap glyphicons to Woocommerce Checkout Input Fields?

I have narrowed down the code to this filter so far (found this in another SO answer):
//Checkout page editor bootstrap
add_filter('woocommerce_checkout_fields', 'addBootstrapGlyphs' );
function addBootstrapGlyphs($fields) {
foreach ($fields as &$fieldset) {
foreach ($fieldset as &$field) {
// if you want to add the form-group class around the label and the input
$field['class'][] = 'input-group';
// add form-control to the actual input
$field['input_class'][] = 'form-control';
}
}
return $fields;
}
That sets my form and input elements. Now to add glyphicons, I tried reading from $fields but I just can't seem to get a good handle to something that will let me add a span element before the input. Glyphicon needs this:
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
jQuery let's me do it this way:
<script type='text/javascript'>
jQuery(document).ready(function(){
jQuery('#billing_last_name_field').prepend('<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>');
});
</script>
but there has to be a better, more performant way to build the page with this in place already. I want to do this in php, so the checkout pageload remains fast. Please help. I come from a world of Java.
tl;dr: How to add a glyphicon to woocommerce checkout input boxes from https://github.com/woocommerce/woocommerce/blob/master/includes/wc-template-functions.php#L1920
Part 2
making progress w.r.t the above question using something like this:
// define the woocommerce_form_field_<type> callback
function filter_woocommerce_form_field_type( $field, $key, $args, $value ) {
$field = str_replace('<input','<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span><input',$field);
return $field;
};
// add the filter
add_filter( "woocommerce_form_field_email", 'filter_woocommerce_form_field_type', 10, 4 );
I know, that is not the right glyph. However, the next hurdle is to edit the html. Like Mithc mentioned in a comment below, I will now try to do this more elegantly with some type of DOM handling code.
So my follow-up question is, how do I add a DOM element the proper way with php? This time, I am looking for something like,
Convert string to DOM for processing
read some attributes from the <p> or <input>
Determine the type of glyph i should use
Add my span
Convert DOM back to string for return
Any elegant ways to do this, or is str_replace() good enough?
Apparently, there's no filter/action that allows you to modify the forms in that way. You can follow the clue of how the forms are built by checking the /templates/checkout/form-checkout.php and /includes/wc-template-functions.php.
Solution #1: Pure CSS
You could use CSS pseudo elements to add icons to the fields but due to the layout of the form, playing around with ::before and ::after could make the responsiveness a nightmare. But here's an example:
.form-row#billing_company_field {
position: relative;
padding-left: 2.8em;
}
.form-row#billing_company_field::before {
content: '';
width: 2.8em;
height: 2.8em;
background-color: #2d2e34;
position: absolute;
left: 0;
bottom: 0;
}
.form-row#billing_company_field::after {
content: "\e139";
position: absolute;
left: 0;
color: white;
font-family: 'Glyphicons Halflings';
/* Excluding position styling */
}
But as I mentioned before, the responsiveness could be a little bit like... A headache. But totally possible.
Solution #2: Template Override
WooCommerce allows you to override templates via themes. The only thing you have to do is to create a template folder in your theme's root folder.
For instance, if your theme's folder is my-store, you should have my-store/woocommerce. To override the template parts that contain the checkout form, you should have:
my-store/woocommerce/checkout/form-checkout.php
and
my-store/woocommerce/checkout/form-billing.php
Then you can modify any markup there. Just keep in mind that sometimes they update the templates, so keep an eye on them for big changes to keep them up to date too.
Solution #3: DOMDocument() [Update]
If you have the markup of each field on the filter, you can modify the output HTML with the DOMDocument() methods. Here's an example:
// Let's say this is the HTML coming from the filter.
$field = '<p class="form-row validate-required">';
$field .= '<input type="text">...';
$field .= '</p>';
// Create a DOM Object of $field. LIBXML_HTML_NOIMPLIED and LIBXML_HTML_NODEFDTD will help to prevent doctype, html and body tags being inserted at the end.
$field_object = new DOMDocument();
$field_object->loadHTML( $field, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
// Select the wrapper of the input (`<p>`) and the input (`<input />`) to know where to insert the glyph (between them).
$wrapper = $field_object->getElementsByTagName( 'p' )->item( 0 );
$input = $field_object->getElementsByTagName( 'input' )->item( 0 );
// Create the glyphicon HTML.
$glyph = $field_object->createDocumentFragment();
$glyph->appendXML( '<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>' );
// Insert the glyphicon HTML.
$wrapper->insertBefore( $glyph, $input );
The example above will get you:
<p class="form-row validate-required">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span><input type="text">...
</p>
To load attributes you can use getAttribute( $attribute_name )
on the DOMElement (like the $wrapper and $input objects). And, to determine the glyphicon you have to use, you could get the class of the $wrapper and determine the class of the glyphicon based on it. For instance, if the $wrapper contains the class user, then glyphicon's class should be glyphicon glyphicon-user which you can easily insert when you create the glyphicon HTML.

Change CSS of posts in a category in Wordpress

I'm kinda new to Wordpress and CSS, I hope you guys can help me out.
I want to change the position of the sitelogo .site-branding of all the posts under a specific category.
I can change the site-branding in my style.css to my liking but it effects the whole site including all pages, posts and category's.
.site-branding {
left: 50%;
position: absolute;
top: 40%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
Hope you guys can help me out.
Thanks in advance.
WordPress gives you the ability to target the category by adding its name to your stylesheet (usually "category-x") and then you can uniquely target any and all categories in your css.
Here's a great step by step article for targeting this class in your css.
An example might be:
<body class="archive category category-agriculture category-40">
With category-agriculture being the class you want to target like so:
body.category-agriculture .site-branding {color: red;}
Thanks for the effort, but I have had a little help and fixed the problem.
I added this filter to my functions.php
function pn_body_class_add_categories( $classes ) {
// Only proceed if we're on a single post page
if ( !is_single() )
return $classes;
// Get the categories that are assigned to this post
$post_categories = get_the_category();
// Loop over each category in the $categories array
foreach( $post_categories as $current_category ) {
// Add the current category's slug to the $body_classes array
$classes[] = 'category-' . $current_category->slug;
}
// Finally, return the $body_classes array
return $classes;
}
add_filter( 'body_class', 'pn_body_class_add_categories' );
That filter will add the category name as a class to the body on single posts.
For example, if the category is called News, it will add category-news to the body as a class on single posts.
Once that’s done, you can use that body class to only target .site-branding on single posts in the News category like this:
.single.category-news .site-branding {
left: 20%;
}
You will likely need Javascript and Jquery for this.
So if this is your URL structure: www.mysite.com/home/category/,
(function($){
var $pathArray = window.location.pathname.split('/');
var $location = pathArray[2]
var $branding = $(".site-branding")
if ($location == 'cat1' || $location == 'cat2') {
$branding.css({
'left' : '50%',
'position' : 'absolute',
'top' : '40%',
'-webkit-transform' : 'translate(-50%, -50%)',
'-ms-transform' : 'translate(-50%, -50%)',
'transform' : 'translate(-50%, -50%)'
});
}
});
Assuming you are running a child theme on your wordpress instance (which if you are not, you definitely should) you can add this script at the bottom of your header.php file.
For that I think you will have to add a PHP conditional in your header.php that checks if the current post is in that specific category, and then add another class to your logo tag that changes it's position.
Would be something like this:
<h1 class="site-branding <?php in_array( YOUR_CATEGORY_ID, get_the_category((get_the_ID()) ) ? ' new-posision' : '' ; ?>"></h1>
Wordpress may add category as a class to body tag.
If it is so for your theme than you may add specific css rule for category.
.category .site-branding {
/* your css rules here */
}

Advanced Custom Fields (ACF) css

I have been trying to find out how to add PHP from ACF to style some text in CSS. Using: https://www.advancedcustomfields.com/resources/color-picker/
.special-color {
background-color: <?php the_field('color'); ?>;
}
To echo php into workable CSS, you'll have to include the CSS in the php sections of the site (or something more advanced, probably using functions.php). This will work if you simply add:
<style>
.special-color {
background-color: <?php the_field('color'); ?>;
}
</style>
..to (say) your single.php file within the loop.
As an aside, I don't think this would be a viable way to alter site colours (if that's what you are trying to do?), but more as a way of (say) specifying a particular color for a title of one post.
Then you might think of including the style INLINE (pseudo code):
<h1 style="color: <?php the_field('color'); ?>">Post title</h1>
Simply I get the "advanced custom field" value (which is custom_color for an element) of the current post, and then change the element's color using JQuery.
So I created a new js file (custom_css.js) in the child theme with the following code:
jQuery(document).ready(function($) {
console.log(css.custom_color);
// add dynamic css to the elements
});
Then here is the code in functions.php file:
add_action('wp_enqueue_scripts', 'custom_css');
/* Get position details */
function custom_css() {
wp_enqueue_script('custom_css', get_stylesheet_directory_uri() . '/js/custom_css.js', array('jquery'));
wp_localize_script('custom_css', 'css', array(
'admin_url' => admin_url(),
'custom_color' => get_field('custom_color', get_queried_object_id() )
));
}

RegExp search and replace path to image in css

It is necessary to perform a search and replace strings in css file. And found only the title picture with.
While the search is done so with the exception of
/:(\s*)url\(((.(?!.*https:|.*http:|.*base64|.*data:image))*)\)/ig
and replace
:$1url(\'../dist/img/vendor/$2\')
In this case, I replace the path in a similar way. And I get this result
background-image: url('../dist/img/vendor/"../images/preloader.gif"');
A need of a string
background-image: url("../images/preloader.gif");
get
background-image: url('../dist/img/vendor/preloader.gif');
Find
/(url\(\s*[\"\'])(?:[^\"\']+\/)?([^\/\"\']+[\"\']\s*\))/ig
Replace
$1../dist/img/vendor/$2
Demo https://regex101.com/r/kU7cC9/3
Using a css parser is a better way if you want among other things to avoid quotes problems (single quotes, double quotes, no quotes).
As an aside, the background-image CSS property isn't the only one that can contain a path to an image file, since the background property can compile all the data from other background- properties.
An example with sabberworm PHP CSS Parser that automatically encloses paths between double quotes:
require __DIR__ . '/vendor/autoload.php';
define('NEW_PATH', '../dist/img/vendor/');
$oCssParser = new Sabberworm\CSS\Parser($css);
$oCssDocument = $oCssParser->parse();
$properties = ['background-image', 'background'];
foreach($oCssDocument->getAllRuleSets() as $oRuleSet) {
foreach($properties as $property) {
$oCssRules = $oRuleSet->getRules($property);
foreach ($oCssRules as $oCssRule) {
$value = $oCssRule->getValue()->__toString();
if (!preg_match('~https?:|base64|data:image~S', $value)) {
$value = preg_replace('~url\("\K(?:[^"/]*/)*~', NEW_PATH, $value);
$oCssRule->setValue($value);
}
}
}
}
echo $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());

Resources