module – How to handle dynamic data in a script tag in head section for every page

I am absolutely new to Magento 2 (1 week in). I am trying to develop a Magento module that lets the admin specify a string (token) and when the admin saves the module I would like the token to inserted together with a tag into the section of each page.

If the admin changes the token and saves the config, it would be nice if it can update the same tag. Or even remove it if no token is specified.

The module UI is no problem and also the saving works fine and intercepting the token value (with PHP), but I got stuck on how exactly to control the that gets inserted.

I experimented with view/frontend/layout/default.xml and can influence the header, but this seems to be very static.

<?xml version="1.0" ?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <script src="https://some-external-website.com/external-script.js" 
                data-token="token_value" 
                src_type="url"></script>
    </head>
</page>

So basically I would like to change the value in data-token (“token_value”) when the admin saves the config from the module, which I do from a PluginConfig file:

    ...
    public function aroundSave(MagentoConfigModelConfig $subject, callable $proceed) {
        // your custom logic
        $section = $subject->getSection();
        $returnValue = $proceed();
        $newConfigs = $this->scopeConfig->getValue($section);
        $token = $newConfigs("general")("token_value");

        // +++ here would like to write value of $token to the <script> tag +++
        
        return $returnValue;
    }
    ...

Any help appreciated!

magento2 – How to create my custom visual swatch color attribute in my own module Vendor/Module/Setup/Patch/Data/MyOwnColorAttribute?

I take from https://github.com/magento/magento2/blob/2.3/dev/tests/integration/testsuite/Magento/Swatches/_files/product_visual_swatch_attribute.php like example, but my own color attribute patch didn’t create any options if I add those parameters. This is my code:

<?php 
namespace VendorModuleSetupPatchData;

use MagentoCatalogModelProduct;
use MagentoEavModelEntityAttributeScopedAttributeInterface;
use MagentoEavModelEntityAttributeSourceTable;
use MagentoEavSetupEavSetupFactory;
use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupPatchDataPatchInterface;
use VendorModuleModelAttributeBackendColor as Backend;
use VendorModuleModelAttributeFrontendColor as Frontend;

class AddColorAttribute implements DataPatchInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;

    /**
     * @var EavSetupFactory
     */
    private $eavSetupFactory;

    /**
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $eavSetupFactory,
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * @inheritdoc
     */
    public function apply()
    {
        $this->moduleDataSetup->startSetup();
        $eavSetup = $this->eavSetupFactory->create();
        $eavSetup->addAttribute(Product::ENTITY, 'visual_swatch_color_attribute', (
            'type' => 'int',
            'label' => 'Visual Swatch Color Attribute',
            'input' => 'select',
            'frontend' => Frontend::class,
            'backend' => Backend::class,
            'source' => Table::class,
            'required' => false,
            'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
            'visible' => true,
            'is_used_in_grid' => true,
            'is_visible_in_grid' => true,
            'is_filterable_in_grid' => true,
            'user_defined' => true,
            'searchable' => true,
            'filterable' => true,
            'comparable' => true,
            'visible_on_front' => true,
            'used_in_product_listing' => true,
            'is_html_alowed_on_front' => true,
            'unique' => false,
            'swatch_input_type' => 'visual',
            'swatchvisual' => (
                'value' => (
                    'Obsidian' => '#3a322d',
                    'Pure' => '#0000ff',
                    'Crimson' => '#dc143c',
                    'Emerald' => '#50c878',
                    'Ametyst' => '#9966cc',
                ),
            ),
            'optionvisual' => (
                'values' => (
                    'Obsidian' => ('Obsidian'),
                    'Pure' => ('Pure'),
                    'Crimson' => ('Crimson'),
                    'Emerald' => ('Emerald'),
                    'Ametyst' => ('Ametyst'),
                ),
            ),
            'default' => '1'
        ));

        $eavSetup->addAttributeToGroup(
            MagentoCatalogModelProduct::ENTITY,
            'Default',
            'Product Details',
            'visual_swatch_color_attribute',
            18
        );
        $this->moduleDataSetup->endSetup();
    }

    /**
     * @inheritdoc
     */
    public static function getDependencies(): array
    {
        return ();
    }

    /**
     * @inheritdoc
     */
    public function getAliases(): array
    {
        return ();
    }
}

CDN module: wrong settings broke my site

