SlideShare a Scribd company logo
Drupal 8, where did
the code go? From
info hook to plugin
Peter Wolanin
July 14, 2016
Background and “What’s a plugin?”!
Example of a core info hook conversion!
Simple but common plugin example:

adding new tabs (a.k.a. local tasks)!
Configurable plugins (ConfigEntity based)!
‣ Adding a custom block!
‣ Adding a custom text filter!
Considerations for defining your own plugins
Here’s What’s In the Talk
2
Drupal 5, 6, 7, 8 core
contributor!
Drupal Security Team!
Acquia Engineering!
Helped create some
Drupal 8 plugins including
SearchPlugin, MenuLinks,
LocalTasks, LocalActions,
ContextualLinks!
DrupalCamp NJ organizer
Who Am I?
3
https://www.drupal.org/u/pwolanin
Photo by amazeelabs, by-nc-sa
I’ll assume you know something about:!
The DIC/container/service container!
‣ The container is an object that contains
instances of stateless “services” (the current
request, the current user, URL generator, etc)!
The new routing system - names instead of paths.!
‣ a route name is just a machine name connected
to a path and callbacks to provide, title, content,
access etc. - like a D7 menu router!
Namespaced classes (PHP 5.3+) like 

DrupalsearchPluginBlockSearchBlock
Drupal 8 Background
4
Encapsulate some re-useable functionality inside
a class that implements one or more specific
interfaces!
Plugins combine what in Drupal 7 was an info
hook and a number of implementation hooks and
possibly configuration: e.g. hook_search_info()
and hook_search_execute(), etc., or
hook_block_info() and hook_block_view(),
_configure(), _save()!
Evolved from ctools and views plugins, but have
quite different mechanisms to discover them
Plugins
5
Every plugin type has a manager - registered as a
service (available from the container) and used to
find and instantiate the desired plugin instance(s)!
Each plugin has an ID, which may be in its
definition, or generated as a derivative!
For a given plugin ID one single class will be used
for all plugin instances using that plugin ID!
A plugin instance is specified by the combination of
plugin ID and its configuration values, potentially
coming from a ConfigEntity
Plugin Manager and IDs
6
“The Drop is
always moving”
http://flickr.com/photos/alkalinezoo/32265389/
drupal.org/node/65922
7.x: hook_image_toolkits()
8
/**!
* Implements hook_image_toolkits().!
*/!
function system_image_toolkits() {!
include_once DRUPAL_ROOT . '/' . drupal_get_path('module',
'system') . '/' . 'image.gd.inc';!
return array(!
'gd' => array(!
'title' => t('GD2 image manipulation toolkit'),!
'available' => function_exists('image_gd_check_settings') &&!
image_gd_check_settings(),!
),!
);!
}!
8.x: GD Image Toolkit Plugin
9
/**!
* Defines the GD2 toolkit for image manipulation within Drupal.!
*!
* @ImageToolkit(!
* id = "gd",!
* title = @Translation("GD2 image manipulation toolkit")!
* )!
*/!
class GDToolkit extends ImageToolkitBase {!
//... more methods ..//!
!
public static function isAvailable() {!
// GD2 support is available.!
return function_exists('imagegd2');!
}!
!
//... more methods ..//!
}
8.x: ImageToolkitManager
10
class ImageToolkitManager extends DefaultPluginManager {!
// ... various methods ... //!
!
/**!
* Gets a list of available toolkits.!
*/!
public function getAvailableToolkits() {!
// Use plugin system to get list of available toolkits.!
$toolkits = $this->getDefinitions();!
!
$output = array();!
foreach ($toolkits as $id => $definition) {!
if (call_user_func($definition['class'] . '::isAvailable')) {!
$output[$id] = $definition;!
}!
}!
return $output;!
}!
}
7.x: image_desaturate() Function
11
/**!
* Converts an image to grayscale.!
*!
* @param $image!
* An image object returned by image_load().!
*!
* @return!
* TRUE on success, FALSE on failure.!
*!
* @see image_load()!
* @see image_gd_desaturate()!
*/!
function image_desaturate(stdClass $image) {!
return image_toolkit_invoke('desaturate', $image);!
}!
!
8.x: Image::desaturate() via Plugin
12
/**!
* Defines an image object to represent an image file.!
*!
* @see DrupalCoreImageToolkitImageToolkitInterface!
* @see DrupalimageImageEffectInterface!
*/!
class Image implements ImageInterface {!
//... more methods ..//!
!
public function apply($operation, array $arguments = array()) {!
return $this->getToolkit()->apply($operation, $arguments);!
}!
!
public function desaturate() {!
return $this->apply('desaturate', array());!
}!
!
//... more methods ..//!
}!
7.x: Operation by Function Prefix
13
/**!
* Convert an image resource to grayscale.!
*!
* Note that transparent GIFs loose transparency when desaturated.!
*!
* @param $image!
* An image object. The $image->resource value will be modified.!
* @return!
* TRUE or FALSE, based on success.!
*!
* @see image_desaturate()!
*/!
function image_gd_desaturate(stdClass $image) {!
// PHP using non-bundled GD does not have imagefilter.!
if (!function_exists('imagefilter')) {!
watchdog('image', 'The image could not be desaturated.');!
return FALSE;!
}!
return imagefilter($image->resource, IMG_FILTER_GRAYSCALE);!
}!
!
8.x: Operations Are Also Plugins/**!
* Defines GD2 Desaturate operation.!
*!
* @ImageToolkitOperation(!
* id = "gd_desaturate",!
* toolkit = "gd",!
* operation = "desaturate",!
* label = @Translation("Desaturate"),!
* )!
*/!
class Desaturate extends GDImageToolkitOperationBase {!
!
protected function execute(array $arguments) {!
// PHP using non-bundled GD does not have imagefilter.!
if (!function_exists('imagefilter')) {!
$this->logger->notice("The image could not be desaturated");!
return FALSE;!
}!
return imagefilter($this->getToolkit()->getResource(),!
IMG_FILTER_GRAYSCALE);!
}!
}
14
What About Hooks?
http://flickr.com/photos/avelino_maestas/2532426169/
Most plugin managers invoke an _alter hook so
the modules can add to or alter the plugins’
definitions!
For example, hook_block_alter()allows you
to alter the block plugin definitions!
Info hooks that simply return a data array, without
associated code and logic, were not candidates to
become plugins (but may have become YAML)!
Others like hook_cron() or
hook_entity_access() are still present
Hooks Still Have Their Place
16
The discovery of plugins is basically the same as
invoking an info hook (and, in fact, it can even be
implemented that way)!
Discovery gives you an array of plugin definitions,
each of which is just an array of keys and values!
The discovery process fills in defaults, such a
‘provider’ which is the name of the module
providing the plugin!
Discovery can make derivatives (many from one)
like FieldUiLocalTask - one tab per bundle
Plugin Discovery
17
YAML based:!
MenuLink, LocalTask, LocalAction,
ContextualLink!
Annotation, some config, but no config entity:!
ImageToolkit, Archiver!
Annotation and config entity (many) including:!
Block, ViewsDisplay, ImageEffect, SearchPlugin!
Not a pure Plugin but uses Annotation discovery:!
Entity (Node, User, etc.)
Plugin Discovery & Config in Core
18
Let’s Start Learning The
Drupal 8.x Plugin Toolkit
http://flickr.com/photos/booleansplit/2376359338/
As in Drupal 7, code is provided by modules - so
you need a module. You need a .info.yml file - like
a .info file for Drupal 7!
You no longer need even an empty .module file!
The only remaining code in .module files are a few
hook implementations: most code lives in classes
Pre-requisite: a Drupal 8 Module
20
name: 'My test module'!
type: module!
description: ‘Acquia webinar demo.'!
core: 8.x
modules/mymodule/mymodule.info.yml
For most uses, just add a YAML file listing your tabs:
mymodule/mymodule.links.tasks.yml
Adding Two Tabs:
21
mymodule.list_tab:!
route_name: mymodule.list!
title: 'List'!
base_route: mymodule.list!
!
mymodule.settings_tab:!
route_name: mymodule.settings!
title: 'Settings'!
base_route: mymodule.list
Plugin	
ID
Local tasks	
reference	
a base
route
which
groups
them
Unlike Drupal 7 you don’t need to jump though the
hoops of a default local task, or making the paths
align in a certain hierarchy
Adding Two Tabs:
22
Of course, those routes need to be defined or pre-
existing: mymodule/mymodule.routing.yml
LocalTask Plugins Need Routes:
23
mymodule.list:!
path: '/admin/config/mymodule/list'!
defaults:!
_controller: 'DrupalmymoduleControllerMyController::dolist'!
_title: 'Mymodule list'!
requirements:!
_access: 'TRUE'!
!
mymodule.settings:!
path: '/admin/config/also-mymodule/settings'!
defaults:!
_controller: 'DrupalmymoduleControllerMyController::settings'!
_title: 'Mymodule settings'!
requirements:!
_access: 'TRUE'
The plugin configuration options and defaults are on
the LocalTaskManager class
LocalTask Plugin Keys:
24
class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerInterface {!
protected $defaults = array(!
// (required) The name of the route this task links to.!
'route_name' => '',!
// Parameters for route variables when generating a link.!
'route_parameters' => array(),!
// The static title for the local task.!
'title' => '',!
// The route name where the root tab appears.!
'base_route' => '',!
// The plugin ID of the parent tab (or NULL for the top-level tab).!
'parent_id' => NULL,!
// The weight of the tab.!
'weight' => NULL,!
// The default link options.!
'options' => array(),!
// Default class for local task implementations.!
'class' => 'DrupalCoreMenuLocalTaskDefault',!
// The plugin id. Set by the plugin system based on the top-level YAML key.!
'id' => '',!
);!
}!
The New Block
http://flickr.com/photos/kubina/973244593/
Each custom block is defined in code as a class!
When the admin places the block into a region in
a theme, a configuration object is created to track
that setting!
The config object is a ConfigEntity - it’s an
abstraction on top of CMI (storing your Drupal
configuration in YAML files) - it makes it
convenient to list, load, etc. using entity functions. !
Drupal can easily list the active block instances!
Note - you don’t need to worry about the config!
Blocks as Plugins
26
Blocks implement the!
DrupalCoreBlockBlockPluginInterface!
If you extend the abstract

