Month: May 2015

wp_remote_get() vs. wp_safe_remote_get()

Due to a small Twitter discussion, which started after a tweet of Pippin I realized again, the WordPress HTTP API has “safe” functions. Some days or weeks ago I’ve heard of them already, but I didn’t check on them. The topic is the following: The functions wp_remote_post(), wp_remote_get() and wp_remote_head() do have siblings, which are not documented in the Codex but only in the reference:

After the WordPress community discusses largely the top security, I was quite alarmed. What are these “safe”-functions and what do they do? What is the difference between wp_remote_post() and wp_safe_remote_post()?

How the HTTP API works

Before we start, let’s be clear, what the HTTP API actually does. In wp-includes/http.php several functions are located, with which you can perform HTTP requests. All these functions basically interact with the WP_Http() class, located in wp-includes/class-http.php.

So it is relatively easy to perform a POST request with the function wp_remote_post() and to work with the received data afterwards. Tom McFarlin has published a tutorial how to work with this function on Tuts+.

What is the difference between wp_remote_post() and wp_safe_remote_post()?

If you read the source code, you will find only one difference: wp_safe_remote_post() – and the same applies to all safe_remote functions – extends the argument array with the boolean 'reject_unsafe_urls' set to true:

As you can see, these arguments are passed to the WP_Http() class. So what does 'reject_unsafe_urls' accomplish there? Once this boolean is true, the URL gets validated by the function wp_http_validate_url().

What does wp_http_validate_url()?

Since WordPress 3.5.2 wp_http_validate_url() can be found in the core. If you read the description in the source, it says.

[The function] validate[s] a URL for safe use in the HTTP API.

How does the function perform this task? As a first step, it checks (by using wp_kses_bad_protocol()), if the URL has a valid protocol. Valid protocols are only HTTP and HTTPS. If 'reject_unsafe_urls' is not true SSL is also perceived as a valid protocol (s. wp-includes/class-http.php L186). If the protocol is not valid the function will return false.

Also a URL is considered to be unsafe, if it contains a username or a password, by which a user tries to authenticate himself. The following URL would be rejected: http://benutzername:passwort@example.com

If the host of the URL contains one of the following symbols, the URL will be rejected: :#?[]

URLs which do resolve to another port than 80, 443 or 8080 – so to speak the usual HTTP posts – will be rejected.

And this is for safety reasons?

To understand the history of the safe_remote functions it helps to study the ticket 24646. In WordPress Version 3.5.2 the core developers focused on securing the HTTP API against Server Side Request Forgeries. Lets just assume, the HTTP API would not check the protocols before firing the request and the requested URL would be dict://localhost:11211/stat. This would send the string “stat” to the locale Memcached, which usually listens to the port 11211. Since the request was locally, no firewall would prevent the server to respond to this request. To be short here: Danger! In 3.5.2 the developers closed this issue, but they overshoot a little bit. The result was, WordPress was not able to access the locale installation with the HTTP API. If you wanted to fetch your own feed using wp_remote_get() the script blocked the resource.

So they had to step back a little bit. Well, the mentioned attack above is not possible, even using wp_remote_get(). But they introduced the safe remote functions. As long as you can be sure the URL can not be used for an attack on the own system, you still can rely on wp_remote_get(), wp_remote_post() and wp_remote_head(). This is useful, if you want to perform HTTP requests, which target your own host.

But if you can not be sure about the URL, you should use wp_safe_remote_get(),wp_safe_remote_post() and wp_safe_remote_head() to raise the level of security. From now on the request is limited to the conditions mentioned above.

TLTR

If you are not sure about the URL which will be passed through wp_remote_get() use wp_safe_remote_post(). It is simply the safe way to do it.

Of what use is wp_is_mobile() in times of responsive web design?

Today, I want to discuss a function in WordPress which some might believe is outdated: wp_is_mobile() (to be found in wp-includes/vars.php). This function detects whether a mobile device is used or not by using the user agent of the browser. What? In times of responsive web design? Five years after Ethan Marcottes legendary article about responsive web design?

Usage in the WordPress Core

And still, aren’t there uses where we need to know on the PHP level if a user visits the site is using a mobile device? Let’s have a look into the WordPress Core first and see, how the function is used there.

The admin bar