I installed the cdn module from:

https://www.drupal.org/project/cdn

and in the UI i setted a wrong cdn path.

now my site is broken it can load css and js. end i cannot disable the module from the UI.

i have admin access at the server but i cant figure out how to disable cdn, there is a cdn,settings.yml but it seems that the option isnt there.

i cant find any documentation for the module… can you please help me?

magento2.3 – Composer can’t install any module due to “Your requirements could not be resolved to an installable set of packages”

Running 2.3.6
When I try to install any module via composer I get the following error:

 ()$ COMPOSER_MEMORY_LIMIT=-1 composer require stripe/stripe-php:^7
Warning from https://repo.packagist.org: You are using an outdated version of Composer. Composer 2 is now available and you should upgrade. See https://getcomposer.org/2
./composer.json has been updated
Loading composer repositories with package information
Warning from https://repo.packagist.org: You are using an outdated version of Composer. Composer 2 is now available and you should upgrade. See https://getcomposer.org/2
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Conclusion: remove magento/product-community-edition 2.3.6
    - Conclusion: don't install magento/product-community-edition 2.3.6
    - Installation request for magento/product-community-edition 2.3.6 -> satisfiable by magento/product-community-edition(2.3.6).
    - Installation request for veriteworks/cookiefix ^3.0 -> satisfiable by veriteworks/cookiefix(3.0.0).
    - Conclusion: don't install magento/framework 102.0.6-p1
    - magento/product-community-edition 2.3.6 requires laminas/laminas-code ~3.3.0 -> satisfiable by laminas/laminas-code(3.3.2, 3.3.0, 3.3.1).
    - Can only install one of: laminas/laminas-code(3.4.1, 3.3.0).
    - Can only install one of: laminas/laminas-code(3.4.1, 3.3.1).
    - Can only install one of: laminas/laminas-code(3.4.1, 3.3.2).
    - Can only install one of: laminas/laminas-code(3.4.1, 3.3.2).
    - Can only install one of: laminas/laminas-code(3.4.1, 3.3.2).
    - Conclusion: install magento/framework 102.0.6-p1|install laminas/laminas-code 3.4.1


Installation failed, reverting ./composer.json to its original content.

What is composer telling me to do?

Is it possible i made a mess since few days ago (before that I think
everything was working fine) and then I launched “composer
dump-autoload -o” for some reason?

Edit:
i ran same command and got different error

     composer require stripe/stripe-php:^7
The "magento/magento-composer-installer" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "dealerdirect/phpcodesniffer-composer-installer" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "magento/inventory-composer-installer" plugin was skipped because it requires a Plugin API version ("^1.1") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "laminas/laminas-dependency-plugin" plugin was skipped because it requires a Plugin API version ("^1.1") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "magento/composer-root-update-plugin" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
./composer.json has been updated
The "magento/magento-composer-installer" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "dealerdirect/phpcodesniffer-composer-installer" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "magento/inventory-composer-installer" plugin was skipped because it requires a Plugin API version ("^1.1") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "laminas/laminas-dependency-plugin" plugin was skipped because it requires a Plugin API version ("^1.1") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
The "magento/composer-root-update-plugin" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.
Running composer update stripe/stripe-php
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - magento/composer-root-update-plugin is locked to version 1.0.0 and an update of this package was not requested.
    - magento/composer-root-update-plugin 1.0.0 requires composer-plugin-api ^1.0 -> found composer-plugin-api(2.0.0) but it does not match the constraint.
  Problem 2
    - Root composer.json requires veriteworks/cookiefix ^3.0 -> satisfiable by veriteworks/cookiefix(3.0.0).
    - veriteworks/cookiefix 3.0.0 requires magento/framework ~102.0.6-p1||~103.0.1 -> found magento/framework(102.0.6-p1, 103.0.1, 103.0.1-p1, 103.0.2) but the package is fixed to 102.0.6 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
  Problem 3
    - dealerdirect/phpcodesniffer-composer-installer is locked to version v0.5.0 and an update of this package was not requested.
    - dealerdirect/phpcodesniffer-composer-installer v0.5.0 requires composer-plugin-api ^1.0 -> found composer-plugin-api(2.0.0) but it does not match the constraint.
  Problem 4
    - laminas/laminas-dependency-plugin 1.0.4 requires composer-plugin-api ^1.1 -> found composer-plugin-api(2.0.0) but it does not match the constraint.
    - magento/product-community-edition 2.3.6 requires laminas/laminas-dependency-plugin ^1.0 -> satisfiable by laminas/laminas-dependency-plugin(1.0.4).
    - magento/product-community-edition is locked to version 2.3.6 and an update of this package was not requested.

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

