Skip to main content

Blog

Inspired by (OK, word-for-word stealing from) a bag of pretzels, with the full connivance if not outright help from co-founder Ben, Dan Hakimzadeh crafted a surprisingly not-entirely-fictional account of Agaric's origin, which graced our About page from around 2006 through 2012:

The Story on Agaric

I've always had a passion for good design and healthy coding, even back in the days of owning a web site cart in downtown Natick. Back then, my partner and I made all natural HTML roll-up web sites and, as an incentive for customers to wait in line, we baked Drupal into different flavored designs. The Drupal became remarkably popular and before we knew it, the Agaric Design Collective was born.

Today, you can enjoy Agaric Design sites in six great flavors. They are baked, all natural and totally delicious. So treat yourself well, and treat yourself often

Visit http://www.agaricdesign.com to find more about our other sites, discover great recipes, and stay in touch.

Dan Hakimzadeh
Co-Founder

Sign up to be notified when Agaric gives a migration training:

An original co-founder of Agaric, Dan spends his time and energy building on this mystical phenomenon popularly called the Internet. He believes in the principles of free open source software and develops primarily using the Drupal content management framework.

Find his latest at dhakimzadeh.com.

Valoramos aprender cosas nuevas y compartir nuestros conocimientos, por lo que nos tomamos el tiempo cada semana para compartir lo que hemos descubierto o descubierto. Nos damos cuenta de que esto puede ser de interés para personas ajenas al Agaric, especialmente para aquellas personas que trabajan solas o están en organizaciones que no fomentan el intercambio de habilidades. Por lo tanto, estamos invitando a socios, estudiantes, colegas, y usted, a participar en la observación o presentación de presentaciones cortas.

También discutimos nuestros flujos de trabajo y modelos de negocio como cooperativas. Esta cita es de nuestros amigos en Argentina - Fiqus.coop:

"El propósito de ponerse en contacto con otras cooperativas en el mundo no es solo una, y se podría decir que son varias al mismo tiempo y con la misma importancia.

En primer lugar, creemos que la mejor manera de fortalecer el movimiento cooperativo es conectarse, compartir experiencias, información ... en otras palabras, cooperar entre sí. Esa es la esencia de la forma organizativa que adoptamos para nuestras empresas ".

Suscríbase a la lista de correo para recibir invitaciones al chat y comparta este enlace con un amigo: Mostrar y Contar.

 

 

Impedit veniam consectetur dolores id provident. Voluptas non voluptates rerum. Aut et laudantium nisi quia pariatur vero nemo.

Enim aperiam dolor numquam saepe perferendis fugit nam veniam. Impedit rerum repellendus voluptatem voluptatem fugit consequatur. Omnis illum quaerat vel voluptatem error praesentium.

The entity_generate process plugin receives a value and checks if there is an entity with that name. If the term exists then it uses it and if it does not then creates it (which is precisely what I need).

So, here is a snippet of the article migration YAML file using the entity_generate plugin:

id: blog
migration_group: Drupal
label: Blog
source:
  plugin: d7_node
  node_type: blog
destination:
  plugin: entity:node
process:
  status: status
  created: created
  field_tags:
    plugin: sub_process
    source: field_tags
    process:
      target_id:
      - plugin: entity_generate
        source: name
        value_key: name
        bundle_key: vid
        bundle: tags
        entity_type: taxonomy_term
        ignore_case: true
        …

In our field_tags field we are using the Drupal 7  field_tags Values We are going to read the entities and pass that value into the entity_generate plugin to create the entities. In this example, there is a problem,  the d7_node migrate plugin (included in the migrate module) provides the taxonomy terms IDs and this will make the entity_generate plugin to create some taxonomy terms using the IDs as the term names, and this is not what we want.

So what I need to do is to get from somewhere the terms names, not their ids, to do that I need to add an extra source property.

