I am having trouble preloading CSS on my WordPress site. I was writing a script to find every JS and CSS script enqueued in the footer, and preload it in the <head>. The code for the JS scripts works fine (when I go to page source on the site, I can see the <link> tags with the preload attribute inside), but the CSS preload link tags aren't showing up.
It is very likely I am doing this completely wrong, as I found working code for the JS scripts and then tried to alter it to get it to work for the CSS. For instance, I don't think the version appendage applies to CSS, but I assumed it would still work since it would default to false, right?
As a related question, I am having the same issue with webfonts. Google Pageview Insights is telling me to preload webfonts, so I added some php to do that, but when I run pageview insights again, no dice.
Here is the code:
add_action('wp_head', function () {
global $wp_scripts;
global $wp_styles;
foreach($wp_scripts->queue as $handle) {
$script = $wp_scripts->registered[$handle];
//-- Check if script is being enqueued in the footer.
if($script->extra['group'] === 1) {
//-- If version is set, append to end of source.
$source = $script->src . ($script->ver ? "?ver={$script->ver}" : "");
//-- Spit out the tag.
echo "<link rel='preload' href='{$source}' as='script'/>\n";
}
}
foreach($wp_styles->queue as $handle) {
$style = $wp_styles->registered[$handle];
if ($style->extra['group'] === 1) {
$source = $style->src . ($style->ver ? "?ver={$style->ver}" : "");
echo "<link rel='preload' href='{$source}' as='style' onload='this.rel = \"stylesheet\"'/>\n
<noscript><link rel='stylesheet' href='{$source}'/></noscript>\n";
}
}
//This is the code to preload webfonts
echo "<link rel='preload' href='/wp-content/themes/salient/css/fonts/fontawesome-webfont.woff?v=4.2' as='font' type='font/woff'>";
echo "<link rel='preload' href='/wp-content/themes/salient/css/fonts/fontawesome-webfont.ttf?v=4.2' as='font' type='font/ttf'>";
}, 1);
Welcome to StackOverflow!
A function that I have used in my projects for preloading CSS effectively is:
function add_rel_preload($html, $handle, $href, $media) {
if (is_admin())
return $html;
$html = <<<EOT
<link rel='preload' as='style' onload="this.onload=null;this.rel='stylesheet'"
id='$handle' href='$href' type='text/css' media='all' />
EOT;
return $html;
}
add_filter( 'style_loader_tag', 'add_rel_preload', 10, 4 );
A similar function could in theory be used for JS and Webfonts, but this has only been tested with CSS.
Hope this is helpful!
The exact code, which has worked for me:
function preload_for_css ( $html, $handle, $href, $media ) {
if ( is_admin () )
{
return $html;
}
echo '<link rel="stylesheet preload" as="style" href="' . $href . '" media="all">';
}
add_filter ( 'style_loader_tag', 'preload_for_css', 10, 4 );
It will pass GTmetrix and Google Insights test. At least passed for me :-)
Related
I need to include some js, css type items in specific pages.
So far I've done the following:
define("DIR_ADMIN", "admin");
function fusion($location, $page, $type) {
$dirAdmin = DIRECTORY_SEPARATOR.DIR_ADMIN;
$change = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $location);
$changed = ucfirst($change);
$result = $dirAdmin.$changed;
if($type=='js'){
echo "<script src='$result'></script>\n";
} elseif($type=='css'){
echo "<link rel='stylesheet' href='$result' />";
} elseif($type=='favicon'){
echo "<link rel='shortcut icon' href='$result' />";
} elseif($type=='logo'){
echo "<img src='$result' alt='logo'>";
} else {
echo $result;
}
}
In HTML I called the function like this:
<?php fusion("/assets/vendors/js/vendor.bundle.base.js", "clients", "js"); ?>
First is the file URL, then the page, and finally the file type.
What I'm not able to come up with is the part that receives the value $page.
I created a routing system in php, so all files are accessed like this: index.php?page=clients, except in the case of the homepage which is just index.php.
I need that when the value of $page is set for example with clients it should load all items that have this same when the clients route is accessed.
In some cases the route may have another word attached, for example: index.php?page=clients-add, in which case it should check if there is only the word clients in $_GET.
And if I set the value of $page to all, it should display on all pages. How can I do this?
Within your fusion function you need to pick up which page you're on and then including the displaying of content after that.
Use this snippet to help dictate the page you're on.
$curr_page = "home";
if ( isset( $_GET["page"] ) ) {
$curr_page = $_GET["page"];
}
if ( $page == "all" || $page == $curr_page ) {
//echo items here
}
I am developing a WordPress plugin which I would like it to add some predefined CSS to a stylesheet when someone enables a feature.
I cannot simply include the stylesheet in addition to the regular stylesheet because some features will conflict with it. I would like it so that when they click one element it loads only the CSS relevant to this.
When they select this element it should "print" the relevant CSS into a stylesheet.
Can I call a function that I created which contains CSS and gets called only once the feature is enabled?
There are a couple ways I would approach this.
You can use use inline css and not require the theme's style sheet. And write what you need between your conditions, like this the first example or use wp_add_inline_style.
IDEA 1: not using wp_add_inline_style
//* Load CSS
function yourplugin_prefix_load_css() {
add_action( 'wp_head', 'yourpluginprefix_css', 15 );
}
add_action( 'plugins_loaded' , 'yourplugin_prefix_load_css' );
//* CSS
function yourpluginprefix_css() {
//vars
$a = get_option( 'where_a', 'what_a' );
$b = get_option( 'where_b', 'what_b' );
// begin CSS
$css = '';
$css .= '<style class="whatever" >';
//condition $a
if ( $a == '0' ) :
$css .= '
.property{
display: inline-block;
}
';
endif; //condition for $a
//condition $b
if ( $b != '1' ) :
$css .= '
.property-something{
border: 1px solid #333;
}
';
endif; //condition for $b
//close the style sheet
$css .= '</style>';
//minify it
$css_min = str_replace( array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $css );
echo $css_min;
}
IDEA 2 with wp_add_inline_style
Alternatively, you can use wp_add_inline_style and get the current theme's handle .
function pluginprefix_css() {
//get current theme stylesheet handle
$current_theme = ( wp_get_theme() );
//get our values for conditions
$a = get_option( 'where_a', 'what_a' );
$b = get_option( 'where_b', 'what_b' );
//begin css
$css = '';
//condition $a
if ( $a == '0' ) :
$css .= '
.property{
display: inline-block;
}
';
endif; //condition for $a
//condition $b
if ( $b != '1' ) :
$css .= '
.property-something{
border: 1px solid #333;
}
';
endif; //condition for $b
//minify css
$css_min = str_replace( array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $css );
//add inline style
wp_add_inline_style( $current_theme->stylesheet, $css_min );
}
add_action( 'wp_enqueue_scripts', 'pluginprefix_css' );
If you need to load library after the site is loaded, your best hope is javascript.
E.g. you can add code snippet into head when click on element. In jQuery
var e = 'button.class';
var remove_css = '#my_style_1';
var code = '<link rel="stylesheet" type="text/css" href="/path/to/css_part.css">';
$(e).on( 'click', function() {
$('head').append( code );
$(remove_css).remove();
});
Replace e variable with class or element which will add code into header on click.
UPDATED: find in source the identificator (ID) of your css file and put it in remove_css variable. It will remove it after element clicked. I should note that this solution is not persistent and lasts until page switch.
--
If you need load css based on option, create an option in your admin, register your styles and then enable it based on option.
Somewhere in code register your style:
wp_register_style( 'my_style_original', '/path/to/css_part.css' );
wp_register_style( 'my_style_replace', '/path/to/css_part.css' );
And then eneable it based on option
$enable_css = get_option( 'enable_css' );
if( $enable_css )
wp_enqueue_style( 'my_style_replace' ); // if setting enabled load second css
else
wp_enqueue_style( 'my_style_original' ); // if setting not enabled load original css
This will load the style only when option 'enable_css' is not false or empty.
To create option page see https://codex.wordpress.org/Creating_Options_Pages or for easier setup you can stick to ACF options (https://www.advancedcustomfields.com/add-ons/options-page/);
You can create a function that writes indented style into the specific element. Remember that this is not considered bad coding, anyway I don't know how it'd be considered since it'd be dynamic content.
So, for example, you have:
<input type="text" />
And when the user clicks to add the style, the function would add:
<input type="text" style="..." />
In the other hand, when the user refreshes the page, the style would disappear.
Create a php function that takes the arguments of what features are enabled to make a custom stylesheet, and dynamically enqueue that stylesheet. Use .htaccess or similar settings to redirect requests for your custom_thingy.css to custom_thingy.php and just have it echo the custom styles, it'll behave like a regular stylesheet.
foreach($style_options as $option) {
echo file_get_contents($option_style_file[$option]);
}
if you using wordpress. you can use wp_add_inline_style
My menu system all comes from the index file. A simplified example:
#index.php
...
<div id="container">
include($inc_file) //index.php?site=news will show news.php
</div>
...
My question is: how can I only include some js-files and css-files when they are needed. For example, I have a file with a slider. I would like only to include the js/css-files related to the slider when visiting that page.
I know that I can make if/else clauses, but I find that a bit ineffective. Is it possible to place a session containing an array with all the files that should be included on the frontpage?
Here is what I would use:
<?php
$path_parts = pathinfo(__FILE__);
$filename = $path_parts['filename'];
if ($filename === "somepage") {
?>
<script src=""></script>
<link ...>
<?php } ?>
I would just have a preset array for each page with an array of css/js files it would need to include.
eg.
settings.php
<?php
$pages = array();
$pages['index'] = array(
"css" => array("main.css","index.css"),
"js" => array("jquery.min.js","someotherjs.js")
);
$pages["about"] = array(
...
);
index.php
<?php
include('settings.php');
?>
...
<head>
<?php
foreach($pages['index']['css'] as $css)
echo "<link rel='stylesheet' type='text/css' href='$css'>";
?>
...
<?php
foreach($pages['index']['js'] as $js)
echo "<script src='$js'></script>";
</body>
</head>
This may not be the answer you were expecting but did you know that the browser does not download css or js files that have not changed since the last time they were downloaded. They are cached on the client PC and only refreshed if the copy on the server has changed.
Theerfore you may not need to be so selective about what you load on each page as it probably wont cause a fresh download of a css or js file.
Prepare an object where you can add style or js files as you need, here a little example.
class head {
private styles = array();
private scripts = array();
public function __construct() {}
// add script in page
public function add_script(filepath){
array_push($this->scripts, filepath);
}
// add style in page
public function add_style(filepath){
array_push($this->styles, filepath);
}
// get html <link> for styles
public function get_styles(){
$html = '';
$len = count($this->styles);
for($i=0; $i < $len; $i++){
$html .='<link rel="stylesheet" type="text/css" href="'.$this->styles[$i].'">';
}
return $html;
}
// get html <script> for scripts
public function get_scripts(){
$html = '';
$len = count($this->scripts);
for($i=0; $i < $len; $i++){
$html .='<script type="text/javascript" src="'.$this->scripts[$i].'"></script>';
}
return $html;
}
}
// destruct ...
in your controller :
require('/class/head.php');
$head = new head();
$head->add_style('/css/myStyle.css');
$head->add_script('/js/myScript.js');
in head
<?php echo $head->get_styles(); ?>
<?php echo $head->get_scripts(); ?>
I am using PHP and CodeIgniter. In every view file, I include the header.php, seen below:
<head>
<link rel="...">
<script type="text/javascript">...</script>
</head>
Notice that the head tag is closed in this file. Now I want to add a <script> tag in another file without modifying header.php. C# has ContentPlaceHolder that can be used to indicate where tags can be added within head tag. Is there any equivalent in php? If not, How can I achieve this?
You can easily add other scripts in your header by adding a single variable in your controller like this:
Controller:
$data['myScript'] = '<link rel="..."><script type="text/javascript">...</script>';
$this->load->view('myView',$data);
Then in your header.php add:
<head>
<link rel="...">
<script type="text/javascript">...</script>
<?php if (isset($myScript)) echo $myScript; ?>
</head>
This makes a very customizeable template for each view because you can add the scripts only in the views you need them.
Here's what I usually do with any CodeIgniter project...
I extend the HTML helper (application/helpers/MY_html_helper.php) to include a js() function:
function js($js)
{
$js_base_path = '';
// If you have multiple JS files, pass an array
if(is_array($js))
{
foreach($js as $script_src)
{
if(strpos($script_src, 'http://') === false && strpos($script_src, 'https://') === false)
{
$js_base_path = base_url() . 'js/';
}
echo '<script src="' . $js_base_path . $script_src . '"></script>';
}
}
// Otherwise, a string will do
else
{
if(strpos($js, 'http://') === false && strpos($js, 'https://') === false)
{
$js_base_path = base_url() . 'js/';
}
echo '<script src="' . $js_base_path . $js . '"></script>';
}
}
In my controller, I'll include my footer (header, in your case) with a js parameter:
$this->load->view('_footer', array('js'=>'jquery.cycle.lite.js'));
My _footer view runs the js() function like this:
<?php
if(isset($js))
{
$this->load->helper('html');
js($js);
}
?>
This has worked great for me, feel free to customize it to your needs.
Phil Sturgeon's template library has some handy functionalities for this:
http://philsturgeon.co.uk/demos/codeigniter-template/user_guide/library.html#prepend_metadata
I would like to hide the unused js and css files from the php page.
Some of the js files are unused by some pages, so I would like to hide them. By hidding them I can make webpage faster and get good grade in pagetest.
I used simple php code to hide the code for one page. Works good, the file is hidden for that page, for other pages the code not works. It is displaying text instead of link , like a text in textarea..
<?php
function curPageName() {
return substr($_SERVER["SCRIPT_NAME"],strrpos($_SERVER["SCRIPT_NAME"],"/")+1);
}
$currentp=curPageName();
if($currentp=="main1.php"){
echo "";
} else {
//works
echo "<link type=\"text/css\" rel=\"stylesheet\" href=\"../rws.css\" />";
/// not works
echo "<link type=\"text/css\" rel=\"stylesheet\" href=\"http://img.y.com/rws.css\" />";
}
?>
The code works for /rws.css, if I use a http://url.com/rws.css it wont.
Here an example :
<?php
function get_current_file_name () {
$Exploded_Data = explode(‘/’, $_SERVER['PHP_SELF']); //explode the path to current file to array
$Exploded_Data = array_reverse ($Exploded_Data); //reverse the arrays order cos php file name is always after last /
$CurrentPage = $Exploded_Data[0]; // assign the php file name to the currentpage variable
return $CurrentPage;
}
$CurrentPage = get_current_file_name ();
if($CurrentPage!="main1.php"){
echo('<link type="text/css" rel="stylesheet" href="style1.css" />');
}
else if$CurrentPage!="main2.php"){
echo('<link type="text/css" rel="stylesheet" href="style2.css" />');
}
?>
You can use __FILE__ instead of $_SERVER['PHP_SELF']
Is the code getting the correct current page and it's entering the ELSE?
you can use singles quotes and inside double quotes to make sure you're not missing any escape.
if($currentp!="main1.php"){
echo('<link type="text/css" rel="stylesheet" href="http://img.y.com/rws.css" />');
}