' . 'Settings' . ''; return $links; } /** * Adds a link to the adaptive images settings in the plugins listing page for convenience. * * @author Nevma (info@nevma.gr) * * @param array $links The plugin links array in the plugins listing page. * * @return void */ function adaptive_images_admin_settings_row_meta_add ( $links, $file ) { if ( $file != adaptive_images_plugin_get_name() ) { return $links; } $links[] = 'Plugin page'; $links[] = 'Support page'; return $links; } /** * Adds the plugin settings page to the admin area. * * @author Nevma (info@nevma.gr) * * @return void */ function adaptive_images_admin_settings_page_add () { // Adds the plugin's options page as a submenu of the admin settings. $hook_name = add_options_page( 'Adaptive Images', // page title 'Adaptive Images', // menu title 'manage_options', // capability 'adaptive-images', // menu slug 'adaptive_images_admin_print_options_page' // print function callback ); // Adds the action which adds the plugin admin actions. add_action( 'admin_head-' . $hook_name, 'adaptive_images_admin_settings_actions' ); } /** * Registers the plugin settings. * * @author Nevma (info@nevma.gr) * * @return void */ function adaptive_images_admin_settings_register () { // Registers the plugin settings field. register_setting( 'adaptive-images-settings', // option group 'adaptive-images', // option name 'adaptive_images_admin_settings_sanitize' // function validator callback ); // Adds the plugin main settings section. add_settings_section( 'adaptive-images-settings', // id '', // title '', // print function callback 'adaptive-images' // plugin page ); // Adds the adaptive images resolutions field. add_settings_field( 'resolutions', // id 'Resolution breakpoints', // title 'adaptive_images_admin_print_resolutions_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images landscape field. add_settings_field( 'orientation', // id 'Landscape orientation', // title 'adaptive_images_admin_print_landscape_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images hidpi field. add_settings_field( 'hidpi', // id 'HiDPI support', // title 'adaptive_images_admin_print_hidpi_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images CDN support field. add_settings_field( 'cdn-support', // id 'CDN support', // title 'adaptive_images_admin_print_cdn_support_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images cache directory field. add_settings_field( 'cache-directory', // id 'Cache directory', // title 'adaptive_images_admin_print_cache_directory_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images watched directories field. add_settings_field( 'watched-directories', // id 'Watched directories', // title 'adaptive_images_admin_print_watched_directories_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images content types field. add_settings_field( 'content-type', // id 'Image types', // title 'adaptive_images_admin_print_content_types', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images JPEG quality field. add_settings_field( 'jpeg-quality', // id 'JPEG quality', // title 'adaptive_images_admin_print_jpeg_quality_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images sharpen field. add_settings_field( 'sharpen-images', // id 'Sharpen images', // title 'adaptive_images_admin_print_sharpen_images_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images watch cache (for stale images) field. add_settings_field( 'watch-cache', // id 'Watch cache', // title 'adaptive_images_admin_print_watch_cache_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); // Adds the adaptive images browser cache duration field. add_settings_field( 'browser-cache', // id 'Browser cache', // title 'adaptive_images_admin_print_browser_cache_field', // print function callback 'adaptive-images', // plugin page 'adaptive-images-settings' // section ); } /** * Prints the resolutions settings field. * * @author Nevma (info@nevma.gr) * * @return void */ function adaptive_images_admin_print_resolutions_field () { $options = adaptive_images_plugin_get_options(); adaptive_images_plugin_check_empty_setting( $options, 'resolutions' ); ?> A comma separated list of device widths.
These are the different image sizes that will be created, cached and served to mobile devices.

Resolution breakpoints

Think of these numbers as breakpoints or as important device resolutions, that correspond to device widths. When a request is made from any device, the Adaptive Images plugin tries to calculate in which of these breakpoits the device falls into, so that it can serve it an appropriate scaled image size according to them.

Example 1:

• Device that sends the request: 640px wide
• Available resolution breakpoints: { 1024, 640, 480 }

=> Bingo, the the 640px breakpoint is chosen.

Example 2:

• Device that sends the request: 800px wide
• Available resolution breakpoints: { 1024, 640, 480 }

=> The 1024px breakpoint is the closest biggest one.

Example 3:

• Device that sends the request: 320px wide
• Device pixel density: 2 (HiDPI/retina)
• Available resolution breakpoints: { 1024, 640, 480 }

=> The 640px breakpoint is chosen because 2x320=640.

If the original image size is even smaller than the chosen breakpoint, then the original image is served (because it is too small). If the device is bigger than the biggest breakpoint, then the original image is served again (because it is too big).

This way we do not need to create and cache too many image sizes, one for every available device out there. It is up to you to decide how many such resolution breakpoints you need. You may have 100, if you want, or even just 1. However the default 3 are a good default choice, based on the known popular devices of today.

Landscape orientation

Users usually hold their devices in the portrait orientation like this 📱, but quite often they also hold them in the landscape orientation like this 📱, so this setting defines whether the Adaptive Images plugin should or shouldn't take into account the device orientation when determining its width.

HiDPI Support

Many mobile and tablet screens NOWADAYS have a feature called HiDPI (high device pixel density). Most people know these screens as retina. What they can do is to take bigger versions of an image and render it to the size instructed by the developer, but with much better clarity (due to the bigger size).

For example, if the pixel density of a device is 2, then it can take a 1000px version of a 500px image and show it with much better clarity still seeming 500px. Adaptive Images can detect these devices and serve them bigger images, yet remaining withing the boundaries of the given resolution breakpoints.

Of course this results in sending bigger file sizes to these devices, depending on the compression settings you have chosen. Your call.

CDN Support

CDNs, Varnish and other external caching servers, when they are used, stand between your website and your users in order to deliver your content and, of course, you images to them. With this option the Adaptive Images plugin alters your HTML images in the server side, and then, in the browser side, adds a special url parameter to their src attributes via Javascript, so that the caching server may know which version of an image to serve each time.

Examples

The general idea is that the Adaptive images plugin replaces in the server the src and srcset attributes to data-adaptive-images-src and data-adaptive-images-srcset and then, in the browser, when the DOM loads, it restores them with Javascript back to normal by addding them the information for the device dimensions on the url like this ?resolution=360,1.

Image elements with src


            

Image elements with srcset


            

Image elements inside figure elements


            

Picture elements


            

Notice

This technique inevitably tampers with the HTML output of your website. You are advised to test it with caution. CDNs and frontend libraries (like image lazy loading) use many different and diverse techniques to achieve their goals. It takes one to know the underlying mechanics of all of them in order to resolve any spossible conflicting circumstances. We will be more than happy to support you on this.

Directory inside /wp-content to store the image cache.
Current path of cache directory on server: .

Cache directory

Right now saving the image cache in a directory outside your WordPress installation is not supported. Actually, to be precise, the cache directories must be inside the /wp-content directory. So, this setting is a relative path inside it. Leaving this setting in its default value, /wp-content/cache/adaptive-images, is the best option because this is what many other plugins use as a standard place for caching stuff.


Directories to watch for images to resize. Has to be relative paths inside your WordPress installation.

Watched directories

These are the directories in which your original images are saved by WordPress. The Adaptive Images plugin must know which of these directories you want to be watched for resizing its images. The most common are the /wp-content/uploads and the /wp-content/themes. But it could be anything else you choose.

Just remember that these directories must be inside your WordPress installation in order for the plugin to be able to detect them and serve them in the way it is designed. It is possible for one to keep their /wp-content outside WordPress, but this is a case we are still working on.

You may freely change the name of your /wp-content and /wp-content/uploads directories, but you must update the above list of watched directories manually in this case.


Choose the image types that you wish the Adaptive Images plugin to handle, resize and serve.

Image types

The Adaptive Images plugin can handle JPG/JPEG images very well indeed. It also handles PNG images with or without transparency and also alpha transparency. It is not able to compress PNGs very effectively on the fly, but it does a great job resizing them. GIF images are also supported, but without frames. If you do not choose an image type of the above, then the images that belong to it will simply be served in their original version. All image conversions are done via the PHP GD library.

Compression level of JPEG images, 100 means best quality but biggest file size.
Usuallly a 75 JPEG compression level works fine for the human eye with very small file sizes. Your call!

JPEG quality

A JPEG image is a compressed image with reduced quality and smaller file size when compared to its original version. However the JPEG algorithm manages to achieve amazing results in reducing the file sizes of images yet retaining excellent quality for the human eye. But JPEG has many compression levels. We measure these levels in a scale of 0-100:

 • 0 => low quality, smaller file sizes
 • 100 => high quality, bigger file sizes

It is generally acceptable that -practically speaking- a JPEG compression level of around 75 achieves more than decent quality for the human eye, while keeping the resulting file size orders of magnitude smaller than the original file. Unfortunately, one cannot further compress an already compressed JPEG image, unless they decide to lower its quality.

Sharpen images

When images are resized to smaller dimensions and compressed, eg via the very efficient JPEG algorithm, it is possible that some blur may appear in certain areas. Usually this is not even visible to the human eye. Sharpening the images attempts to reduce this blur in a generic manner, adding a bit of contrast and seeming clarity to them. This is quite safe a process. Leaving it on, in it default value, guarantees a minimum of good quality results.

Watch cache

By selecting this feature, when the original version of the image has been updated in the filesystem, the Adaptive Images plugin will detect it the first time the images is accessed again and update the cache accordingly. Usually, this is not much to worry about, unless you edit your images after having uploaded them to your website.

How long should browsers be instructed to "remember" images.
Unless you have a very special need and you know what you are doing, set this as high as you can.

Browser cache

Browsers are designed to remember images (and other resources) that they present to their users. This way they do not have to download everything every time a website is accessed and, as a result, websites can load faster. However sometimes some resources do change and a browser needs to be notified about it. This is when a user hits one "Refresh" after the other waiting for fresh content.

Fortunately, an uploaded image in WordPress changes very rarely, if ever. So, feel free to set the browser cache time period as high as you wish. It will only do good to the download times of your website, especially if you have users who visit it repeatedly.

Adaptive Images for WordPress Settings

Image cache tools

Cleanup the image cache or simply calculate its current size (takes some time, depending on the cache size). Calculate size Cleanup cache

Debugging Tools

Print useful plugin debug information. Print debug info Print diagnostics

Help & support

Do not hesitate to report any problems you may encounter and send us your suggestions in the plugin support page.

Plugin support page

Show us your love

🌟🌟🌟🌟🌟
We do appreciate honest reviews and ratings, so feel free to give us one!

🍺🍺🍺🍺🍺
Should you wish to buy us a glass of beer, then bless you, we prefer weiss!

🍫🍫🍫🍫🍫
We are also suckers for fine dark chocolate, so feel free to spoil us with some.

Nevma
The development team

If you are not so sure about yourself, just trust the wisely chosen defaults. Hit the question marks for more help.

Adaptive Images v.

' . '

Total files deleted from the adaptive images cache: ' . $result['files'] . '

' . '

Total directories deleted from the adaptive images cache: ' . $result['dirs'] . '

' . '

' . 'Total size deleted from the adaptive images cache: ' . adaptive_images_plugin_file_size_human( $result['size'] ) . '

', 'updated' ); } // Calculate image cache size action. if ( $_GET['action'] == 'calculate-cache-size' && wp_verify_nonce( $_GET['_wpnonce'], 'adaptive-images-calculate-cache-size' ) ) { $cache_path = adaptive_images_plugin_get_cache_directory_path(); $cache_size = adaptive_images_plugin_dir_size( $cache_path ); add_settings_error( 'adaptive-images-settings', 'adaptive-images-settings-error', 'Calculate cache size
' . '

Total files in the adaptive images cache: ' . $cache_size['files'] . '

' . '

Total directories in the adaptive images cache: ' . $cache_size['dirs'] . '

' . '

' . 'Total size of the adaptive images cache: ' . adaptive_images_plugin_file_size_human( $cache_size['size'] ) . '

', 'updated' ); } // Print plugin info action. if ( $_GET['action'] == 'print-debug-info' && wp_verify_nonce( $_GET['_wpnonce'], 'adaptive-images-print-debug-info' ) ) { add_settings_error( 'adaptive-images-settings', 'adaptive-images-settings-error', 'Debug information
' . adaptive_images_debug_general_info( FALSE ), 'updated' ); } // Print system info action. if ( $_GET['action'] == 'print-diagnostic-info' && wp_verify_nonce( $_GET['_wpnonce'], 'adaptive-images-print-diagnostic-info' ) ) { add_settings_error( 'adaptive-images-settings', 'adaptive-images-settings-error', 'Diagnostic information
' . adaptive_images_debug_diagnostics( FALSE ), 'updated' ); } } /** * Validates the adaptive images submitted settings. * * @param $data array The submitted settings array. * * @author Nevma (info@nevma.gr) * * @return The sanitized and validated settings array. */ function adaptive_images_admin_settings_sanitize ( $data ) { // To avoid the bug of sanitizing twice the first time the option is created. if ( isset( $_REQUEST['sanitized'] ) && $_REQUEST['sanitized'] ) { return $data; } // Get the defaults just in case. $defaults = adaptive_images_plugin_get_default_settings(); // Resolutions field array validation. if ( isset( $data['resolutions'] ) && is_array( $data['resolutions'] ) ) { // Option given as an array or already stored as an array. $resolutions_array = $data['resolutions']; } else if ( isset( $data['resolutions'] ) && is_string( $data['resolutions'] ) ) { // Option coming from settings page form field as a string. $resolutions = trim( $data['resolutions'] ); $resolutions_array = explode( ',', $resolutions ); } else { // Default case, option has never been set. $resolutions_array = $defaults['resolutions']; } $resolutions_array_sanitized = array(); for ( $k = 0, $length = count( $resolutions_array ); $k < $length; $k++ ) { $resolution = trim( $resolutions_array[$k] ); $resolution = intval( $resolution ); if ( $resolution > 0 ) { $resolutions_array_sanitized[] = $resolution; } } rsort( $resolutions_array_sanitized ); if ( count( $resolutions_array_sanitized ) == 0 ) { $resolutions_array_sanitized = $defaults['resolutions']; } $data['resolutions'] = $resolutions_array_sanitized; // Landscape field validation. $landscape = isset( $data['landscape'] ) && $data['landscape'] == 'on' ? TRUE : FALSE; $data['landscape'] = $landscape; // Hidpi field validation. $hidpi = isset( $data['hidpi'] ) && $data['hidpi'] == 'on' ? TRUE : FALSE; $data['hidpi'] = $hidpi; // Hidpi field validation. $cdn_support = isset( $data['cdn-support'] ) && $data['cdn-support'] == 'on' ? TRUE : FALSE; $data['cdn-support'] = $cdn_support; // Cache field directory validation. $cache_directory = isset( $data['cache-directory'] ) ? trim( $data['cache-directory'] ) : ''; if ( $cache_directory == '' ) { $cache_directory = $defaults['cache-directory']; } // $cache_directory = preg_replace( '/[^a-zA-Z\d-_\/]+/i', '', $cache_directory ); $cache_directory = validate_file( $cache_directory ) == 0 ? $cache_directory : ''; $cache_directory = wp_normalize_path( $cache_directory ); $cache_directory = untrailingslashit( $cache_directory ); $cache_directory = trim( $cache_directory ); if ( ! adaptive_images_plugin_is_file_in_wp_content( $cache_directory ) ) { $cache_directory == $defaults['cache-directory']; } $data['cache-directory'] = $cache_directory; // Watched directories field validation. if ( isset( $data['watched-directories'] ) && is_array( $data['watched-directories'] ) ) { // Option given as an array or already stored as an array. $watched_directories_array = $data['watched-directories']; } else if ( isset( $data['watched-directories'] ) && is_string( $data['watched-directories'] ) ) { // Option coming from settings page form field as a string. $watched_directories_string = trim( $data['watched-directories'] ); $watched_directories_array = explode( "\n", $watched_directories_string ); } else { // Default case, option has never been set. $watched_directories_array = $defaults['watched-directories']; } $watched_directories_array_sanitized = array(); foreach ( $watched_directories_array as $directory ) { // $directory = preg_replace( '/[^a-zA-Z\d-_\/]+/i', '', $directory ); $directory = validate_file( $directory ) == 0 ? $directory : ''; $directory = wp_normalize_path( $directory ); $directory = untrailingslashit( $directory ); $directory = trim( $directory ); if ( $directory ) { $watched_directories_array_sanitized[] = $directory; } } $data['watched-directories'] = $watched_directories_array_sanitized; // Content types fields validation. if ( isset( $data['content-types-jpeg'] ) || isset( $data['content-types-png'] ) || isset( $data['content-types-gif'] ) ) { // Options comming from settings page form as checkbox values. $content_types = array(); if ( isset( $data['content-types-jpeg'] ) && $data['content-types-jpeg'] == 'on' ) { $content_types []= 'jpg'; $content_types []= 'jpeg'; unset( $data['content-types-jpeg'] ); } if ( isset( $data['content-types-png'] ) && $data['content-types-png'] == 'on' ) { $content_types[] = 'png'; unset( $data['content-types-png'] ); } if ( isset( $data['content-types-gif'] ) && $data['content-types-gif'] == 'on' ) { $content_types[] = 'gif'; unset( $data['content-types-gif'] ); } $data['content-types'] = $content_types; } adaptive_images_plugin_check_empty_setting( $data, 'content-types' ); // JPEG quality field validation. $jpeg_quality = isset( $data['jpeg-quality'] ) ? intval( $data['jpeg-quality'] ) : 0; if ( $jpeg_quality <= 0 || $jpeg_quality > 100 ) { $jpeg_quality = $defaults['jpeg-quality']; } $data['jpeg-quality'] = $jpeg_quality; // PNG8 setting hardcoded to false for now. $data['png8'] = FALSE; // Sharpen field validation. $sharpen_images = isset( $data['sharpen-images'] ) && $data['sharpen-images'] == 'on' ? TRUE : FALSE; $data['sharpen-images'] = $sharpen_images; // Watch cache field validation. $watch_cache = isset( $data['watch-cache'] ) && $data['watch-cache'] == 'on' ? TRUE : FALSE; $data['watch-cache'] = $watch_cache; // Browser cache field validation. $browser_cache = isset( $data['browser-cache'] ) ? floatval( $data['browser-cache'] ) : -1; if ( $browser_cache < 0 ) { $browser_cache = $defaults['browser-cache']; } $data['browser-cache'] = $browser_cache; // Save plugin version. $data['version'] = adaptive_images_plugin_get_version(); // Avoid the bug of sanitizing twice in the same request. $_REQUEST['sanitized'] = TRUE; // Notify user appropriately. $message = 'Adaptive Images — Settings updated.
' . '

✔ The plugin settings have been saved in the database.

'; // Add the adaptive images .htaccess rewrite block. $result = adaptive_images_actions_htaccess_update( $data ); if ( is_wp_error( $result ) ) { $error_data = $result->get_error_data(); $htaccess = $error_data['htaccess']; $permissions = adaptive_images_plugin_file_permissions( $htaccess ); $message .= '

' . '✖ ' . $result->get_error_message() . '

' . '

' . 'This probably means a filesystem error or a permissions problem: ' . '' . $htaccess . ' => ' . $permissions . '.' . '

' . '

' . 'Consider adding this code to your .htaccess file manually: ' . '

' . htmlspecialchars( trim( $error_data['rewrite'] ) ) . '
' . '

'; } else { $message .= '

' . '✔ The .htaccess file has been successfully updated: ' . '' . adaptive_images_plugin_get_htaccess_file_path() . '.' . '

'; } // Add the /wp-content directory path and web url to the settings. $data['wp-content-dir'] = wp_normalize_path( WP_CONTENT_DIR ); $data['wp-content-url'] = WP_CONTENT_URL; // Save user settings PHP file. $result = adaptive_images_actions_user_settings_php_save( $data ); if ( is_wp_error( $result ) ) { $file = adaptive_images_plugin_get_user_settings_file_path(); $permissions = adaptive_images_plugin_file_permissions( $file ); $message .= '

' . '✖ ' . $result->get_error_message() . '

' . '

' . 'This probably means a filesystem error or a permissions problem. Please contact your system administrator on how to deal with this!' . '

' . '

' . 'The user settings file permissions are: ' . '' . $file . ' => ' . $permissions . '.'. '

' . '

' . 'The plugin will still be able to function but with its default settings until this problem is resolved.' . '

'; } else { $message .= '

' . '✔ The user settings PHP file was successfully updated: ' . '' . adaptive_images_plugin_get_user_settings_file_path() . '.' . '

'; } // Add NginX configuration info. $message .= '

' . '--
' . 'If you are using NginX, you probably need to manually add this snippet in your configuration file:' . '

' . '
' .
                adaptive_images_actions_nginx_get_block() .
            '
'; // Inform user accordingly. add_settings_error( 'adaptive-images-settings', 'adaptive-images-settings-error', $message, 'updated' ); return $data; } ?>