When WordPress renders the admin bar, it checks by using wp_is_mobile() if a mobile device is used. In this case, the class .mobile will be attached to the bar (see wp-includes/class-wp-admin-bar.php), although, if I am not mistaken, there are no additional styles attached to this class. Also the body-Tag in the admin gets extended by the .mobile class, which changes the behavior of the menu for example.

The editor

The WordPress editor in mobile view
The WordPress editor in mobile view

Most people will write their blog posts usually in the WYSIWYG mode. At least, they have the possibility. But not, if they use mobile devices. In this case the function user_can_richedit() (wp-includes/general-template.php) will return false and what remains is the text mode. The “Visual”-Tab, which you usually find on the top right disappears as well as the full screen button.

More uses

Furthermore, you will find this function is used by _device_can_upload(). But here it plays a minor role. WordPress uses this boolean also to pass it to Javascript, for example in the Customizer.

How works wp_is_mobile()?

The basic is very simple. It checks whether the user agent of the browser contains one of the following text strings: “Mobile”, “Android”, “Silk/”, “Kindle”, “BlackBerry”, “Opera Mini” or “Opera Mobi”. In this case, the function will return true otherwiese false. With these seven strings all major mobile browsers are detected, which lets this function work pretty accurate. Of course it can always happen, a user changes his user agent individually and is not detected correctly. But, these cases aside, wp_is_mobile() works quite well in detecting mobile devices.

More interesting use cases

Since the last mobile update by Google the topic is back again. Mobile devices take more time to render pages and in most cases the internet connection is slower than for desktop devices. All this is bad for the user experience. If you develop your site mainly for desktop, using heavy sliders and much more, for mobile users this results in a catastrophe. Not only many sliders are not as mobile as one wishes them to be, especially the loading times are horrible. This results in high bounce rates. So, why don’t you stop the output of sliders and other heavy features on mobile devices by using wp_is_mobile()?

Another nice feature, you could easily realize with wp_is_mobile()? You could add an additional feature for mobile devices. In many cases the top of the page has a bar with the contact details. Why not checking if the device is mobile and add a SMS button to this bar?

Conclusion

Even the WordPress Core is still using a function which looks a bit outdated right now. And I tried to present two small examples, where I think checking the device on the PHP level would be more efficient than using CSS. If you have other use cases for this function or you have another opinion about the function, I am always happy about comments. 🙂

WordPress And Backwards Compatibility

If you ask a developer why WordPress has so much more success compared to other CMS like Drupal or Joomla, one concept will pop up for sure: Backwards Compatibility. Since the beginning of WordPress, its developers focused on one issue: Not to break functionality from one version to another.

One example are deprecated functions: Functions which aren’t used no more in one version won’t be simply kicked out. They remain in the core and will be marked as deprecated. They remain quite a while till they are finally kicked out. Long before this happens, developers can inform themselves on this page, which of the WordPress functions are deprecated. And also by using WP_DEBUG they will be informed.

Another example is the database. The wp_links table is currently of no use in WordPress. It sounds simple: WordPress doesn’t need this table no more and deletes it. But nobody knows, which data is stored in this table by single installations and how this data is used. To simply delete this table would have drastic consequences. Data, which WordPress users have collected with a lot of effort would simply disappear. Instead of keeping a consistent structure and remove this table, WordPress still keeps it, although it has no current use for it.

Related to this topic: Did anyone wonder, why the Post ID in the table wp_term_relationship is called object_id and not, like in any other table post_id? Even rows of wp_links used to be connected to terms. So back then, the developers decided to call this column object_id, since it contained not only post IDs. But nowadays the column basically contains only post IDs. Still the name remains. Why? How many plugins are out there, who access this table via SQL and are using object_id in their syntax? All these plugins would break! WordPress has a history and you can read its history by reading its inconsistencies.

Even in revised functions you will find examples: Take the second parameter of load_plugin_textdomain() as one. You always have to set this parameter to false. Until version 2.7 this parameter was carrying the relative path to the directory with the translations. Today the relative path is defined starting from WP_PLUGIN_DIR and not from ABSPATH. So the second parameter is deprecated and you define the relative path by the third parameter. But still, the second remains since old plugins might still use it. If you would remove this parameter, plugins would break.

