How to minify Wordpress output html code on single line? [closed] - html

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
i need to speed up my Wordpress blog. I searched around the web, but no success.
I want to minify or compress my output html code on one(single) line, like Matt Cutt's blog.
I tried W3TC, WP Minify and many others, but without result.
I need script, plugin, function or something that works.
Thanks in advance.

Here is one solution what I give in WordPress.StackExchange.com
https://wordpress.stackexchange.com/a/227896/82023
Generaly, in index.php you can place one code what will compress your HTML using regex. i made and use this on many places and work fine. Is not complete inline but do it's job.
<?php
/**
* Front to the WordPress application. This file doesn't do anything, but loads
* wp-blog-header.php which does and tells WordPress to load the theme.
*
* #package WordPress
*/
/**
* Tells WordPress to load the WordPress theme and output it.
*
* #var bool
*/
define('WP_USE_THEMES', true);
/** Manualy compress WP by Ivijan-Stefan Stipic **/
function compressorCF($str)
{
// clear HEAD
$str = preg_replace_callback('/(?=<head(.*?)>)(.*?)(?<=<\/head>)/s',
function($matches) {
return preg_replace(array(
/* Fix HTML */
'/\>[^\S ]+/s', // strip whitespaces after tags, except space
'/[^\S ]+\</s', // strip whitespaces before tags, except space
'/\>\s+\</', // strip whitespaces between tags
), array(
/* Fix HTML */
'>', // strip whitespaces after tags, except space
'<', // strip whitespaces before tags, except space
'><', // strip whitespaces between tags
), $matches[2]);
}, $str);
// clear BODY
$str = preg_replace_callback('/(?=<body(.*?)>)(.*?)(?<=<\/body>)/s',
function($matches) {
return preg_replace(array(
'/<!--(.*?)-->/s', // delete HTML comments
'#\/\*(.*?)\*\/#s', // delete JavaScript comments
/* Fix HTML */
'/\>[^\S ]+/s', // strip whitespaces after tags, except space
'/[^\S ]+\</s', // strip whitespaces before tags, except space
'/\>\s+\</', // strip whitespaces between tags
), array(
'', // delete HTML comments
'', // delete JavaScript comments
/* Fix HTML */
'>', // strip whitespaces after tags, except space
'<', // strip whitespaces before tags, except space
'><', // strip whitespaces between tags
), $matches[2]);
}, $str);
return $str;
}
/** Loads the WordPress Environment and Template */
ob_start();
require_once( dirname( __FILE__ ) . '/wp-blog-header.php' );
$content=ob_get_clean();
//echo $content;
echo compressorCF($content);

This is really not the best way to speedup your site. If you do it in the template it make the files unreadable and hard to maintain for less than 1% speedup. If you do it with a plugin that process the output, it will slow down the render.
Make sure :
You use as few plugins as possible, for example it's much faster to copy tracking code (google analytics or such) in footer.php than using a plugin
You have compiled, cleaned, minifyied CSS and JS that is on your server and properly compressed files.
You use CDN for all files that are on CDN like JQuery on https://developers.google.com/speed/libraries/devguide
Put mod_expire on your server and set expire date for media files far in future with .htaccess . This will prevent browsers from checking if files have changed (all the 200 status code you see in network traffic analysis)
Cache content using WP supercache or similar plugin
Install APC cache with enough memory (at least 32M for a single WP installation)