You are using Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report a plugin-issue to ask them to support Composer 2.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

8 – Is it possible to use only one module for multiple Site Studio (Cohesion) elements?

I’m creating custom elements to use within Acquia Site Studio/Cohesion (following this), but one majorly inconvenient thing is that you have to create a whole new module for each element. I’m trying to integrate an entire preexisting design system with several components, so registering and enabling modules for each of them is a bit of a pain.

I noticed that all of Site Studio’s stock elements use only one module, so it gave me the idea to do the same. However, those elements aren’t like custom ones, in the sense that they’re retrieved from an API and the markup is generated at runtime. So I can’t exactly just follow the same process.

So far what I’ve tried is creating a single “Components Package” module, then defining multiple classes for each element inside the src/Plugin/CustomElement/ComponentPackage.php file. But the class has to match the file name, so that doesn’t work.

I’ve read through all of Acquia’s documentation and there’s nothing that addresses this, so I fear it may not be possible. But their documentation lacks in several areas, so maybe it is. Any help would be much appreciated.

higher algebra – Is the rank of free module spectra unique?

$pi_0: Spto Ab$ is a direct sum preserving functor, and it sends $E_1$-ring spectra to rings, and modules over them to modules over them.

In particular you get a functor $pi_0: Mod_Rto Mod_{pi_0(R)}$. If $R^nsimeq R^m$ as $R$-modules, then $pi_0(R)^ncong pi_0(R)^m$ as $pi_0(R)$-modules. So if $pi_0(R)$ is commutative and nonzero (which is a much weaker hypothesis than $R$ having an $E_infty$-structure), this implies $n=m$.

More generally, it suffices that $pi_0(R)$ have the invariant basis property.

Note that conversely, if $pi_0(R)$ does not have the invariant basis property, we can find inverse nonsquare matrices $M,N$ with coefficients in $pi_0(R)$, and you can view them as elements of $pi_0map_R(R^n,R^m)$ ($pi_0map_R(R^m,R^n)$ respectively), and their matrix product corresponds to the composition up to homotopy, so that $R^nsimeq R^m$ as $R$-modules.

So it’s an “if and only if” situation with $pi_0(R)$.

A related claim is the fact that group-completion $K$-theory only sees $pi_0$, namely if $R$ is a ring spectrum, then the group-completion $K$-theory of projective $R$-modules (summands of $R^n$ for some finite $n$, no shifts) is the same as that of $tau_{geq 0}R$, which is the same as that of $pi_0(R)$.

nodes – Implementing hidden content parts (as in old “Hidden Content” module)

There is (long unsupported) “Hidden Content” module, allowing to insert content blocks visible by certain roles only, i.e. like below:

(hidden role="Role Name")
   ...content visible to "Role Name" role only
(/hidden)

I browsed through related modules (from “Content Access Control” etc), but see no good match for this module’s capabilities. Are there any simple means to achieve the above without either re-implementing the module for Drupal 9 or using inline PHP?

“Paragraphs Access Control” looks somewhat suitable, but it requires creating quite a complex structure only to restrict access to text blocks.

8 – How to generate files with a custom module?

I have a site with Drupal 8. I have created a custom module. Here is its code :

https://github.com/S1BIOSE/generator_website

generator-website-page.html.twig :

