Uso del Sections.xml
Los datos pueden guardarse del lado del servidor o del lado del cliente (Navegador). Si los datos están en el servidor, es posible que estén en algún gestor de base de datos por ejemplo Mysql, MongoDB, SQLite, Elasticsearch, OpenSearch, Varnish, Redis etc. Pero los datos también pueden guardarse en el ordenador del usuario. Los navegadores disponen de varias formas para guardarlos.
Cookies
Las cookies son creadas por el servidor en el navegador del usuario y son enviadas de vuelta al servidor en sus siguientes peticiones HTTP.
# Ejecutar el siguiente código en el devtool console del navegador para ver cookies # Ojo! Las cookies que tengan la propiedad HttpOnly no estarán en la lista console.table(Object.fromEntries(document.cookie.split('; ').map(c => c.split('='))));
Las cookies pueden tener las siguientes propiedades:
- Name: Nombre de la cookie
- Value: Valor del nombre de la cookie
- Domain: El dominio al que el navegador enviará de vuelta las cookies
- Path: indica la ruta que debe existir en el dominio. Si el path es "/", cualquier ruta será admitida
- samesite: Tiene 3 tipos:
- Strict: la cookie no será enviada desde dominios diferentes del que creó la cookie.
- Lax: si el dominio es diferente, la cookie será enviada, si la petición se originó desde el dominio donde se creó la cookie y es del tipo HTTP GET. Por ejemplo: al clicar sobre un enlace externo de la página
- None: la cookie será enviada en todos los casos.
- Secure: si es true exige que el protocolo sea https. Si es false, se puede usar el http.
- HttpOnly: Si es true, la cookie no podrá ser modificada mediante Javascript. Tampoco estará en la lista si ejecutamos
document.cookie
Las cookies disponibles en Magento 2 pueden ser las siguientes:
Cookie | Descripción |
form_key | Se añade un input del tipo hidden en el formulario para protegerse de los ataques CSRF (Cross Site Request Forgery). |
mage-cache-sessid | Limpia el localstorage si la cookie es eliminada desde el lado de servidor. Al eliminarla, la cookie toma el valor true. |
private_content_version | Versión de los datos privados guardados en el localstorage del navegador. |
Observaciones
mage-cache-sessid
Se invoca el método invalidateCacheByCloseCookieSession cuando se recarga la página para comprobar si la cookie es eliminada del lado del servidor.
# Ruta: app/code/Magento/Customer/view/frontend/web/js/customer-data.js
/**
* Invalidate Cache By Close Cookie Session
*/
invalidateCacheByCloseCookieSession = function () {
if (!$.cookieStorage.isSet('mage-cache-sessid')) {
storage.removeAll();
}
$.cookieStorage.set('mage-cache-sessid', true);
};
# Se ejecuta este método al inicializar la clase customer-data
/**
* @param {Object} settings
* @constructor
*/
'Magento_Customer/js/customer-data': function (settings) {
options = settings;
customerData.initStorage();
invalidateCacheBySessionTimeOut(settings);
invalidateCacheByCloseCookieSession();
customerData.init();
deferred.resolve();
}
private_content_version
El valor cambia cuando hay petición HTTP POST o PUT como por ejemplo clicando el botón añadir al carrito. Cambia cuando hay carga de secciones.
# Ruta: lib/internal/Magento/Framework/App/PageCache/Version.php
/**
* Handle private content version cookie
* Set cookie if it is not set.
* Increment version on post requests.
* In all other cases do nothing.
*
* @return void
*/
public function process()
{
if ($this->request->isPost()) {
$publicCookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata()
->setDuration(self::COOKIE_PERIOD)
->setPath('/')
->setSecure($this->request->isSecure())
->setHttpOnly(false)
->setSameSite('Lax');
$this->cookieManager->setPublicCookie(self::COOKIE_NAME, $this->generateValue(), $publicCookieMetadata);
}
}
Localstorage
El full page caché de Magento tiene 2 tipos: privado y público. Los datos compartidos (cabecera, menú, pie de página etc.) se almacenan del lado del servidor en los mecanismos como Varnish, Redis y File Cache System. Los datos privados de cada usuario tales como el carrito, el checkout etc. se guardan del lado cliente (navegador) por ejemplo en el LocalStorage. Si vemos el encabezado de las páginas cache-controls cache-control: no-store, no-cache, must-revalidate, max-age=0, es porque Varnish no quiere que los navegadores cacheen porque el caché compartido está en el Varnish.
Magento define los datos del Localstorage con PHP y los pinta en los ficheros phtml. Luego esos datos son recogidos por Javascript y y puestos en el almacenamiento Localstorage del navegador. Si se quiere modificar algún dato del almacenamiento, Magento usa peticiones POST mediante Ajax.
Renovación de los datos para el Localstorage
En el LocalStorage se guardan datos de customer, cart, address etc. Si queremos que se renueven los datos para las peticiones HTTP POST o HTTP HEAD, tenemos que especificar las urls en el fichero sections.xml.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
<action name="customer/account/logout">
<section name="*"/>
</action>
<action name="customer/account/loginPost">
<section name="*"/>
</action>
<action name="customer/account/createPost">
<section name="*"/>
</action>
<action name="customer/account/editPost">
<section name="*"/>
</action>
<action name="customer/ajax/login">
<section name="checkout-data"/>
<section name="cart"/>
</action>
</config>
En la etiqueta action se pone la ruta de la url a la que se hará petición POST y en la etiqueta section se ponen secciones que se renovarán después de la petición POST. ¡Ojo! La petición tiene que llevar el encabezado HTTP x-requested-with: XMLHttpRequest en la solicitud para que Magento la considere válida.
Después de la petición POST, se hará inmediatamente una petición GET O HEAD por Javascript para renovar localstorage, esta petición es hecha por Javascript y también con el encabezado HTTP x-requested-with: XMLHttpRequest. En el siguiente ejemplo, se renuevan todas las secciones.
https://example.com/customer/section/load/?sections=
messages,
customer,
compare-products,
last-ordered-items,
cart,
directory-data,
captcha,
instant-purchase,
persistent,
review,
wishlist,
recently_viewed_product,
recently_compared_product,
product_data_storage,
paypal-billing-agreement
&force_new_section_timestamp=false&_=1641891224956
Un ejemplo para implementar esta funcionalidad puede ser la integración de algún api de Google o Facebook (Autenticación con la cuenta de Google o Facebook). Después de hacer petición a las apis, nos devuelven una respuesta con nombre y mail del cliente, entonces usando algún callback del Javascript mediante el método JSONP recogemos los datos y los enviamos al servidor para procesarlos. Necesitaremos usar sections.xml, si los datos procesados tienen que estar en el localstorage.
Ejemplo del Product View Counter en la página del producto
Definición de los datos con PHP y los pinta en el phtml
Ir a una página de producto. Abrir el navegador e ir al Storage > Localstorage. Seleccionamos el dominio de la página web. Entonces veremos la propiedad product_data_storage y su valor en formato json.
{
"665": {
"add_to_cart_button": {
...
},
"add_to_compare_button": {
...
},
"price_info": {
"final_price": ...,
"max_price": ...,
"max_regular_price": ...,
"minimal_regular_price": ...,
"minimal_price": ...,
"regular_price": ...,
"formatted_prices": {
...
}
},
"extension_attributes": {
"msrp": {
},
Estos datos están en el código fuente de la página. Son datos del tipo raw (datos pintados por PHP cuando entramos en una página, datos pintados antes de que estén construidos en el DOM y ejecución del Javascript). Si hacemos el CTRL + U veremos lo siguiente en la página.
<script type="text/x-magento-init">
{
"*": {
"Magento_Catalog/js/product/view/provider": {
"data": {"items": ...
}
}
</script>
Este trozo de código es eliminado cuando el DOM es construido y Javascript ejecutado. Entonces se crea un link para enlazar a su fichero de Javascript.
<script type="text/javascript"
charset="utf-8"
async=""
data-requirecontext="_"
data-requiremodule="Magento_Catalog/js/product/view/provider"
src="https://example.com/static/version1660944500/frontend/example/hogar/es_ES/Magento_Catalog/js/product/view/provider.min.js">
</script>
Antes de eliminarlo, los datos pasados por PHP son recogidos y guardados en la memoria. Así, cuando su fichero de Javascript es enlazado en el DOM, se ejecuta su código Javascript usando sus datos guardados previamente en el localstorage.
# Ruta del fichero phtml del trozo de código: app/code/Magento/Catalog/view/frontend/templates/product/view/counter.phtml
/**
* Product viewed counter template
*
* @var $block \Magento\Catalog\Block\Ui\ProductViewCounter
*/
<script type="text/x-magento-init">
{
"*": {
"Magento_Catalog/js/product/view/provider": {
"data": = /* @noEscape */ $block->getCurrentProductData() ?>
}
}
}
</script>
El fichero counter.phtml está en el layout catalog_product_view.xml, que es el layout de la página del producto.
# Ruta del layout: app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
<referenceContainer name="content">
<block
class="Magento\Catalog\Block\Ui\ProductViewCounter"
name="product_viewed_counter"
template="Magento_Catalog::product/view/counter.phtml"/>
</referenceContainer>
# Ruta del Controller: app/code/Magento/Catalog/Controller/Product/View.php
# Devuelve el layout
/**
* Product view action
*
* @return Forward|Redirect
*/
public function execute()
{
...
// Render page
try {
$this->applyCustomDesign($productId);
$page = $this->resultPageFactory->create();
$this->viewHelper->prepareAndRender($page, $productId, $this, $params);
return $page;
...
Para actualizar datos de la sección product_data_storage, una de las maneras es hacer petición mediante ajax del tipo POST
https://example.com/customer/section/load/?sections=
product_data_storage
&force_new_section_timestamp=false&_=1641891224956
Referencias
- Magento Web Oficial: Cómo añadir una nueva sección nuestra a Magento
- Magento Web Oficial: Lista de cookies
- Magento Web Oficial: Contenido Privado
- Mozilla: Cookies
- Google: Cómo ver Cookies
- StackExchange: Uso del Form Key
- Magento Web Oficial: Localizar el fichero js