First, we need to create a new custom module and in there create a source plugin which extends the Node process plugin, something like this (let's say that our custom module’s name is my_migration):

Create the file:

my_migration/src/Plugin/migrate/source/MyNode.php

And the file should contain this code:

namespace Drupal\my_migration\Plugin\migrate\source;

use Drupal\migrate\Row;
use Drupal\node\Plugin\migrate\source\d7\Node;

/**
 * Adds a source property with the taxonomy term names.
 *
 * @MigrateSource(
 *   id = “my_node",
 *   source_module = "node"
 * )
 */
class MyNode extends Node {

  public function prepareRow(Row $row) {
    $nid = $row->getSourceProperty('nid');
    // Get the taxonomy tags names.
    $tags = $this->getFieldValues('node', 'field_tags', $nid);
    $names = [];
    foreach ($tags as $tag) {
      $tids[] = $tag['tid'];
    }
    if (!$tids) {
      $names = [];
    }
    else {
      $query = $this->select('taxonomy_term_data', 't');
      $query->condition('tid', $tids, 'IN');
      $query->addField('t', 'name');
      $result = $query->execute()->fetchCol();
      $names[] = ['name' => $result['name']];
      foreach ($result as $term_name) {
        $names[] = ['name' => $term_name];
      }
    }
    $row->setSourceProperty('field_tags_names', $names);
    return parent::prepareRow($row);
  }
}

It does the following things:

  • It reads the nid of the article
  • Gets all the terms IDs of the field_tags field
  • For each ID, it gets the name of the term and put it in the `names` array
  • Finally, it sets this value inside the $row using the `setsourceProperty` method.

Now our rows will have a property called fields_tags_names with the terms names, and we can pass this data to the entity_generate plugin.

We need to make a few adjustments in our initial migration file,  first and most important update the  source plugin to use our new source plugin:

source:
  plugin: my_node
  …

And update the source in the field_tags field to use the new  field_tags_names source property.

  …
  field_tags:
    plugin: sub_process
    source: field_tags_names
  ….

The final migration file looks like this:

id: blog
migration_group: Drupal
label: Blog
source:
  plugin: my_node
  node_type: blog
destination:
  plugin: entity:node
process:
  status: status
  created: created
  field_tags:
    plugin: sub_process
    source: field_tags_names
    process:
      target_id:
      - plugin: entity_generate
        source: name
        value_key: name
        bundle_key: vid
        bundle: tags
        entity_type: taxonomy_term
        ignore_case: true
        …

And that’s it; if we run the migration, it will create on the fly the terms if they do not exist and use them if they do exist.

A mobile version of Vulk website's home page.

Respecting your privacy and being responsible with the data we collect from you is of the utmost importance to us.  We will not use or share your information with anyone except as described in this privacy policy.

Information collection and use

If you choose to leave a comment or a private message through our contact form, we may require you to provide us with certain personally identifiable information, including your name and email address. The information that we collect will be used to contact or identify you.

Log data

We want to inform you that whenever you visit our Service, we collect information that your browser sends to us that is called Log Data. This Log Data may include information such as your computer's Internet Protocol (“IP”) address, browser version, pages of our Service that you visit, the time and date of your visit, the time spent on those pages, and other statistics.

Cookies

We do not use cookies for visitors to our site. (Cookies are files with small amount of data that is commonly used as an anonymous unique identifier.)

Service providers

We employ a third-party company, Google, to assist us in analyzing how our website is used. Only anonymized data is collected.

Hotjar assists its us in providing our end users with a better experience and service as well as assist us in diagnosing technical problems and analyzing user trends. Most importantly, through Hotjar’s services, the functionality of the site can be improved, making them more user-friendly, more valuable, and simpler to use for the end users.

You may opt-out from having Hotjar collect your information when visiting a Hotjar Enabled Site at any time by visiting our Opt-out page and clicking ‘Disable Hotjar’ or enabling Do Not Track (DNT) in your browser.

Changes to this privacy policy

We may update our Privacy Policy from time to time. Thus, we advise you to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately, after they are posted on this page.

Contact us

If you have any questions or suggestions about our privacy policy, do not hesitate to contact us.

Have you ever been asked to log into a website while you are viewing a page? And after doing so you get redirected to some page other than the one you were reading? This is an obvious and rather common usability problem. When this happens people lose track of what they were doing and some might not even bother to go back. Let's find out how to solve this in Drupal 8.

In a recent project a client wisely requested exactly that: whenever a user logs into the site, redirect them to the page they were before clicking the login link. This seemed like a very common request so we looked for a contrib module that provided the functionality. Login Destination used to do it in Drupal 7. Sadly the Drupal 8 version of this module does not provide the functionality yet.

Other modules, and some combinations of them, were tested without success. Therefore, we built Login Return Page. It a very small module that just does one thing and it does it well: it appends destination=/current/page to all the links pointing to /user/login effectively redirecting users to the page they were viewing before login. The project is waiting to be approved before promoting it to full project.

Have you had a similar need? Are there other things you are requested to do after login? Please share them in the comments.

UPDATE: It seems to this is a regression from Drupal 7 and there is an issue that would fix it. Thanks to Wim Leers for letting me know about it.

 We look forward to being in communication, perchance to work together or just to meet in person sometime!

Sign up to be notified when Agaric gives a migration training:

Here is how to deal with the surprising-to-impossible-seeming error "Unable to uninstall the MySQL module because: The module 'MySQL' is providing the database driver 'mysql'.."

Like, why is it trying to uninstall anything when you are installing? Well, it is because you are installing with existing configuration— and your configuration is out-of-date. This same problem will happen on configuration import on a Drupal website, too. (See update below for those steps!)

Really this error message is a strong reminder to always run database updates and then commit any resulting configuration changes after updating Drupal core or module code.

And so the solution is to roll back the code to Drupal 9.3, do your installation from configuration, and then run the database updates, export configuration, and commit the result.

For example:

git checkout <commit-hash-of-earlier-composer-lock>
composer install
drush -y site:install drutopia --existing-config
git checkout main
composer install
drush -y updb
drush -y cex
git status # Review what is here; git add -p can also help
git add config/
git commit -m "Apply configuration updates from Drupal 9.4 upgrade"

The system update enable_provider_database_driver is the post-update hook that is doing the work here to "Enable the modules that are providing the listed database drivers." Pretty cool feature and a strong reminder to always, always run database updates and commit any configuration changes immediately after any code updates!

Update: Steps on for resolving the unable to uninstall MySQL module error on configuration import

This is what you probably already did, before the drush -y cim failed (luckily, luckily it failed).

composer update
drush -y updb

All that is great! Now continue, not with a config import, but with a config export:

drush -y cex
git status # Review what is here; git add -p can also help
git add config/
git commit -m "Apply configuration updates from Drupal 9.4 upgrade"

Remember, after every composer update and database update, you need to do a configuration export and commit the results— database updates can change configuration, and if you do not commit those, you will undo these intentional and potentially important changes on a configuration import. If you ran into this problem on a configuration import, it is a sign of breakdown in discipline in following these steps!

Every time you bring in code changes with composer update all this must be part and parcel:

composer update
drush -y updb
drush -y cex
git status # Review what is here; git add -p can also help
git add config/
git commit -m "Apply configuration from database updates"

We received the go-ahead from Studio Daniel Libeskind to take their web site live a few weeks ago, but it was presenting here at Pacific Northwest Drupal Summit that we realized we should mention it to the world.

The architect partners and their one-woman public relations powerhouse are fantastic, as was the project's driving force and designer, Todd Linkner.  We'll be sharing much more about this project, but in the meantime, enjoy this bold site:

http://daniel-libeskind.com

Drupal 8 has a great AJAX Form API which includes some tools to create modal dialogs using the jQuery modal library. The Examples module even demonstrates how to create a custom form and display it in a modal window. But what if what you want to do is display an already created form in a modal? How do we do that? Let's see how to do it with an example. Let's display the node add form in a modal window.

The first thing that we need to do is create a link which will trigger the modal when the user clicks it. The only special things that this link needs to have are a few attributes that will let Drupal know to display the contents of the link in a dialog:

 
<a href="/node/add/article"
  class="use-ajax"
  data-dialog-type="modal"
  data-dialog-options="{'width':800,'height':500}">
    Create Node
</a>
 

Drupal also needs to include the JavaScript libraries which will read these attributes and make them work, so let's add the following libraries to your module's dependencies (in your equivalent to this example's modal_form_example.libraries.yml file).

  
  dependencies:
     'core/drupal.dialog.ajax',
     'core/jquery.form',
  

If you are unsure about how to add libraries on Drupal 8 you can consult the documentation to either add it in a theme or add it in a custom module. At the end of the post I will provide a repository with the code where I added the libraries in a block.

And that's it! If you click the link, the form will be displayed in a modal dialog! Drupal will automatically detect that you are sending an AJAX request and will display just the form so you won't need to worry about removing the rest of the blocks or hiding undesired markup.

The last thing missing, is what will happen if the user creates a node? By default, the node will redirect the user to another page but if we want to just close the modal dialog and leave the user on the same page we need to tell the form to do that. For this we are going to alter the form and add an AJAX command letting Drupal know that we want to close the dialog as soon as the node is created. In the .module file of a custom module we will add this code:

  
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\RedirectCommand;

/**
 * Implements hook_form_alter().
 */
function modal_form_example_form_node_article_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['actions']['submit']['#submit'][] = '_modal_form_example_ajax_submit';
  $form['actions']['submit']['#attributes']['class'][] = 'use-ajax-submit';
}

/**
 * Close the Modal and redirect the user to the homepage.
 *
 * @param array $form
 *   The form that will be altered.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   FormState Object.
 */
function _modal_form_example_ajax_submit(array $form, FormStateInterface &$form_state) {
  $response = new AjaxResponse();
  $response->addCommand(new CloseModalDialogCommand());
  $form_state->setResponse($response);
}
 

The first function adds an extra submit function (which will be executed after Drupal finishes processing the node) and the second function adds the command to close the Dialog when the node has been created.

We can do this with practically any form in Drupal and you can add extra commands to do more complex things. Here are two resources:

Flock of birds flying.