Timeline

Send me a webmention with Drupal!

After months of reading, experimenting and a lot of coding, I'm happy that the first release candidate of the Drupal IndieWeb module is out. I guess this makes the perfect time to try it out for yourself, no? There are a lot of concepts within the IndieWeb universe, and many are supported by the module. In fact, there are 8 submodules, so it might be daunting to start figuring out which ones to enable and what they exactly allow you to do. To kick start anyone interested, I'll explain in a few steps how you can send a webmention to this page. Can you mention me?

Step 1: enabling modules

After you downloaded the module and installed the required composer packages, enable following modules: IndieWeb, Webmention and Microformats2. In case you are not authenticated as user 1, also toggle the following permissions: 'Administer IndieWeb configuration' and 'Send webmention'.

Step 2: expose author information

To discover the author of a website after receiving a webmention, your homepage, or the canonical url of a post needs author information. The module comes with an Author block so you can quickly expose a block where you can configure your name. Your real name or nickname is fine, as long as there's something. The minimal markup should look like something like this:

<p class="h-card">Your <a class="u-url p-name" rel="me" href="https://example.com">name</a></p>

Note: this can be anywhere in your HTML, even hidden.

Step 3: configure webmention module

All configuration exposed by the modules lives under 'Web services' > 'IndieWeb' at /admin/config/services/indieweb. To configure sending webmentions go to /admin/config/services/indieweb/webmention/send. Ignore the ' Syndication targets' fieldset and scroll down to ' Custom URL's for content' and toggle the 'Expose textfield' checkbox.

Scroll down a bit more and configure how you want to send webmentions, either by cron or drush (webmentions are stored in a queue first for performance reasons)

Step 4: configure Microformats module

When sending a webmention to me, it would be nice to be able to figure out what exactly your post is. To achieve this, we need to add markup to the HTML by using CSS classes. Let's configure the minimal markup at /admin/config/services/indieweb/microformats by toggling following checkboxes:

  • h-entry on node wrappers
  • e-content on standard body fields. In case your node type does not use the standard body field, enter the field name in the 'e-content on other textarea fields' textarea.
  • dt-published, p-name, u-author and u-url in a hidden span element on nodes.

Now create a post!

Create a post with a title and body. Your body needs to contain a link with a class so that when I receive your webmention, I know that this page is valid. As an example, we're going to write a reply:

Hi swentel! I just read your <a href="https://realize.be/blog/send-me-webmention-drupal" class="u-in-reply-to">article</a> and it's awesome!

Save the post and verify the markup more or less looks like underneath. Make sure you see following classes: h-entry, u-url, p-name, dt-published, e-content, u-author.

<article role="article" class="h-entry node node--type-article node--promoted node--unpublished node--view-mode-full clearfix">
  <header>
     <div class="node__meta">
        <span>
          Published on <span class=" field--label-hidden">Tue, 04/12/2018 - 22:39</span>
        </span>
        <span class="hidden">
          <a href="https://example.com/canonical-url" class="u-url">
            <span class="p-name">Test send!</span>
            <span class="dt-published">2018-12-04T22:39:57+01:00</span>
          </a>
          <a href="/" class="u-author"></a>
        </span>
      </div>
      </header>
  <div class="node__content clearfix">
  <div class="e-content clearfix ">Hi swentel! I just read your <a href="https://realize.be/blog/send-me-webmention-drupal" class="u-in-reply-to">article</a> and it's awesome!</div>
  </div>
</article>

If everything looks fine, go to the node form again. Open the 'Publish to' fieldset where you can enter 'https://realize.be/blog/send-me-webmention-drupal' in the custom URL textfield. Save again and check the send list at /admin/content/webmention/send-list. It should tell that there is one item in the queue. As a final step, run cron or the 'indieweb-send-webmentions' drush command. After that the queue should be empty and one entry will be in the send list and I should have received your webmention!

Note: You can vary between the 'u-in-reply-to', 'u-like-of' or 'u-repost-of' class. Basically, the class determines your response type. The first class will create a comment on this post. The other two classes will be a mention in the sidebar.

What's next?

Well, a lot of course. But the next step should be receiving webmentions no? If you go to /admin/config/services/indieweb/webmention, you can enable receiving webmentions by using the built-in endpoint. Make sure you expose the link tag so I know where to mention you!

I tried it, and it didn't work!

Maybe I missed something in the tutorial. Or you have found a bug :) Feel free to ping me on irc.freenode.net on #indieweb-dev or #drupal-contribute. You may also open an issue at https://github.com/swentel/indieweb

