In theming the Drupal Commerce site Zeederberg Leather, on the product page, the mobile view was significantly different to the desktop view. This was in layout as well as function.
Mobile Detect to the rescue!
It is possible in Drupal 8 to load a specific Twig template based on a mobile detect process, however I did not want to use such a extensive solution. I searched around and discovered the Mobile Detect module.
This seemed exactly what I needed. Why?
- For preprocess I could use:
$md=\Drupal::service('mobile_detect'); $is_mobile=$md->isMobile(); $is_tablet = $md->isTablet();
- The Drupal 8 module extends Twig Extensions module thus in my Twig template I can use:
{% if is_mobile() %} {% if is_tablet() %} {% if is_device('iphone') %} {% if is_ios() %} {% if is_android_os() %}
All went fine until I tested on Desktop and Mobile. If I went to the page on desktop first, the page on mobile was blank. If I went to the page on mobile first the page on desktop was blank. At the time of writing this, the current Drupal 8 8.x-2.0
version of the Module does not have cache support. There is an issue on it here.
Resolving the issue
tarik.cipix's snippet (#11) helped me greatly and I was able to use Mobile Detect with the following code in my custom module:
- The Twig template: since I wanted the layout for the product display to be different depending on device, I targeted the
commerce-product.html.twig
template. I had the following:{% if is_mobile() %} {# small screen layout layout #} {% else %} {# large screen layout #} {% endif %}
- Adding Cache Context to the detections: In my custom module I had the following preprocess:
/** * Implements hook_preprocess_HOOK() * * hook_preprocess_commerce_product() * add cache context for the mobile detect module * reference: https://www.drupal.org/project/mobile_detect/issues/2627504 */ function MyModule_preprocess_commerce_product(array &$variables) { // Add cache context so both versions are saved. $variables['#cache']['contexts'][] = 'MyModule_context_mobile_detected'; // Add classes if device is mobile or tablet. $detect = \Drupal::service('mobile_detect'); if ($detect->isMobile()) { $variables['attributes']['class'][] = 'is--mobile'; } elseif ($detect->isTablet()) { $variables['attributes']['class'][] = 'is--tablet'; } else { $variables['attributes']['class'][] = 'is--desktop'; } }
- Define the new Context: I define the new Context in a service in my custom module:
services: cache_context.ze_classy_context_mobile_detected: class: Drupal\ze_classy\Cache\Context\MobileDetectCacheContext arguments: [] tags: - { name: cache.context }
- Add the Context: Add the context in my custom module in:
src/Cache/Context/MobileDetectCacheContext
The code looks something like:‹?php namespace Drupal\MyModule\Cache\Context; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\Context\CacheContextInterface; /** * Class MobileDetectCacheContext. */ class MobileDetectCacheContext implements CacheContextInterface { /** * Constructs a new MobileDetectCacheContext object. */ public function __construct() { } /** * {@inheritdoc} */ public static function getLabel() { return t('Mobile Detect'); } /** * {@inheritdoc} */ public function getContext() { $md = \Drupal::service('mobile_detect'); if ($md->isMobile() || $md->isTablet()) { return TRUE; } return FALSE; } /** * {@inheritdoc} */ public function getCacheableMetadata() { return new CacheableMetadata(); } }
The modules I have used
Use Composer to require and Drush to enable the following module:
composer require drupal/mobile_detect drush en -y mobile_detect
-
Mobile Detect (mobile_detect)
This is a lightweight mobile detection based on the Mobile_Detect.php library, which can be obtained from the GitHub repository.This module is intended to aid developers utilizing mobile-first and responsive design techniques who also have a need for slight changes for mobile and tablet users. An example would be showing (or hiding) a block or content pane to a particular device.
This module is not intended (and never will be enhanced) to provide theme switching or redirection; other modules already provide this functionality.
My research
This article was aided by the following excellent contributions:
Comments
Anonymous users
Does this work for anonymous users? We use varnish implemented this code but anonymous users keep getting mobile content on desktop.
Latest dev branch resolves the issue. 8.x-2.x-dev
See Comment #34. https://www.drupal.org/project/mobile_detect/issues/2627504
Does not work for anonymous users
I have installed the latest version of this module and still it has issue with the internal page cache module. It does not work with internal page cache module enabled.(i.e for anonymous users).
See the note on the module page
About the cache contexts:
By design, the "Internal Page Cache" core module assumes that all pages served to anonymous users will be identical, regardless of the implementation of cache contexts.
If you want to use the mobile_detect cache contexts to vary the content served to anonymous users, "Internal Page Cache" must be disabled, and the performance impact that entails incurred.
https://www.drupal.org/project/mobile_detect
I was very much delighted to…
I was very much delighted to read your blog and it felt very informative to me. But I would like to add some points for some extra information to your readers.
1. Enable Drupal's built-in caching
2. Install and configure caching modules
3. Implement custom caching
4. Utilize a Content Delivery Network (CDN)
5. Consider integrating Varnish caching
6. Implement cache invalidation strategies
7. Test and benchmark your website to ensure caching
These are some of the points I thought to be included. Having a non-technical background it was difficult for me to develop an optimized website but a company like Alakmalak Technologies helped me to build a high-quality website, you can also visit them if you are having the same problem.
@Katelin, I appreciate..
the time you took to add these comments. Many thanks
Add new comment