If your plugin loads CSS and JS files properly there is no point to say that they will make your website slow.
1. Another issue is how many database call these plugin make to render a particular task.
2. Whether that plugin check data from a remote server to update something like akismat and jetpack, thus makes these two pluin the most resource hungry.
Proper coded theme can help you to load your website properly. like my own site ( http://www.binarynote.com ) score loads score is 99/100 in getmetrix.com

We have Just developed a code in C++ using that we can compress any code. The main function is given here for your ready reference.
//function to compress text files
void compress(char source[], char dest[])
{
ifstream fin(source);
ofstream fout(dest);
char ch;
int sp=0;
while(fin.get(ch))
{
if(ch==' '||ch=='\t')
sp++;
else
sp=0;
if(ch=='\n' || ch=='\r')
fout<<' ';
else
if(sp>=1)
fout<<' ';
else
fout<<ch;
}
fin.close();
fout.close();
}

Put this code to function.php:
class WP_HTML_Compression
{
// Settings
protected $compress_css = true;
protected $compress_js = true;
protected $info_comment = true;
protected $remove_comments = true;
// Variables
protected $html;
public function __construct($html)
{
if (!empty($html))
{
$this->parseHTML($html);
}
}
public function __toString()
{
return $this->html;
}
protected function bottomComment($raw, $compressed)
{
$raw = strlen($raw);
$compressed = strlen($compressed);
$savings = ($raw-$compressed) / $raw * 100;
$savings = round($savings, 2);
return '<!--HTML compressed, size saved '.$savings.'%. From '.$raw.' bytes, now '.$compressed.' bytes-->';
}
protected function minifyHTML($html)
{
$pattern = '/<(?<script>script).*?<\/script\s*>|<(?<style>style).*?<\/style\s*>|<!(?<comment>--).*?-->|<(?<tag>[\/\w.:-]*)(?:".*?"|\'.*?\'|[^\'">]+)*>|(?<text>((<[^!\/\w.:-])?[^<]*)+)|/si';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
$overriding = false;
$raw_tag = false;
// Variable reused for output
$html = '';
foreach ($matches as $token)
{
$tag = (isset($token['tag'])) ? strtolower($token['tag']) : null;
$content = $token[0];
if (is_null($tag))
{
if ( !empty($token['script']) )
{
$strip = $this->compress_js;
}
else if ( !empty($token['style']) )
{
$strip = $this->compress_css;
}
else if ($content == '<!--wp-html-compression no compression-->')
{
$overriding = !$overriding;
// Don't print the comment
continue;
}
else if ($this->remove_comments)
{
if (!$overriding && $raw_tag != 'textarea')
{
// Remove any HTML comments, except MSIE conditional comments
$content = preg_replace('/<!--(?!\s*(?:\[if [^\]]+]|<!|>))(?:(?!-->).)*-->/s', '', $content);
}
}
}
else
{
if ($tag == 'pre' || $tag == 'textarea')
{
$raw_tag = $tag;
}
else if ($tag == '/pre' || $tag == '/textarea')
{
$raw_tag = false;
}
else
{
if ($raw_tag || $overriding)
{
$strip = false;
}
else
{
$strip = true;
// Remove any empty attributes, except:
// action, alt, content, src
$content = preg_replace('/(\s+)(\w++(?<!\baction|\balt|\bcontent|\bsrc)="")/', '$1', $content);
// Remove any space before the end of self-closing XHTML tags
// JavaScript excluded
$content = str_replace(' />', '/>', $content);
}
}
}
if ($strip)
{
$content = $this->removeWhiteSpace($content);
}
$html .= $content;
}
return $html;
}
public function parseHTML($html)
{
$this->html = $this->minifyHTML($html);
if ($this->info_comment)
{
$this->html .= "\n" . $this->bottomComment($html, $this->html);
}
}
protected function removeWhiteSpace($str)
{
$str = str_replace("\t", ' ', $str);
$str = str_replace("\n", '', $str);
$str = str_replace("\r", '', $str);
while (stristr($str, ' '))
{
$str = str_replace(' ', ' ', $str);
}
return $str;
}
}
function wp_html_compression_finish($html)
{
return new WP_HTML_Compression($html);
}
function wp_html_compression_start()
{
ob_start('wp_html_compression_finish');
}
add_action('get_header', 'wp_html_compression_start');
on https://photogrist.com it's works fine :)

Related

ACF overrides HTML attributes added with load_value hook

I'm using ACF together with the ACF Hook acf/load_value to add a custom HTML wrapper to the ACF value. I use then the ACFs to build an Elementor template (I'm using Elementor PRO).
The Template works and the values of ACFs are rendered, but the attribute I've added in the wrapper disappear
I've tried to change the priority of my filters, but it wasn't the problem. I 've also tried to look into the ACF settings, but seems that I cannot change this behavior just changing some settings.
This is the filter I made
if (!function_exists('my_acf_span_property')) {
function my_acf_span_property($value, $property) {
$value = '<span property="' . $property . '">' . $value . '</span>';
return $value;
}
}
if (!function_exists('my_acf_industry_value')) {
function my_acf_industry_value($value)
{
return my_acf_span_property($value, 'industry');
}
}
add_filter('acf/format_value/name=industry', 'my_acf_industry_value');
I made one filter for each ACF I need to change, this is only one as example.
I've tried to debug the filter changing return $value; to return htmlentities($value); in the function my_acf_span_property and the attributes are rendered in the frontend.
The output was expected to be <span property="industry">ACF value</span>
But wat is rendered is <span>ACF value</span>
It could be an Elementor problem?
Any Idea?
I solved with an action to allow the attributes in the posts
if (!function_exists('allow_property_attribute')) {
function allow_property_attribute() {
global $allowedposttags, $allowedtags;
$newattribute = "property";
$allowedposttags["span"][$newattribute] = true;
$allowedtags["span"][$newattribute] = true;
$allowedposttags["div"][$newattribute] = true;
$allowedtags["div"][$newattribute] = true;
$allowedposttags["p"][$newattribute] = true;
$allowedtags["p"][$newattribute] = true;
}
}
add_action( 'init', 'allow_property_attribute' );
It looks like was WordPress my problem, and not Elementor or ACF.