From the user’s point of view, this all might look different. With every update the forums are floated with questions like “I just made an update and I can’t reach my admin no more/ I don’t see my pictures no more/ I can’t reach my site no more”. But all these questions lead us only towards two insights:

  1. How important backwards compatibility really is and
  2. how difficult it is, to realize backwards compatibility in an environment like WordPress.

For developers backwards compatibility is a double-edged sword, because it bloat your code. For some out of proportion. But if you consider the recent debate about security and the necessity to keep your system up to date, most developers conclude: there is no other way than backwards compatibility. Everything else would lead to a disproportionate effort especially for small bloggers and businesses or – if you consider almost 20 percent of the internet sites are run on WordPress – to a much more insecure Internet.

But: Is the concept of backwards compatibility only a topic for the core developers or do we plugin and theme developers have to be alerted too? Of course it has to concern us too. To update a plugin has to be a secure process which doesn’t break things.* Exactly like updating WordPress. This is the reason why Pippin Williamson, author of Easy Digital Downloads, gave a great speech on the Loopconf 2015 addressing backwards compatibility. I think every developer should watch this:

*) I have to admit, I need to do some work on one of my plugins as well to match the criteria of backwards compatibility. Well, not now, but this post shall be a reminder for me too 🙂

BuddyPress Desktop Notification

My latest plugin has just been released on wordpress.org: “BuddyPress Desktop Notification“. If you are running a BuddyPress community, you can use this plugin in order to display new messages, activities and friendship requests for your users.

BuddyPress Desktop Notification
A notification, which is displayed, while the browser is open

How this works? After a user logged in, the browser will ask for the permission to display desktop notifications. This works with most modern browsers (see a list here). While usually notification plugins show a pop-up or something similar, which are displayed only in the browser, desktop notifications also pops up, if the browser is minimized:

Desktop notification works also with minimized browsers
Desktop notification works also with minimized browsers

It’s quite a lightweight plugin, but it might cause some traffic because it produces an ajax request every five seconds for every logged in user who enabled the notifications. I decided to make this plugin configurable via filters and not using another admin menu page, since – to be honest – I am not such a fan of overloaded admin menus. If you are using this plugin and it produces too much load, you can reduce the request interval with the following piece of code:

More information on my latest plugin can be found on the website.

Four ways to hide the WordPress admin bar

If you are logged in, WordPress usually displays the admin bar on the top of your page. But there are situations, where you don’t want to display the bar. Sometimes, it is ruining your site layout or you want to hide the bar for certain groups of users.

There are different ways to hide the admin bar. The first way is of course, to uncheck the corresponding checkbox in the admin itself.

You can disable the adminbar.
You can disable the admin bar for certain users.

If it’s just about one or two users this is probably the quickest way to solve this issue. It will be less comfortable, when you are handling dozens of users or when you have to repeat this procedure for each new user by hand.

So it is interesting to know, where the information is saved. It is a meta information for users, saved in the wp_usermeta table of the database. The corresponding key, which is used to save this setting is 'show_admin_bar_front'. The value 'true' displays the admin bar, while the value 'false' will hide it. So you could set this value to 'false' during the registration:

But maybe you want to hide the toolbar only in specific sections of your site. Responsible for the rendering of the bar are the functions _wp_admin_bar_init() and wp_admin_bar_render() which reside in wp-includes/admin-bar.php. Before these functions start to render the bar, they check by using is_admin_bar_showing(), if the bar is supposed to show up. This function can be found in admin-bar.php too. is_admin_bar_showing() just returns a boolean, whether the bar is supposed to show up or not. By using the filter hook 'show_admin_bar' you can intervene in the process. So you could tell WordPress to suppress the rendering of the bar on blog posts:

Of course, there remains the possibility to hide the bar by using CSS. The admin bar has the ID '#adminbar', which you can simply hide:

#adminbar{ display: none; }

But by doing this, the native layout is not restored yet. By using margin WordPress creates some space for the admin bar on the top of the page by moving the whole HTML-element 32 pixels down. Since all this takes place in the 'wp_head' action, you have to load your definitions later. One option is, to use the 'wp_footer'-action and move the HTML-element back on the top again. You have to consider, WordPress is using !important, so we have to do so too:

As you can see, there are a lot of ways to hide the admin bar. It depends on your needs, which of these ways is the best for you.