Nov 2017 I talked about WordPress threats and how to protect your site at WordCamp Stockholm. Video available via https://wordpress.tv
Nov 2017 I talked about WordPress threats and how to protect your site at WordCamp Stockholm. Video available via https://wordpress.tv
Any project we are working on should always have some type of development environment where we can test code before we take it live (aka “in production”). In reality, this is not always the case due to resource or time constraints. When working on live sites we don’t want to make mistakes but unfortunately there is a huge mistake we can make while trying to avoid mistakes. This mistake is making backups of files and leaving those backups on the live server, accessible to the world.
But how would anyone know where to look for them? you might ask. Well, they can guess. Us humans are surprisingly predictable and assuming a pattern of behavior can obviously yield results. Otherwise the “bad guys” wouldn’t keep trying. I recently reviewed my access logs. Judging by the assumptions made by the hackers, these are the names that people have used in the past when making live backups of their WordPress config file (wp-config.php).
Examples of wp-config backup file scans:
wp-config.php~
wp-config.php.bak
wp-config.php.save
wp-config%20fix.txt
wp-config-backup1.txt
wp-config
wp-config.phpOLD
wp-config.txt
wp-config.phpa
wp-config.old
wp-config.php.txt
wp-config.
wp-config-backup.txt
wp-config-backup
config.bak
Remember that only files ending in .php will be executed before they are served so the examples above deliver all your WordPress database information in plain text format to anyone who were to access those files. If you think you may have done this on a WordPress site in the past, you better undo it asap. If it was a long time ago, there is a big risk the site is now hacked. Ideally, you should not be leaving any backup files on the live site at all. It takes up space can cause confusion for other developers about which files are actually in use. If you have a good reason to leave backups of files on the live server, make sure you put them below the root (public_html/www) so that they are not accessible to the world.
I’ll add that whether database credentials can be used to compromise your site will depend on configurations on that specific server. If the server only allows database connections from localhost, database credentials alone are not enough to hack a site. Unless of course you’ve reused your database password (used the same password for your control panel or WordPress admin). Hopefully you’ve never done that. 🙂
When WordPress site owners have been victims of hacking they often suffer consequences by getting blocked by Google or getting warnings from Google about malicious URLs on their site. After cleaning the site, these problems can linger when the URLs are only query strings and not actual URLs because query strings will not trigger a 404 in WordPress. One way of fixing this is to gather all the nasty query strings and then set them up to trigger a 404. Here is a basic script that does just that.
To add query strings to the list that triggers a 404, add them in the “force404” array. In the example below the following URLs force a 404.
mywebsite.com/?some-spammy-query
mywebsite.com/?another-spammy-query
Please note that this script requires a 404 template so make sure your theme has one.
add_filter('template_redirect', 'force_404_override' );
function force_404_override() {
parse_str($_SERVER['QUERY_STRING'], $qs);
$force404 = Array("some-spammy-query", "another-spammy-query");
foreach ($qs as $key => $value) {
if (in_array($key, $force404)) {
status_header( 404 );
nocache_headers();
include( get_query_template( '404' ) );
die();
}
}
}
Responsive design forces us to scale images. We are typically going to have two or three image sizes to work with suited for desktop, large retina and small retina screens. Sometimes we can just use desktop size for small retina screens. In the past year/s while implementing large scale systems that serve images of different size I’ve noticed some inconsistencies in performance between the largest browsers. If an image is scaled down too much, it will be jagged in Explorer. If it’s scaled down too little (i.e. just a bit) it will be blurry in FireFox. There is an obvious dilemma here as I can not find a size that accomodates both. Just now though I found this amazing css hack.
Prented that you are rotating the image, and Firefox will clear right up.
.image-scale-hack {
transform: rotate( 0deg );
}
This means I can stick to scaling only as much as absolutely needed which is what works best in Explorer, while the images stay fresh in Firefox. On top of this, users won’t have to load large images on desktop because they look better. Haleljuah.
If you want to order a custom WP-Query by two meta values you can add a function via a filter that modifies the query. Define the meta values in your query arguments and then refer to them in the filter with “mt1” for the first meta and “mt2” for the second one.
$args = array(
'posts_per_page' => -1,
'offset' => 0,
'post_type' => 'post',
'post_status' => 'publish',
'order' => 'DESC',
'meta_key' => 'price',
'meta_query' => array(
array(
'key' => 'price'
),
array(
'key' => 'amount'
)
)
);
function customorderby($orderby) {
return 'mt1.meta_value DESC, mt2.meta_value+0 DESC';
}
add_filter('posts_orderby','customorderby');
$query = new WP_Query( $args );
remove_filter('posts_orderby','customorderby');
Password Protected is one of my favorite plugins for WordPress and I use it regularly. More often than not a site needs to go online for client approval and/or the last parts of development before it’s actually ready. That’s when Password Protected really comes in handy. It’s a very easy little plugin to use that does nothing more than you want it to do. It password protects your WordPress site.
When the password page is supposed to be up for more than a few days you might want to customize it. You don’t want to hack the plugin of course but the author has added a filter hook for us to use. In the core plugin file you’ll find this line
$theme_file = apply_filters( 'password_protected_theme_file', $default_theme_file );
This allows us to jump in and replace the theme file with our own theme file. Here is a quick way of doing that. First, make a copy of password-protected/theme/login.php file which is located in the WordPress plugin directory. Leave the copy in the same folder, but rename it to for example “my-custom-login.php”. Then you need to add the filter to your themes function.php file.
function custom_login_page($content) {
return str_replace('login.php', 'my-custom-login.php', $content);
}
add_filter( 'password_protected_theme_file', 'custom_login_page' );
Now you can hack away at the file “my-custom-login.php” as much as you like without any risk of breaking the core plugin files. Add styles, images, scripts whatever you need to make that login page look fabulous.
Of course we want to use Iris colorpicker in our WordPress widgets. There are tutorials online for how to do this but none of the ones I found included a solution/explanation for why Iris doesn’t work when you initiate a new instance of a widget and stops working when you save a widget. The reason it breaks: Widgets are created and saved with an ajax post. When elements are reloaded in a page (with ajax or other methods) jQuery loses track of them. So starting with the code we have been recommended to use by several tutorials out there
jQuery(document).ready(function($) {
$('.my-color-picker').wpColorPicker();
});
This will trigger Iris on form elements with class “.my-color-picker” that are already active when the page loads. But when ajax reloads your form elements, jQuery will see them as new elements and won’t remember what it did when the page loaded. To fix this we should be able to add a trigger and rebind wpColorPicker() to our form fields when/if ajax is triggered. Like so
// Don't actually do this it doesnt work
jQuery(document).ready(function($) {
$("body").bind("ajaxComplete", function(){
$('.my-color-picker').wpColorPicker();
});
});
Unfortunately, it’s not that simple. When you drag a new widget to a sidebar that’s also done with ajax. But something funky happens here. Attempting to bind wpColorPicker to onload and ajaxComplete will leave you with a duplicate color picker that is broken. I’m not sure about the details but it has something to do with the picker being applied to the widget both before and after it is moved to a sidebar.
Now then for the solution. I found a few bug reports on this issue. Only since a few weeks back it’s considered solved. Some new jQuery hooks have been added that enables us to target our color-picker form fields more precisely. Personally, I think it would make more sense if Iris/WordPress handled this on it’s own. Maybe it will at some point in the future! For now though, we have to target our form fields directly and trigger the picker only on particular events.
I’ll be looking in to this during the next couple of days but for now, this is the javascript demo provided in the bug report.
( function( $ ){
function initColorPicker( widget ) {
widget.find( '.color-picker' ).wpColorPicker( {
change: _.throttle( function() { // For Customizer
$(this).trigger( 'change' );
}, 3000 )
});
}
function onFormUpdate( event, widget ) {
initColorPicker( widget );
}
$( document ).on( 'widget-added widget-updated', onFormUpdate );
$( document ).ready( function() {
$( '#widgets-right .widget:has(.color-picker)' ).each( function () {
initColorPicker( $( this ) );
} );
} );
}( jQuery ) );
So the vh css value is pretty cool. Potentially it should allow us to simplify the process of giving a html element equal-or-higher height as the viewport. From what I’ve read online so far browser support for vh should be fairly wide. Supposedly, it works down to IE9. Now I’ve been testing this with IE9 and unfortunately it does not seem to have full support. height: 100vh
works but min-height: 100vh
doesn’t. My conclusion thus far is therefore that if you are building a layout with limited height that you want to make the size of the browser window you can use vh. If you however need automatic strollbars it’s not (unless you want to write browser specific css hacks).
I haven’t been able to get vh to work at all in Safari on windows. Haven’t tried it on mac yet. Feel free to let me know in a comment if you have any more info on the status of vh at the moment.
We want our footers at the bottom, right? That’s easy enough to do with absolute position and extra padding on the preceding element. But it requires that we set an absolute height on the footer. That’s no fun. So what to do?
Why not set the padding of the preceding element dynamically based on the height on the footer with JavaScript? Yes! Let’s do it.
Here is the basic css for absolutely positioned footer
/* #everything wraps header, main and footer */
#everything {
min-height: 100%;
position: relative;
}
header {
[block element whatever you want]
}
main {
position: relative; overflow: hidden;
padding-bottom: 80px; /* Remove this, we'll be manipulating it with JS*/
}
footer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
And then we have to do make the padding responsive. I’m using jQuery here. You have to do this when the page loads and when the page is resized.
$("main").css("padding-bottom", $("footer").height() );
I won’t go in to how you build efficient resize event handlers here. There is a lot of info about it online. Just to mention a little thing, you need to debounce which essentially means that you need a delay that prevents your function from running on every pixel change. For most resize events you only want them to run once after all resizing has stopped.
Good luck and happy coding!
It’s always a bit tricky to get your hands on solid information on technical usage statistics. I’ve recently been going over statistics for a couple of different Swedish websites so I thought I’d share. I’ve come to the conclusion that about 70% of visitors are on stationary computers. How many of the remaining are on tablets vs mobile phones varies quite a bit though. Some sites have hardly no tablet traffic at all and others have as much tablet as mobile phone. That’s kind of interesting because it indicates that at this point in time, tablet users are to some extent a distinct group. What makes you special, tablet users? Age? Wealth? Interests?