strpos always returns FALSE with wordpress post content

I am trying to search a string from wordpress post content and see if my substring is present or not. Following is the code
$closing_p = '</p>';
$paragraphs = explode($closing_p, $content);
$search_string="fdfd";
foreach($paragraphs as $index => $paragraph)
{
if (strlen($search_string) > 0)
{
$posi = strpos($paragraphs[$index],$search_string);
if ($posi===FALSE)
{
$insert_ad = false;
}
else
{
$insert_ad = true;
echo "yessssss";
}
}
Content of wordpress post is
"
Welcome to WordPress. This is your first post. Edit or delete it, then start writing!fdfdf"
But it always says not found . Any problems here

WordPress Shortcode adding attributes

I'm writing a shortcode function for WP. Inside the function I have the $content (in this case an image). I need to be able to add a couple attributes to that content and return it in a string, like so:
function Shortcode( $atts, $content=null ){
if(!is_null($content){
return '<div class="wrapper">'. $content .'</div>'
}
}
Currently, just the image is getting spit back, but I need to somehow modify it and add a couple attributes before adding it to the string above.
I need to do something like this:
function Shortcode( $atts, $content=null ){
if(!is_null($content){
// CONVERT $CONTENT TO STRING
$content_html=somefunction($content)
echo $content_html; // <img src='....' />
return '<div class="wrapper">'. $content_html .'</div>'
}
}

Converting HTML to XML

I have got hundereds of HTML files that need to be conveted in XML. We are using these HTML to serve contents for applications but now we have to serve these contents as XML.
HTML files are contains, tables, div's, image's, p's, b or strong tags, etc..
I googled and found some applications but i couldn't achive yet.
Could you suggest a way to convert these file contents to XML?
I was successful using tidy command line utility. On linux I installed it quickly with apt-get install tidy. Then the command:
tidy -q -asxml --numeric-entities yes source.html >file.xml
gave an xml file, which I was able to process with xslt processor. However I needed to set up xhtml1 dtds correctly.
This is their homepage: html-tidy.org (and the legacy one: HTML Tidy)
I did found a way to convert (even bad) html into well formed XML. I started to base this on the DOM loadHTML function. However during time several issues occurred and I optimized and added patches to correct side effects.
function tryToXml($dom,$content) {
if(!$content) return false;
// xml well formed content can be loaded as xml node tree
$fragment = $dom->createDocumentFragment();
// wonderfull appendXML to add an XML string directly into the node tree!
// aappendxml will fail on a xml declaration so manually skip this when occurred
if( substr( $content,0, 5) == '<?xml' ) {
$content = substr($content,strpos($content,'>')+1);
if( strpos($content,'<') ) {
$content = substr($content,strpos($content,'<'));
}
}
// if appendXML is not working then use below htmlToXml() for nasty html correction
if(!#$fragment->appendXML( $content )) {
return $this->htmlToXml($dom,$content);
}
return $fragment;
}
// convert content into xml
// dom is only needed to prepare the xml which will be returned
function htmlToXml($dom, $content, $needEncoding=false, $bodyOnly=true) {
// no xml when html is empty
if(!$content) return false;
// real content and possibly it needs encoding
if( $needEncoding ) {
// no need to convert character encoding as loadHTML will respect the content-type (only)
$content = '<meta http-equiv="Content-Type" content="text/html;charset='.$this->encoding.'">' . $content;
}
// return a dom from the content
$domInject = new DOMDocument("1.0", "UTF-8");
$domInject->preserveWhiteSpace = false;
$domInject->formatOutput = true;
// html type
try {
#$domInject->loadHTML( $content );
} catch(Exception $e){
// do nothing and continue as it's normal that warnings will occur on nasty HTML content
}
// to check encoding: echo $dom->encoding
$this->reworkDom( $domInject );
if( $bodyOnly ) {
$fragment = $dom->createDocumentFragment();
// retrieve nodes within /html/body
foreach( $domInject->documentElement->childNodes as $elementLevel1 ) {
if( $elementLevel1->nodeName == 'body' and $elementLevel1->nodeType == XML_ELEMENT_NODE ) {
foreach( $elementLevel1->childNodes as $elementInject ) {
$fragment->insertBefore( $dom->importNode($elementInject, true) );
}
}
}
} else {
$fragment = $dom->importNode($domInject->documentElement, true);
}
return $fragment;
}
protected function reworkDom( $node, $level = 0 ) {
// start with the first child node to iterate
$nodeChild = $node->firstChild;
while ( $nodeChild ) {
$nodeNextChild = $nodeChild->nextSibling;
switch ( $nodeChild->nodeType ) {
case XML_ELEMENT_NODE:
// iterate through children element nodes
$this->reworkDom( $nodeChild, $level + 1);
break;
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
// do nothing with text, cdata
break;
case XML_COMMENT_NODE:
// ensure comments to remove - sign also follows the w3c guideline
$nodeChild->nodeValue = str_replace("-","_",$nodeChild->nodeValue);
break;
case XML_DOCUMENT_TYPE_NODE: // 10: needs to be removed
case XML_PI_NODE: // 7: remove PI
$node->removeChild( $nodeChild );
$nodeChild = null; // make null to test later
break;
case XML_DOCUMENT_NODE:
// should not appear as it's always the root, just to be complete
// however generate exception!
case XML_HTML_DOCUMENT_NODE:
// should not appear as it's always the root, just to be complete
// however generate exception!
default:
throw new exception("Engine: reworkDom type not declared [".$nodeChild->nodeType. "]");
}
$nodeChild = $nodeNextChild;
} ;
}
Now this also allows to add more html pieces into one XML which I needed to use myself. In general it can be used like this:
$c='<p>test<font>two</p>';
$dom=new DOMDocument('1.0', 'UTF-8');
$n=$dom->appendChild($dom->createElement('info')); // make a root element
if( $valueXml=tryToXml($dom,$c) ) {
$n->appendChild($valueXml);
}
echo '<pre/>'. htmlentities($dom->saveXml($n)). '</pre>';
In this example '<p>test<font>two</p>' will nicely be outputed in well formed XML as '<info><p>test<font>two</font></p></info>'. The info root tag is added as it will also allow to convert '<p>one</p><p>two</p>' which is not XML as it has not one root element. However if you html does for sure have one root element then the extra root <info> tag can be skipped.
With this I'm getting real nice XML out of unstructured and even corrupted HTML!
I hope it's a bit clear and might contribute to other people to use it.

JSON API to show Advanced Custom Fields - WordPress

I am developing a magazine WordPress site that will have a json feed for a Mobile App. I set the backend up using Advanced Custom Fields with a Repeater Field for Multiple Articles and Multiple Pages within each article. http://www.advancedcustomfields.com/add-ons/repeater-field/
I am using the JSON API but this does not include any of my custom fields. Is there currently a plugin that can do this?
#Myke: you helped me tremendously. Here's my humble addition:
add_filter('json_api_encode', 'json_api_encode_acf');
function json_api_encode_acf($response)
{
if (isset($response['posts'])) {
foreach ($response['posts'] as $post) {
json_api_add_acf($post); // Add specs to each post
}
}
else if (isset($response['post'])) {
json_api_add_acf($response['post']); // Add a specs property
}
return $response;
}
function json_api_add_acf(&$post)
{
$post->acf = get_fields($post->id);
}
Update for Wordpress 4.7
With the release of Wordpress 4.7 the REST functionality is no longer provided as a distinct plugin, rather its rolled in (no plugin required).
The previous filters don't appear to work. However the following snippet does (can be in your functions.php):
>= PHP 5.3
add_filter('rest_prepare_post', function($response) {
$response->data['acf'] = get_fields($response->data['id']);
return $response;
});
< PHP 5.3
add_filter('rest_prepare_post', 'append_acf');
function append_acf($response) {
$response->data['acf'] = get_fields($response->data['id']);
return $response;
};
Note the filter is a wild card filter, applied like
apply_filters("rest_prepare_$type", ...
so if you have multiple content types (custom), you will need to do:
add_filter('rest_prepare_multiple_choice', 'append_acf');
add_filter('rest_prepare_vocabularies', 'append_acf');
function append_acf($response) {
$response->data['acf'] = get_fields($response->data['id']);
return $response;
};
Note It appears that rest_prepare_x is called per record. So if you are pinging the index endpoint, it will be called multiple times (so you don't need to check if its posts or post)
Came here by searching with the same question. This isn't totally vetted yet but I think this is getting on the right path. Check it out.
I have one less nested level than you do so this might need altered a bit. But the JSON API plugin has a filter called json_api_encode. I have a repeater called specifications that looks like this.
http://d.pr/i/YMvv
In my functions file I have this.
add_filter('json_api_encode', 'my_encode_specs');
function my_encode_specs($response) {
if (isset($response['posts'])) {
foreach ($response['posts'] as $post) {
my_add_specs($post); // Add specs to each post
}
} else if (isset($response['post'])) {
my_add_specs($response['post']); // Add a specs property
}
return $response;
}
function my_add_specs(&$post) {
$post->specs = get_field('specifications', $post->id);
}
Which appends a custom value to the JSON API output. Notice the get_field function from ACF works perfectly here for bringing back the array of the repeater values.
Hope this helps!
There is now a small plugin which adds the filter for you.
https://github.com/PanManAms/WP-JSON-API-ACF
I'm not sure if you're still interested in a solution, but I was able to modify the json-api plugin models/post.php file to display the repeater data as an array. This is a modification of a modification made by http://wordpress-problem.com/marioario-on-plugin-json-api-fixed-get-all-custom-fields-the-right-way/
replace the set_custom_fields_value() function with the following:
function set_custom_fields_value() {
global $json_api;
if ($json_api->include_value('custom_fields') && $json_api->query->custom_fields) {
// Query string params for this query var
$params = trim($json_api->query->custom_fields);
// Get all custom fields if true|all|* is passed
if ($params === "*" || $params === "true" || $params === "all") {
$wp_custom_fields = get_post_custom($this->id);
$this->custom_fields = new stdClass();
// Loop through our custom fields and place on property
foreach($wp_custom_fields as $key => $val) {
if (get_field($key)) {
$this->custom_fields->$key = get_field($key);
} else if ($val) {
// Some fields are stored as serialized arrays.
// This method does not support multidimensionals...
// but didn't see anything wrong with this approach
$current_custom_field = #unserialize($wp_custom_fields[$key][0]);
if (is_array($current_custom_field)) {
// Loop through the unserialized array
foreach($current_custom_field as $sub_key => $sub_val) {
// Lets append these for correct JSON output
$this->custom_fields->$key->$sub_key = $sub_val;
}
} else {
// Break this value of this custom field out of its array
// and place it on the stack like usual
$this->custom_fields->$key = $wp_custom_fields[$key][0];
}
}
}
} else {
// Well this is the old way but with the unserialized array fix
$params = explode(',', $params);
$wp_custom_fields = get_post_custom($this->id);
$this->custom_fields = new stdClass();
foreach ($params as $key) {
if (isset($wp_custom_fields[$key]) && $wp_custom_fields[$key][0] ) {
$current_custom_field = #unserialize($wp_custom_fields[$key][0]);
if (is_array($current_custom_field)) {
foreach($current_custom_field as $sub_key => $sub_val) {
$this->custom_fields->$key->$sub_key = $sub_val;
}
} else {
$this->custom_fields->$key = $wp_custom_fields[$key][0];
}
}
}
}
} else {
unset($this->custom_fields);
}
}
Current version of ACF prints out a custom_fields object on a call to the JSON API, containing all the fields relative to the Post or Page. I edited #Myke version to add specific custom fields from the ACF Option page to each Post or Page. Unfortunately there is not get_fields() function for the whole Option Page so you'll have to edit it depending on your fields structure.
add_filter('json_api_encode', 'json_api_encode_acf');
function json_api_encode_acf($response) {
if (isset($response['posts'])) {
foreach ($response['posts'] as $post) {
json_api_add_acf($post); // Add specs to each post
}
}
else if (isset($response['post'])) {
json_api_add_acf($response['post']); // Add a specs property
}
else if (isset($response['page'])) {
json_api_add_acf($response['page']); // Add a specs to a page
}
return $response;
}
function json_api_add_acf(&$post) {
$post->custom_fields->NAME_OF_YOUR_CUSTOM_FIELD = get_field( 'NAME_OF_YOUR_CUSTOM_FIELD', 'option' );
}