Send me a webmention with #drupal! 101 setup with the first release candidate of the #indieweb module. Can you mention me? https://realize.be/blog/send-me-webmention-drupal

Exclude entities which have a redirect from the search api index

For a custom project, we use a taxonomy to tag nodes. Some terms have their own page, while others redirect to a node. The search on the site has one index which contains both nodes and terms, but the terms which are redirecting shouldn't show up when viewing a search results page. While it's possible to use hook_search_api_index_items_alter(), a nicer way to exclude them is by using a processor plugin so you can enable them in the UI per index. The relevant code is underneath. Adjust to your own likings - and maybe inject the service if you want to as well :)

<?php
namespace Drupal\project\Plugin\search_api\processor;

use
Drupal\search_api\IndexInterface;
use
Drupal\search_api\Processor\ProcessorPluginBase;

/**
 * Excludes entities which have a redirect.
 *
 * @SearchApiProcessor(
 *   id = "entity_redirect",
 *   label = @Translation("Entity redirect"),
 *   description = @Translation("Exclude entities which have a redirect from being indexed."),
 *   stages = {
 *     "alter_items" = 0,
 *   },
 * )
 */
class EntityRedirect extends ProcessorPluginBase {

 
/**
   * {@inheritdoc}
   */
 
public static function supportsIndex(IndexInterface $index) {
    foreach (
$index->getDatasources() as $datasource) {
     
$entity_type_id = $datasource->getEntityTypeId();
      if (!
$entity_type_id) {
        continue;
      }
      if (
$entity_type_id === 'node' || $entity_type_id == 'taxonomy_term') {
        return
TRUE;
      }
    }
    return
FALSE;
  }

 
/**
   * {@inheritdoc}
   */
 
public function alterIndexedItems(array &$items) {
   
$repository = \Drupal::service('redirect.repository');
   
$pathAliasmanager = \Drupal::service('path.alias_manager');
   
/** @var \Drupal\search_api\Item\ItemInterface $item */
   
foreach ($items as $item_id => $item) {
     
$object = $item->getOriginalObject()->getValue();
      try {
       
$path = $object->toUrl()->toString();
       
$path = $pathAliasmanager->getPathByAlias($path);
       
$path = ltrim($path, '/');
       
$redirect = $repository->findMatchingRedirect($path);
        if (!empty(
$redirect)) {
          unset(
$items[$item_id]);
        }
      }
      catch (
\Exception $ignored) {}
    }
  }

}
?>
Exclude entities which have a redirect from the search api index: https://realize.be/blog/exclude-entities-which-have-redirect-search-api-index

#15

Finished the #PlanetaryPursuit with a view on the cliffs in Senneville. Amazing view with Fecamp at the tip .. #Normandie

#12

First tryout with led lights on the wings of my #drone and long exposure at night .. need to work on flying in nice patterns now :)
Light painting
Light painting
Light painting
Light painting
Topics

De splitsing

Last year I spent a lot of evenings writing a script for a play I had in mind. And finally it's there, the first production is coming the first weekend of december. You are all invited! If you don't understand dutch, make your own story while watching, who knows we come up with an idea for another play :) More information and tickets reservation are available on okermaan.be

De splitsing

Configuration split: deploy subsets of configuration in Drupal 8

From the Configuration split project page: "The Drupal 8 configuration management works best when importing and exporting the whole set of the sites configuration. However, sometimes developers like to opt out of the robustness of CMI and have a super-set of configuration active on their development machine and deploy only a subset. The canonical example for this is to have the devel module installed or having a few block placements or views in the development environment and then not export them into the set of configuration to be deployed, yet still being able to share the development configuration with colleagues."

This small utility module for Drupal 8 allows you to exactly achieve this use case (and many others). I will cover two common scenarios, explaining how to configure your site and which commands you need to run:

  1. Have (development/ui) modules installed on your dev environment, uninstalled on production
  2. Have modules installed on your production environment, but not on development

Configuration split 101

Configuration split exposes a configuration entity which controls what you want to split off. Currently you can

  • blacklist modules: any configuration that this module owns will automatically be blacklisted too.
  • blacklist configuration: settings or configuration entities. These will be removed from the active sync directory.
  • graylist configuration: settings or configuration entities. These will not be removed if they are in the active sync directory, but also not exported if they are not there yet. I won't cover this functionality in this article post, that will be for another time.

After you configured one or more configurations split entities, you can use the drush commands to export and import configuration, based on one or more of those config entities. When it comes to exporting configuration, you can not use the existing drush core command (config-export / cex). Using drush config-import (cim) or the UI to import may still be used, but this depends on your setup. Drupal Console commands are under revision. Important: since feb 2017, due to https://www.drupal.org/node/2855319 and https://github.com/drush-ops/drush/pull/2471, you can use the standard drush commands without any problems!