DrupalCoreBlockBlockBase class then
all you need to implement is the build() method!
build() is basically the same as
hook_block_view() in Drupal 7!
For example, I added to my module

DrupalmymodulePluginBlockMyBlock
Blocks Implementation
27
When I add the Block to my module:

DrupalmymodulePluginBlockMyBlock!
This is at the corresponding file path (under the
Drupal root directory):

modules/mymodule/src/Plugin/Block/
MyBlock.php!
Note that the class name and the path match up
under src/!
This mapping of class name to path is how the
class can be automatically found and loaded
Side Note - PSR-4
28
29
/**!
* Provides a block with 'Mymodule' links.!
*!
* @Block(!
* id = "mymodule_my_block",!
* admin_label = @Translation("Mymodule block")!
* )!
*/!
class MyBlock extends BlockBase {!
public function build() {!
return [!
'first_link' => [!
'#type' => 'link',!
'#title' => $this->t('Mymodule List'),!
'#url' => Url::fromRoute('mymodule.list'),!
],!
'second_link' => [!
'#type' => 'link',!
'#title' => $this->t('Mymodule Settings'),!
'#url' => Url::fromRoute('mymodule.settings'),!
],!
];!
}!
}
30
Blocks
Admin!
Page Has a
New
Function: 

Place block
31
Blocks
Admin!
Page Has a
New
Function: 