<div class="card mb-5 overflow-hidden shadow rounded bg-white">
  <div class="card-body">
   
    <form>

      <legend>Générateur de site web</legend>
      <div class="mb-3">
        <label for="TokenUrl" class="form-label">L'URL de votre site web</label>
        <input type="text" class="form-control is-invalid" id="TokenUrl" required>
        <div class="invalid-feedback">
          Ce champ est requis.
        </div>
        <small id="helpUrl" class="form-text">Entrez l'URL complète de votre site web.</small>
      </div>
      <div class="mb-3">
        <label for="TokenTitle" class="form-label">Nom de l'entreprise</label>
        <input type="text" class="form-control is-invalid" id="TokenTitle" required>
        <div class="invalid-feedback">
          Ce champ est requis.
        </div>
        <small id="helpTitle" class="form-text">Entrez le nom de votre entreprise.</small>
      </div>
      <div class="mb-3">
        <label for="TokenDescription" class="form-label">Présentation de l'entreprise</label>
        <textarea class="form-control is-invalid" id="TokenDescription" rows="5" required></textarea>
        <div class="invalid-feedback">
          Ce champ est requis.
        </div>
        <small id="helpDescription" class="form-text">Entrez une description de votre entreprise.</small>
      </div>

      <div class="mb-3">
        <label for="TokenFeed" class="form-label">Fil d'actualité</label>
        <input type="text" class="form-control" id="TokenFeed">
        <small id="helpFeed" class="form-text">Entrez l'url de votre Flux RSS sur la plateforme S1BIOSE.</small>
      </div>

      <button type="submit" class="btn btn-primary">Générer</button>
    </form>

  </div>
</div>

What should I put in my module to generate the 3 files above and replace the words starting with Token ?

In this custom module, I created a form with IDs (I’m not sure if this is the right way to go). For example, the data entered in the TokenTitle field must replace TokenTitle wherever it appears in the files.

When a user submits the form, it must download the 3 files with the correct data (the one entered in the form). If possible in a ZIP archive.

It is unnecessary to keep the information submitted in the form in the database.

manifest.json

{
  "orientation":"portrait",
  "short_name": "TokenTitle",
  "name": "TokenTitle",
  "display": "standalone",
  "background_color": "#000000",
  "theme_color": "#000000",
  "description": "TokenDescription",
  "lang": "fr",
  "icons": ({
        "src": "icon-144.png",
        "sizes": "144x144",
        "type": "image/png",
        "purpose": "any maskable"
      }, {
        "src": "icon-192.png",
        "sizes": "192x192",
        "type": "image/png",
        "purpose": "any maskable"
      }, {
        "src": "icon-512.png",
        "sizes": "512x512",
        "type": "image/png",
        "purpose": "any maskable"
      }),
  "start_url": "/?source=pwa",
  "scope": "/"
}

sitemap.xml

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>TokenUrl/index.html</loc>
<lastmod>TokenDate</lastmod>
</url>
</urlset>

sw.js

const staticCacheName = 'TokenTimestamp';
const filesToCache = (
  '/',
  '/index.html',
  '/CHANGELOG.md',
  '/bootstrap.min.css',
  '/style.css',
  '/bootstrap.bundle.min.js',
  '/popover.js',
  '/clipboard.min.js',
  '/btn-clipboard.js',
  '/pwa.js',
  '/feed.js',
  '/toasts.js',
  '/icon-32.png',
  '/icon-144.png',
  '/icon-192.png',
  '/icon-512.png',
  '/iphone5_splash.png',
  '/iphone6_splash.png',
  '/iphoneplus_splash.png',
  '/iphonex_splash.png',
  '/iphonexr_splash.png',
  '/iphonexsmax_splash.png',
  '/ipad_splash.png',
  '/ipadpro1_splash.png',
  '/ipadpro3_splash.png',
  '/ipadpro2_splash.png'
);

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(staticCacheName).then(cache => {
      return cache.addAll(filesToCache);
    })
  );
});

self.addEventListener('activate', event => {
  event.waitUntil(caches.keys().then(function(cacheNames) {
    return Promise.all(
      cacheNames.filter(function(staticCacheName) {
      }).map(function(staticCacheName) {
        return caches.delete(staticCacheName);
      })
    );
  }));
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
      if (cachedResponse) {
        return cachedResponse;
      }
      return fetch(event.request);
    })
  );
});

self.addEventListener('message', event => {
  if (event.data.action === 'skipWaiting') {
    self.skipWaiting();
  }
});

ERROR IN in my SPFX WebPart : Module parse failed: Unexpected token You may need an additional loader to handle the result of these loaders

I have created an SPFx project with reactJS. I am using .jsx extension – functional components.

Now, the spfx webpart is already working fine, but I saw a material kit that I want to reuse its components.

When I referenced the components, I am presented with this error

(SPLoaderError.loadComponentError):
***Failed to load component (WebPart). Original error: ***Failed to load entry point from component WebPart). Original error: Module parse failed: Unexpected token (30:4)
File was processed with these loaders:
./node_modules/source-map-loader/index.js
You may need an additional loader to handle the result of these loaders.