Each config split entity defines the directory in which the splitted configuration will live in case there are some. Not all modules define configuration, so there's a possibility that this directory is empty after you do an export.

An important technical aspect is that the module does not interfere with the active configuration but instead filters on the import/export pipeline. What simple happens is this: just before the actual writing, it will check the configuration and remove any entries that you don't want to be there. Then your active configuration is written away. Config that doesn't belong into the active configuration will be moved to separate directory. On import, the opposite happens: it will merge settings back in and set modules to the installed state just before core configuration then starts importing.

Last, but not least: you can swap the config.storage.sync service so that the synchronize screen will use the config split config entities for importing. More information is in the README file and in the video.

Scenario 1: modules installed on dev, not on production

Step 1

After you installed the module, go to 'admin/config/development/configuration/config-split' and click on 'Add configuration split'. Naming is important, so we'll enter 'Dev split' as the name for this configuration. We'll also create a directory called 'sync-dev-split'. Now toggle the modules that you don't want to have installed on production. In this case, we're going to blacklist Devel, Devel Kint, Field UI, Views UI and database logging. Additionally, also toggle system.menu.devel. This configuration is owned by the system module, so there's no dependency on the devel module. There's no problem having this config on your production site though, so it's not required to blacklist it.

Optionally, you can also blacklist the configuration split module because it doesn't necessarily have to be installed on production. We're not doing that here, because in the second scenario, we're building further on this one and we want to have it installed on the production environment as well.

Step 2

Go to your command line interface and run following command:

swentel@dev:/home/drupal/drupal-core$ drush csex --split=dev_split

The split option is not required, but when starting to work with the module, it helps you to know which config split will be used for this command. It's possible to override the status of any config split config entity so that eventually, you can omit the split option. Sadly enough, you don't get any feedback (yet), but after the command has run you should see various files in your sync-dev-split directory:

swentel@dev:/home/drupal/drupal-core$ ls sync-dev-split/
dblog.settings.yml  devel.settings.yml  field_ui.settings.yml  system.menu.devel.yml

Step 3

You can now commit your active sync and go to production. You don't necessarily have to put the sync-dev-live directory in your version control because production doesn't need to know about these files at all. Once you have pulled on production, go to the synchronize screen to verify what is staged. You will see that the setting files will be removed and core.extension will be changed uninstalling the development modules and installing configuration split. Since we only have one config split configuration, you can hit 'Import all' here or run drush config-import, (which is the drush core command). Note that if you don't use the UI, you can blacklist the configuration manager module as well.

You might wonder why we don't use the 'config-split-import' command from the module itself: this would import the active sync directory and also include the modules and settings again that we have blacklisted. And that's not what we want. This seems confusing at first, but ultimately, if this is your setup, you just keep on using the core / drush commands to import your staged configuration on production.

# This command can be used now, but not anymore further on when we will add scenario 2.
swentel@live:/home/drupal/drupal-core$ drush cim

Scenario 2: modules installed on production, not on dev

Step 1

This scenario builds further on the first one. Config split is now installed on our live website. Create a new config split configuration called 'Live split'. You will need a new directory for this second config split, so make sure it's there. On production we still want to log events and for that we're going to use the syslog module. Install the module, so that we can now blacklist it for the live split configuration.

Step 2

Go to your command line interface and run following commands:

swentel@live:/home/drupal/drupal-core$ drush csex --split=live_split

Again, no feedback here, but after the command has run you should see the syslog settings file in your sync-live-split directory:

swentel@live:/home/drupal/drupal-core$ ls sync-live-split/
syslog.settings.yml

Doing exports and imports on dev or live

From now on, if you want to import new settings whether it's on your dev or live environment, you can not use the drush core commands anymore. Use following commands:

# to export on your dev environment
swentel@dev:/home/drupal/drupal-core$ drush csex --split=dev_split
# to import on your dev environment
swentel@dev:/home/drupal/drupal-core$ drush csim --split=dev_split

# to export on your live environment
swentel@live:/home/drupal/drupal-core$ drush csex --split=live_split
# to import on your live environment
swentel@live:/home/drupal/drupal-core$ drush csim --split=live_split

The future

Please join us in the issue queue because there's still some work:

  • Optimize the user interface and allow wildcards
  • Add confirmation and feedback in the drush commands

Ultimately, this functionality should live in core. A core issue to discuss this is at https://www.drupal.org/node/2830300.