Place block
32
Save the
Block to
Create a
New Plugin
Instance
33
Block Hook to Plugin Comparison
34
Drupal 7.x Drupal 8.x
hook_block_info()
BlockManagerInterface::

getDefinitions()
hook_block_view($delta)
BlockPluginInterface::

build()
?
BlockPluginInterface::

access(AccountInterface $account)
hook_block_configure($delta)
BlockPluginInterface::

blockForm($form, $form_state)
?
BlockPluginInterface::

blockValidate($form, $form_state)
hook_block_save($delta, $edit)
BlockPluginInterface::

blockSubmit($form, $form_state)
Each Plugin type must be in the expected class
namespace for your module - for blocks:
namespace DrupalmymodulePluginBlock;!
Most core plugins have a custom annotation
class - you have to use the right one for your
plugin!
The annotation class provides both a
documentation of the possible keys in the plugin
definition and default values!
There is also a generic Plugin annotation class
Block Discovery and Annotations
35
36
/**!
* Defines a Block annotation object.!
*!
* @Annotation!
*/!
class Block extends Plugin {!
/**!
* The plugin ID.!
*!
* @var string!
*/!
public $id;!
!
/**!
* The administrative label of the block.!
*!
* @var DrupalCoreAnnotationTranslation!
*!
* @ingroup plugin_translatable!
*/!
public $admin_label;!
!
//... more properties ..//!
}
Filtering Text
http://flickr.com/photos/pinksherbet/253412963/
7.x Info Hook
38
/**!
* Implements hook_filter_info().!
*!
* @ingroup project_issue_filter!
*/!
function project_issue_filter_info() {!
$filters['filter_project_issue_link'] = array(!
'title' => t('Project issue to link filter'),!
'description' => t('Converts references to project issues !
(in the form of [#12345]) into links.'),!
'process callback' => '_project_issue_filter',!
'tips callback' => '_project_issue_filter_tips',!
'cache' => TRUE,!
);!
return $filters;!
}
39
/**!
* Provides a filter to format a node ID as a link.!
*!
* @Filter(!
* id = "mymodule_node_link",!
* module = "mymodule",!
* title = @Translation("Format a node ID as a link")!
* )!
*/!
class NodeLinkFilter extends FilterBase {!
public function process($text, $langcode) {!
$regex = ‘(?:(?<!w)[(#d+(?:-[d.]+)?)](?!w))|…’;!
$callback = function($matches) { ... } !
$text = preg_replace_callback("/$regex/", $callback, $text);!
return new FilterProcessResult($text);!
}!
!
// ... more code ...//!
!
public function tips($long = FALSE) {!
return $this->t('Node ID numbers (ex. [#12345]) turn into
links automatically.');!
}!
}
8.x Plugin With Annotation
40
41
42
43
44
You want to upgrade your module to Drupal 8 and
it defined an info hook or had a ctools plugin type !
Use annotation based discovery by default!
It keeps the meta-data together with the class and
is suited for typical plugin types where the actual
class (code) is different for each plugins!
YAML discovery is good for a case like local tasks
where the vast majority use a common class, but
a few will implement a different one (for example,
to provide a dynamic title)
Creating Your Own Plugins
45
Demo code used for this presentation:

drupal.org/sandbox/pwolanin/2087657 !
Converting 7.x modules to 8.x 

drupal.org/update/modules/7/8!
Plugin API in Drupal 8

drupal.org/developing/api/8/plugins!
Why Plugins? drupal.org/node/1637614!
Unraveling the Drupal 8 Plugin System
drupalize.me/blog/201409/unravelling-drupal-8-
plugin-system
Plugin and General 8.x Resources
46
Widespread use of interfaces makes it easier to
replace almost any implementation!
Tabs are grouped regardless of path hierarchy!
Route name rather than system path is unique!
Multiple routes can serve the same path (HTML
vs. JSON or GET vs. POST)!
YAML as a standard for config and data files!
Multiple instances of the same block!
Each block instances has a config entity
Drupal 8 Features I Mentioned
47
Plugins are a way to combine the discovery of
available functionality with the actual
implementation of the functionality!
In Drupal 7, the combination of an info hook and
multiple other hook functions (potentially in
different files) served the same purpose!
When defining your own plugins, use Annotation-
based discovery unless you have a very clear
reason for a different type
To Sum It Up
Licensed:
http://creativecommons.org/licenses/by-nc-sa/2.0/
This presentation is © 2016, Acquia, Inc.

More Related Content

PPT
jQuery and_drupal
PDF
Catalyst patterns-yapc-eu-2016
PPT
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
PDF
Geodaten & Drupal 7
PPTX
Planbox Backbone MVC
PDF
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
PDF
Staying Sane with Drupal (A Develper's Survival Guide)
PPT
Drupal Javascript for developers
jQuery and_drupal
Catalyst patterns-yapc-eu-2016
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
Geodaten & Drupal 7
Planbox Backbone MVC
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
Staying Sane with Drupal (A Develper's Survival Guide)
Drupal Javascript for developers

What's hot (20)

PDF
#31.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_스프링프레임워크 강좌, 재직자환급교육,실업자국비지원...
PDF
Symfony tips and tricks
PPT
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
PDF
Using VueJS in front of Drupal 8
PPTX
Vue business first
PDF
Drupal 8: Fields reborn
PPTX
Spring Boot
PDF
TurboGears2 Pluggable Applications
PDF
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
DOC
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
PPT
Render API - Pavel Makhrinsky
PDF
SBT Crash Course
PPTX
Eddystone Beacons - Physical Web - Giving a URL to All Objects
PDF
AspNetWhitePaper
PDF
Using RequireJS with CakePHP
DOC
How to migrate Cakephp 1.x to 2.x
PPT
Creating the interfaces of the future with the APIs of today
PDF
2021laravelconftwslides11
PPTX
Getting started with sbt
PDF
Getting Into Drupal 8 Configuration
#31.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_스프링프레임워크 강좌, 재직자환급교육,실업자국비지원...
Symfony tips and tricks
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Using VueJS in front of Drupal 8
Vue business first
Drupal 8: Fields reborn
Spring Boot
TurboGears2 Pluggable Applications
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
Render API - Pavel Makhrinsky
SBT Crash Course
Eddystone Beacons - Physical Web - Giving a URL to All Objects
AspNetWhitePaper
Using RequireJS with CakePHP
How to migrate Cakephp 1.x to 2.x
Creating the interfaces of the future with the APIs of today
2021laravelconftwslides11
Getting started with sbt
Getting Into Drupal 8 Configuration
Ad

Viewers also liked (20)

PDF
Hooks and Events in Drupal 8
PPTX
Drupal 8 Development at the Speed of Lightning (& BLT)
PDF
Drupal 8 Render Cache
PPT
Why the Government of Bermuda Chose to Build Their New Citizen-centric Digita...
PPTX
Going Beyond The Click: The Importance of Web Personalization
PDF
Preventing Drupal Headaches: Establishing Flexible File Paths From The Start
PDF
Tomorrow’s Personalization Today: Increase User Engagement with Content in Co...
PPTX
Successes and Challenges When Managing Large Scale Drupal Projects
PDF
Speedrun: Build a Website with Panels, Media, and More in 45 Minutes
PPTX
3 Tips for a Successful Ektron to Drupal Conversion
PDF
Drupal 8: The Foundation for Digital Experience and Digital Business
PPTX
Going Global 101: How to Manage Your Websites Worldwide Using Drupal
PDF
Introducing Workspace Preview System: Solve Your Content Preview Problems
PDF
How Wilson Sporting Goods Is Changing the Game with Experiential Commerce
PDF
From Stone Age-worthy Sites to Cohesive Content: How Trinity University is Us...
PDF
Entities 101: Understanding Data Structures in Drupal
PDF
Open Y: One Digital Platform for all YMCAs
PPTX
Decoupled Drupal Showcase: Using Drupal to Power Digital Signage
PDF
A Future-Focused Digital Platform with Drupal 8
PPTX
Drupal 7 vs. Drupal 8: A Contrast of Multilingual Support
Hooks and Events in Drupal 8
Drupal 8 Development at the Speed of Lightning (& BLT)
Drupal 8 Render Cache
Why the Government of Bermuda Chose to Build Their New Citizen-centric Digita...
Going Beyond The Click: The Importance of Web Personalization
Preventing Drupal Headaches: Establishing Flexible File Paths From The Start
Tomorrow’s Personalization Today: Increase User Engagement with Content in Co...
Successes and Challenges When Managing Large Scale Drupal Projects
Speedrun: Build a Website with Panels, Media, and More in 45 Minutes
3 Tips for a Successful Ektron to Drupal Conversion
Drupal 8: The Foundation for Digital Experience and Digital Business
Going Global 101: How to Manage Your Websites Worldwide Using Drupal
Introducing Workspace Preview System: Solve Your Content Preview Problems
How Wilson Sporting Goods Is Changing the Game with Experiential Commerce
From Stone Age-worthy Sites to Cohesive Content: How Trinity University is Us...
Entities 101: Understanding Data Structures in Drupal
Open Y: One Digital Platform for all YMCAs
Decoupled Drupal Showcase: Using Drupal to Power Digital Signage
A Future-Focused Digital Platform with Drupal 8
Drupal 7 vs. Drupal 8: A Contrast of Multilingual Support
Ad

Similar to Drupal 8, Where Did the Code Go? From Info Hook to Plugin (20)

PDF
Drupal 8 Deep Dive: Plugin System
PPTX
PPTX
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
PPTX
Migrate yourself. code -> module -> mind
PPTX
D8 training
PPTX
PDF
Drupal 8 - Core and API Changes
PDF
Drupal 8 what to wait from
PDF
Web automation with #d8rules (European Drupal Days 2015)
PPTX
Top 8 Improvements in Drupal 8
PDF
The state of hooking into Drupal - DrupalCon Dublin
PDF
Drupal 7 migrating to drupal 8
PDF
Drupal 7-api-2010-11-10
PDF
Drupal 8 - Corso frontend development
PDF
Drupal 8 deeper dive
PDF
Gestione della configurazione in Drupal 8
PDF
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
PDF
Migrate to Drupal 8
PDF
Migrate 140123161042-phpapp02
Drupal 8 Deep Dive: Plugin System
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
Migrate yourself. code -> module -> mind
D8 training
Drupal 8 - Core and API Changes
Drupal 8 what to wait from
Web automation with #d8rules (European Drupal Days 2015)
Top 8 Improvements in Drupal 8
The state of hooking into Drupal - DrupalCon Dublin
Drupal 7 migrating to drupal 8
Drupal 7-api-2010-11-10
Drupal 8 - Corso frontend development
Drupal 8 deeper dive
Gestione della configurazione in Drupal 8
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Migrate to Drupal 8
Migrate 140123161042-phpapp02

More from Acquia (20)

PDF
Acquia_Adcetera Webinar_Marketing Automation.pdf
PDF
Acquia Webinar Deck - 9_13 .pdf
PDF
Taking Your Multi-Site Management at Scale to the Next Level
PDF
CDP for Retail Webinar with Appnovation - Q2 2022.pdf
PDF
May Partner Bootcamp 2022
PDF
April Partner Bootcamp 2022
PDF
How to Unify Brand Experience: A Hootsuite Story
PDF
Using Personas to Guide DAM Results: How Life Time Pumped Up Their UX and CX
PDF
Improve Code Quality and Time to Market: 100% Cloud-Based Development Workflow
PDF
September Partner Bootcamp
PDF
August partner bootcamp
PDF
July 2021 Partner Bootcamp
PDF
May Partner Bootcamp
PDF
DRUPAL 7 END OF LIFE IS NEAR - MIGRATE TO DRUPAL 9 FAST AND EASY
PDF
Work While You Sleep: The CMO’s Guide to a 24/7/365 Lead Machine
PDF
Acquia webinar: Leveraging Drupal to Bury Your Sales Team In B2B Leads
PDF
April partner bootcamp deck cookieless future
PDF
How to enhance cx through personalised, automated solutions
PDF
DRUPAL MIGRATIONS AND DRUPAL 9 INNOVATION: HOW PAC-12 DELIVERED DIGITALLY FOR...
PDF
Customer Experience (CX): 3 Key Factors Shaping CX Redesign in 2021
Acquia_Adcetera Webinar_Marketing Automation.pdf
Acquia Webinar Deck - 9_13 .pdf
Taking Your Multi-Site Management at Scale to the Next Level
CDP for Retail Webinar with Appnovation - Q2 2022.pdf
May Partner Bootcamp 2022
April Partner Bootcamp 2022
How to Unify Brand Experience: A Hootsuite Story
Using Personas to Guide DAM Results: How Life Time Pumped Up Their UX and CX
Improve Code Quality and Time to Market: 100% Cloud-Based Development Workflow
September Partner Bootcamp
August partner bootcamp
July 2021 Partner Bootcamp
May Partner Bootcamp
DRUPAL 7 END OF LIFE IS NEAR - MIGRATE TO DRUPAL 9 FAST AND EASY
Work While You Sleep: The CMO’s Guide to a 24/7/365 Lead Machine
Acquia webinar: Leveraging Drupal to Bury Your Sales Team In B2B Leads
April partner bootcamp deck cookieless future
How to enhance cx through personalised, automated solutions
DRUPAL MIGRATIONS AND DRUPAL 9 INNOVATION: HOW PAC-12 DELIVERED DIGITALLY FOR...
Customer Experience (CX): 3 Key Factors Shaping CX Redesign in 2021

Recently uploaded (20)

PDF
Electronic commerce courselecture one. Pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
cuic standard and advanced reporting.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
Electronic commerce courselecture one. Pdf
Per capita expenditure prediction using model stacking based on satellite ima...
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
Dropbox Q2 2025 Financial Results & Investor Presentation
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
The AUB Centre for AI in Media Proposal.docx
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Spectral efficient network and resource selection model in 5G networks
20250228 LYD VKU AI Blended-Learning.pptx
cuic standard and advanced reporting.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
MYSQL Presentation for SQL database connectivity
The Rise and Fall of 3GPP – Time for a Sabbatical?
Digital-Transformation-Roadmap-for-Companies.pptx
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Building Integrated photovoltaic BIPV_UPV.pdf
Chapter 3 Spatial Domain Image Processing.pdf
Review of recent advances in non-invasive hemoglobin estimation

Drupal 8, Where Did the Code Go? From Info Hook to Plugin

  • 1. Drupal 8, where did the code go? From info hook to plugin Peter Wolanin July 14, 2016
  • 2. Background and “What’s a plugin?”! Example of a core info hook conversion! Simple but common plugin example:
 adding new tabs (a.k.a. local tasks)! Configurable plugins (ConfigEntity based)! ‣ Adding a custom block! ‣ Adding a custom text filter! Considerations for defining your own plugins Here’s What’s In the Talk 2
  • 3. Drupal 5, 6, 7, 8 core contributor! Drupal Security Team! Acquia Engineering! Helped create some Drupal 8 plugins including SearchPlugin, MenuLinks, LocalTasks, LocalActions, ContextualLinks! DrupalCamp NJ organizer Who Am I? 3 https://www.drupal.org/u/pwolanin Photo by amazeelabs, by-nc-sa
  • 4. I’ll assume you know something about:! The DIC/container/service container! ‣ The container is an object that contains instances of stateless “services” (the current request, the current user, URL generator, etc)! The new routing system - names instead of paths.! ‣ a route name is just a machine name connected to a path and callbacks to provide, title, content, access etc. - like a D7 menu router! Namespaced classes (PHP 5.3+) like 
 DrupalsearchPluginBlockSearchBlock Drupal 8 Background 4
  • 5. Encapsulate some re-useable functionality inside a class that implements one or more specific interfaces! Plugins combine what in Drupal 7 was an info hook and a number of implementation hooks and possibly configuration: e.g. hook_search_info() and hook_search_execute(), etc., or hook_block_info() and hook_block_view(), _configure(), _save()! Evolved from ctools and views plugins, but have quite different mechanisms to discover them Plugins 5
  • 6. Every plugin type has a manager - registered as a service (available from the container) and used to find and instantiate the desired plugin instance(s)! Each plugin has an ID, which may be in its definition, or generated as a derivative! For a given plugin ID one single class will be used for all plugin instances using that plugin ID! A plugin instance is specified by the combination of plugin ID and its configuration values, potentially coming from a ConfigEntity Plugin Manager and IDs 6
  • 7. “The Drop is always moving” http://flickr.com/photos/alkalinezoo/32265389/ drupal.org/node/65922
  • 8. 7.x: hook_image_toolkits() 8 /**! * Implements hook_image_toolkits().! */! function system_image_toolkits() {! include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'image.gd.inc';! return array(! 'gd' => array(! 'title' => t('GD2 image manipulation toolkit'),! 'available' => function_exists('image_gd_check_settings') &&! image_gd_check_settings(),! ),! );! }!
  • 9. 8.x: GD Image Toolkit Plugin 9 /**! * Defines the GD2 toolkit for image manipulation within Drupal.! *! * @ImageToolkit(! * id = "gd",! * title = @Translation("GD2 image manipulation toolkit")! * )! */! class GDToolkit extends ImageToolkitBase {! //... more methods ..//! ! public static function isAvailable() {! // GD2 support is available.! return function_exists('imagegd2');! }! ! //... more methods ..//! }
  • 10. 8.x: ImageToolkitManager 10 class ImageToolkitManager extends DefaultPluginManager {! // ... various methods ... //! ! /**! * Gets a list of available toolkits.! */! public function getAvailableToolkits() {! // Use plugin system to get list of available toolkits.! $toolkits = $this->getDefinitions();! ! $output = array();! foreach ($toolkits as $id => $definition) {! if (call_user_func($definition['class'] . '::isAvailable')) {! $output[$id] = $definition;! }! }! return $output;! }! }
  • 11. 7.x: image_desaturate() Function 11 /**! * Converts an image to grayscale.! *! * @param $image! * An image object returned by image_load().! *! * @return! * TRUE on success, FALSE on failure.! *! * @see image_load()! * @see image_gd_desaturate()! */! function image_desaturate(stdClass $image) {! return image_toolkit_invoke('desaturate', $image);! }! !
  • 12. 8.x: Image::desaturate() via Plugin 12 /**! * Defines an image object to represent an image file.! *! * @see DrupalCoreImageToolkitImageToolkitInterface! * @see DrupalimageImageEffectInterface! */! class Image implements ImageInterface {! //... more methods ..//! ! public function apply($operation, array $arguments = array()) {! return $this->getToolkit()->apply($operation, $arguments);! }! ! public function desaturate() {! return $this->apply('desaturate', array());! }! ! //... more methods ..//! }!
  • 13. 7.x: Operation by Function Prefix 13 /**! * Convert an image resource to grayscale.! *! * Note that transparent GIFs loose transparency when desaturated.! *! * @param $image! * An image object. The $image->resource value will be modified.! * @return! * TRUE or FALSE, based on success.! *! * @see image_desaturate()! */! function image_gd_desaturate(stdClass $image) {! // PHP using non-bundled GD does not have imagefilter.! if (!function_exists('imagefilter')) {! watchdog('image', 'The image could not be desaturated.');! return FALSE;! }! return imagefilter($image->resource, IMG_FILTER_GRAYSCALE);! }! !
  • 14. 8.x: Operations Are Also Plugins/**! * Defines GD2 Desaturate operation.! *! * @ImageToolkitOperation(! * id = "gd_desaturate",! * toolkit = "gd",! * operation = "desaturate",! * label = @Translation("Desaturate"),! * )! */! class Desaturate extends GDImageToolkitOperationBase {! ! protected function execute(array $arguments) {! // PHP using non-bundled GD does not have imagefilter.! if (!function_exists('imagefilter')) {! $this->logger->notice("The image could not be desaturated");! return FALSE;! }! return imagefilter($this->getToolkit()->getResource(),! IMG_FILTER_GRAYSCALE);! }! } 14
  • 16. Most plugin managers invoke an _alter hook so the modules can add to or alter the plugins’ definitions! For example, hook_block_alter()allows you to alter the block plugin definitions! Info hooks that simply return a data array, without associated code and logic, were not candidates to become plugins (but may have become YAML)! Others like hook_cron() or hook_entity_access() are still present Hooks Still Have Their Place 16
  • 17. The discovery of plugins is basically the same as invoking an info hook (and, in fact, it can even be implemented that way)! Discovery gives you an array of plugin definitions, each of which is just an array of keys and values! The discovery process fills in defaults, such a ‘provider’ which is the name of the module providing the plugin! Discovery can make derivatives (many from one) like FieldUiLocalTask - one tab per bundle Plugin Discovery 17
  • 18. YAML based:! MenuLink, LocalTask, LocalAction, ContextualLink! Annotation, some config, but no config entity:! ImageToolkit, Archiver! Annotation and config entity (many) including:! Block, ViewsDisplay, ImageEffect, SearchPlugin! Not a pure Plugin but uses Annotation discovery:! Entity (Node, User, etc.) Plugin Discovery & Config in Core 18
  • 19. Let’s Start Learning The Drupal 8.x Plugin Toolkit http://flickr.com/photos/booleansplit/2376359338/
  • 20. As in Drupal 7, code is provided by modules - so you need a module. You need a .info.yml file - like a .info file for Drupal 7! You no longer need even an empty .module file! The only remaining code in .module files are a few hook implementations: most code lives in classes Pre-requisite: a Drupal 8 Module 20 name: 'My test module'! type: module! description: ‘Acquia webinar demo.'! core: 8.x modules/mymodule/mymodule.info.yml
  • 21. For most uses, just add a YAML file listing your tabs: mymodule/mymodule.links.tasks.yml Adding Two Tabs: 21 mymodule.list_tab:! route_name: mymodule.list! title: 'List'! base_route: mymodule.list! ! mymodule.settings_tab:! route_name: mymodule.settings! title: 'Settings'! base_route: mymodule.list Plugin ID Local tasks reference a base route which groups them
  • 22. Unlike Drupal 7 you don’t need to jump though the hoops of a default local task, or making the paths align in a certain hierarchy Adding Two Tabs: 22
  • 23. Of course, those routes need to be defined or pre- existing: mymodule/mymodule.routing.yml LocalTask Plugins Need Routes: 23 mymodule.list:! path: '/admin/config/mymodule/list'! defaults:! _controller: 'DrupalmymoduleControllerMyController::dolist'! _title: 'Mymodule list'! requirements:! _access: 'TRUE'! ! mymodule.settings:! path: '/admin/config/also-mymodule/settings'! defaults:! _controller: 'DrupalmymoduleControllerMyController::settings'! _title: 'Mymodule settings'! requirements:! _access: 'TRUE'
  • 24. The plugin configuration options and defaults are on the LocalTaskManager class LocalTask Plugin Keys: 24 class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerInterface {! protected $defaults = array(! // (required) The name of the route this task links to.! 'route_name' => '',! // Parameters for route variables when generating a link.! 'route_parameters' => array(),! // The static title for the local task.! 'title' => '',! // The route name where the root tab appears.! 'base_route' => '',! // The plugin ID of the parent tab (or NULL for the top-level tab).! 'parent_id' => NULL,! // The weight of the tab.! 'weight' => NULL,! // The default link options.! 'options' => array(),! // Default class for local task implementations.! 'class' => 'DrupalCoreMenuLocalTaskDefault',! // The plugin id. Set by the plugin system based on the top-level YAML key.! 'id' => '',! );! }!
  • 26. Each custom block is defined in code as a class! When the admin places the block into a region in a theme, a configuration object is created to track that setting! The config object is a ConfigEntity - it’s an abstraction on top of CMI (storing your Drupal configuration in YAML files) - it makes it convenient to list, load, etc. using entity functions. ! Drupal can easily list the active block instances! Note - you don’t need to worry about the config! Blocks as Plugins 26
  • 27. Blocks implement the! DrupalCoreBlockBlockPluginInterface! If you extend the abstract
 DrupalCoreBlockBlockBase class then all you need to implement is the build() method! build() is basically the same as hook_block_view() in Drupal 7! For example, I added to my module
 DrupalmymodulePluginBlockMyBlock Blocks Implementation 27
  • 28. When I add the Block to my module:
 DrupalmymodulePluginBlockMyBlock! This is at the corresponding file path (under the Drupal root directory):
 modules/mymodule/src/Plugin/Block/ MyBlock.php! Note that the class name and the path match up under src/! This mapping of class name to path is how the class can be automatically found and loaded Side Note - PSR-4 28
  • 29. 29 /**! * Provides a block with 'Mymodule' links.! *! * @Block(! * id = "mymodule_my_block",! * admin_label = @Translation("Mymodule block")! * )! */! class MyBlock extends BlockBase {! public function build() {! return [! 'first_link' => [! '#type' => 'link',! '#title' => $this->t('Mymodule List'),! '#url' => Url::fromRoute('mymodule.list'),! ],! 'second_link' => [! '#type' => 'link',! '#title' => $this->t('Mymodule Settings'),! '#url' => Url::fromRoute('mymodule.settings'),! ],! ];! }! }
  • 32. 32 Save the Block to Create a New Plugin Instance
  • 33. 33
  • 34. Block Hook to Plugin Comparison 34 Drupal 7.x Drupal 8.x hook_block_info() BlockManagerInterface::
 getDefinitions() hook_block_view($delta) BlockPluginInterface::
 build() ? BlockPluginInterface::
 access(AccountInterface $account) hook_block_configure($delta) BlockPluginInterface::
 blockForm($form, $form_state) ? BlockPluginInterface::
 blockValidate($form, $form_state) hook_block_save($delta, $edit) BlockPluginInterface::
 blockSubmit($form, $form_state)
  • 35. Each Plugin type must be in the expected class namespace for your module - for blocks: namespace DrupalmymodulePluginBlock;! Most core plugins have a custom annotation class - you have to use the right one for your plugin! The annotation class provides both a documentation of the possible keys in the plugin definition and default values! There is also a generic Plugin annotation class Block Discovery and Annotations 35
  • 36. 36 /**! * Defines a Block annotation object.! *! * @Annotation! */! class Block extends Plugin {! /**! * The plugin ID.! *! * @var string! */! public $id;! ! /**! * The administrative label of the block.! *! * @var DrupalCoreAnnotationTranslation! *! * @ingroup plugin_translatable! */! public $admin_label;! ! //... more properties ..//! }
  • 38. 7.x Info Hook 38 /**! * Implements hook_filter_info().! *! * @ingroup project_issue_filter! */! function project_issue_filter_info() {! $filters['filter_project_issue_link'] = array(! 'title' => t('Project issue to link filter'),! 'description' => t('Converts references to project issues ! (in the form of [#12345]) into links.'),! 'process callback' => '_project_issue_filter',! 'tips callback' => '_project_issue_filter_tips',! 'cache' => TRUE,! );! return $filters;! }
  • 39. 39 /**! * Provides a filter to format a node ID as a link.! *! * @Filter(! * id = "mymodule_node_link",! * module = "mymodule",! * title = @Translation("Format a node ID as a link")! * )! */! class NodeLinkFilter extends FilterBase {! public function process($text, $langcode) {! $regex = ‘(?:(?<!w)[(#d+(?:-[d.]+)?)](?!w))|…’;! $callback = function($matches) { ... } ! $text = preg_replace_callback("/$regex/", $callback, $text);! return new FilterProcessResult($text);! }! ! // ... more code ...//! ! public function tips($long = FALSE) {! return $this->t('Node ID numbers (ex. [#12345]) turn into links automatically.');! }! } 8.x Plugin With Annotation
  • 40. 40
  • 41. 41
  • 42. 42
  • 43. 43
  • 44. 44
  • 45. You want to upgrade your module to Drupal 8 and it defined an info hook or had a ctools plugin type ! Use annotation based discovery by default! It keeps the meta-data together with the class and is suited for typical plugin types where the actual class (code) is different for each plugins! YAML discovery is good for a case like local tasks where the vast majority use a common class, but a few will implement a different one (for example, to provide a dynamic title) Creating Your Own Plugins 45
  • 46. Demo code used for this presentation:
 drupal.org/sandbox/pwolanin/2087657 ! Converting 7.x modules to 8.x 
 drupal.org/update/modules/7/8! Plugin API in Drupal 8
 drupal.org/developing/api/8/plugins! Why Plugins? drupal.org/node/1637614! Unraveling the Drupal 8 Plugin System drupalize.me/blog/201409/unravelling-drupal-8- plugin-system Plugin and General 8.x Resources 46
  • 47. Widespread use of interfaces makes it easier to replace almost any implementation! Tabs are grouped regardless of path hierarchy! Route name rather than system path is unique! Multiple routes can serve the same path (HTML vs. JSON or GET vs. POST)! YAML as a standard for config and data files! Multiple instances of the same block! Each block instances has a config entity Drupal 8 Features I Mentioned 47
  • 48. Plugins are a way to combine the discovery of available functionality with the actual implementation of the functionality! In Drupal 7, the combination of an info hook and multiple other hook functions (potentially in different files) served the same purpose! When defining your own plugins, use Annotation- based discovery unless you have a very clear reason for a different type To Sum It Up Licensed: http://creativecommons.org/licenses/by-nc-sa/2.0/ This presentation is © 2016, Acquia, Inc.