enter image description here

It seems that I cannot use the “footer” tag?

enter image description here

8 – Token replacement in webform custom element (webform_score module)

I use the module webform_score for my project but the webform element RadiosQuiz doesn’t handle the tokens replacement.

enter image description here

I’d like to use tokens in title and options text. I look on the RadioQuiz.php but I don’t know how I can do this. Here is the code of the RadiosQuiz.php.

<?php

namespace Drupalwebform_scorePluginWebformElement;

use DrupalCoreConfigConfigFactoryInterface;
use DrupalCoreEntityEntityTypeManagerInterface;
use DrupalCoreRenderElementInfoManagerInterface;
use DrupalCoreSessionAccountInterface;
use DrupalCoreTypedDataTypedDataManagerInterface;
use DrupalwebformPluginWebformElementRadios;
use DrupalwebformPluginWebformElementManagerInterface;
use DrupalwebformWebformLibrariesManagerInterface;
use DrupalwebformWebformSubmissionInterface;
use DrupalwebformWebformTokenManagerInterface;
use Drupalwebform_scorePluginWebformScoreManagerInterface;
use Drupalwebform_scoreQuizInterface;
use PsrLogLoggerInterface;
use SymfonyComponentDependencyInjectionContainerInterface;

/**
 * Provides a 'radios' quiz element.
 *
 * @WebformElement(
 *   id = "webform_score_radios",
 *   label = @Translation("Radios"),
 *   description = @Translation("Provides a form element for a set of radio buttons."),
 *   category = @Translation("Quiz"),
 * )
 */
class RadiosQuiz extends Radios implements QuizInterface {

  use QuizTrait;

  /**
   * RadiosQuiz constructor.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param PsrLogLoggerInterface $logger
   *   A logger instance.
   * @param DrupalCoreConfigConfigFactoryInterface $config_factory
   *   The configuration factory.
   * @param DrupalCoreSessionAccountInterface $current_user
   *   The current user.
   * @param DrupalCoreEntityEntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param DrupalCoreRenderElementInfoManagerInterface $element_info
   *   The element info manager.
   * @param DrupalCoreTypedDataTypedDataManagerInterface $typed_data_manager
   *   Typed data manager.
   * @param DrupalwebformPluginWebformElementManagerInterface $element_manager
   *   The webform element manager.
   * @param DrupalwebformWebformTokenManagerInterface $token_manager
   *   The webform token manager.
   * @param DrupalwebformWebformLibrariesManagerInterface $libraries_manager
   *   The webform libraries manager.
   * @param Drupalwebform_scorePluginWebformScoreManagerInterface $webform_score_manager
   *   Webform score plugin manager.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger, ConfigFactoryInterface $config_factory, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, ElementInfoManagerInterface $element_info, TypedDataManagerInterface $typed_data_manager, WebformElementManagerInterface $element_manager, WebformTokenManagerInterface $token_manager, WebformLibrariesManagerInterface $libraries_manager, WebformScoreManagerInterface $webform_score_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $logger, $config_factory, $current_user, $entity_type_manager, $element_info, $element_manager, $token_manager, $libraries_manager);

    $this->typedDataManager = $typed_data_manager;
    $this->webformScoreManager = $webform_score_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('logger.factory')->get('webform'),
      $container->get('config.factory'),
      $container->get('current_user'),
      $container->get('entity_type.manager'),
      $container->get('plugin.manager.element_info'),
      $container->get('typed_data_manager'),
      $container->get('plugin.manager.webform.element'),
      $container->get('webform.token_manager'),
      $container->get('webform.libraries_manager'),
      $container->get('plugin.manager.webform_score')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getAnswerDataTypeId() {
    return 'string';
  }

  /**
   * {@inheritdoc}
   */
  protected function getAnswer($element, WebformSubmissionInterface $webform_submission) {
    $answer = $webform_submission->getElementData($element('#webform_key'));
    dd($answer);
    if (isset($element('#options')($answer))) {
      $answer = $element('#options')($answer);
    }
    return $this->typedDataManager->create($this->typedDataManager->createDataDefinition($this->getAnswerDataTypeId()), $answer);
  }

}

Thanks in advance for anyone who can help me.