building rednoseday.com on drupal 8
TRANSCRIPT
Building rednoseday.com on Drupal 8
Peter VanheeTech Lead at Comic Relief@pvhee
DrupalCamp London 2017
• Comic Relief strives to create a just world free from poverty
• We raise millions of pounds through two big fundraising campaigns – Red Nose Day and Sport Relief.
• We spend that money in the best possible way to tackle the root causes of poverty and social injustice.
• We use the power of our brand to raise awareness of the issues that we care most about.
Who am I?
• Tech Lead at Comic Relief https://technology.comicrelief.com
• Founder of Marzee Labs, a tech shop from Barcelona @marzeelabs
• Long-time Drupal contributor @pvhee
Drupal at Comic Relief
• 2014: comicrelief.com
• 2015: 2015.rednoseday.com
• 2016: sportrelief.com
Drupal at Comic Relief
• 2014: comicrelief.com
• 2015: 2015.rednoseday.com
• 2016: sportrelief.com
• 2017: rednoseday.com
A fresh start?
• Build a campaign website
• Build a product that can build campaign websites
• Build a product that allows editors to reorganise row components to build a website
• Continuously iterate over our codebase
A product should…• support iterative development
• have a clear versioning scheme
• have tests to guarantee quality
• provide a sensible default start for any campaign
• allow for customisation
Technology Choice?Drupal 8, because of
• embracing industry PHP standards
• built on top of Symfony, use of Twig and Composer
• editorial features “out of the box”
• accessibility features
• built-in REST capabilities
• a development challenge
You can’t be that kid standing at the top of the waterslide,
overthinking it. You have to go
down the chute.Tina Fey
Ingredients to build our product
• Focus on Editor Experience
• Automate and streamline
• Decoupled services
Editor Experience
Landing pages as the norm
• First iteration: panels with panelizer
• Second iteration: panels with panelizer and embedded paragraphs
• Third iteration: paragraphs with block reference
Header with Menu
Footer
Paragraph 1
Paragraph 2
Paragraph 3
Paragraph n
… library of blocks
custom blocks (like email signup)
Editorial blocks
Paragraph types
“content wall”(rows + teasers are blocks)
Cards
blocks are reusable
paragraphs are not reusable
QuotesEmbed
Node Block reference
BLOCKS
PARAGRAPHS
reusable
not reusable
libraryquick editcontextual links
only editable via nodeno quick-edit
(see node …)
content fields
layout fields
refe
renc
e
Living Style Guide
Living Style Guide
• Using KSS, “a documentation syntax for CSS”
• Our new “incubation area”
• Code and style guide are one — no need to update one or the other independently thus guaranteeing it stays fresh!
Style-guide driven development
Component idea
Style Guide(or Pattern Lab)
HTML, SCSS, JS
ReviewMulti-device QA
Sign-off
Drupal development
Content modelView modes
Component moduleTwig / PHP
Improved editor experience
Red Nose Day 2015(Drupal 7)
Red Nose Day 2017(Drupal 8)
Automate & streamline everything
A build in one step
• Package up our website product using an installation profile and using CMI, via config_devel
• Default content in JSON
• Use a build tool — we use Phing and run phing build often
Config modules
Collaborative coding
No automation without tests
• Code quality checks using CodeSniffer, phpmd, phpcpd
• Configuration checks using config_devel
• Distribution installation tests using phing build
• Behavior tests on distribution using Behat
• Drupal log checks (no errors, warnings generated by Behat)
• Visual regression tests using BBC Wraith
BehatBehat tests
Continuous Integration
Preview branches
Decoupled services
Slide from Chet Haase
Minimise custom code
• we have around 2000 custom lines of PHP code (options callbacks, custom Display Suite fields, Solr tweaks)
• “Non-glue code” is contributed back as standalone Drupal modules: rabbitmq, social_links
The Embed Pattern
The Queue Pattern
Producer = Drupal Queue Consumer = 3rd party
an example: email list subscription - Producer: Email Signup Form- Queue: holds email address, template ID, etc.- Consumer: PHP / nodejs app talking to MailChimp
Drupal Producer/** * Our signup form. */ class ExampleForm extends FormBase {
public function buildForm(array $form, Form…face $form_state) { $form['email'] = [ '#type' => 'email', '#title' => $this->t(‘Your email address.'), ]; $form['show'] = [ '#type' => 'submit', '#value' => $this->t('Submit'), ]; return $form; }
public function submitForm(array &$form, Form…face $form_state) { // Get the data you want to send to the queue. $data = $form_state->getValue('email');
// Get the queue config and send it to the data to the queue. $queue_name = 'queue1'; $queue_factory = \Drupal::service('queue'); $queue = $queue_factory->get($queue_name); $queue->createItem($data);
// Send some feedback. drupal_set_message( $this->t(‘Added data to queue @queue: @email', [ '@queue' => $queue_name, '@email' => $form_state->getValue('email'), ]) ); }
}
// Our rabbitmq.config.yml configuration exchanges: my_exchange: type: 'direct' passive: false durable: true auto_delete: false internal: false nowait: false
queues: my_queue: passive: false durable: false exclusive: false auto_delete: true nowait: false routing_keys: - 'my_exchange.my_queue'
// Add to settings.php $settings['queue_service_queue1'] = 'queue.rabbitmq';
rabbitmq module at drupal.org/project/rabbitmq
using Drupal 8 Queue API
RabbitMQ Queue
3-rd party Consumerclass QueueConsumer implements ConsumerInterface { /* @var \stdClass */ private $processingService;
/** * Parse message as JSON and send to processor * * @param AMQPMessage $msg * @return bool */ public function execute(AMQPMessage $msg) { if ($decodedMessage = json_decode($msg->body)) { try { return $this->processingService->process($decodedMessage); } catch (\Exception $e) { $this->logger->alert(‘Queue process error:' . $e->getMessage()); } } else { $this->logger->info(sprintf('Unable to parse as JSON: "%s"', $msg->body)); } return false; } }
Towards micro-services
• oEmbed / iFrame for integrating 3rd-party apps in the CMS
• Message Queues for decoupling logic
What about rednoseday.com?
From product to websitecampaign distribution- v1.1 - … - v1.36- … - v2.x
rednoseday.com
comicrelief.com
rednoseday.org (USA)
sportrelief.com
From product to websitecampaign distribution- v1.1 - … - v1.36- … - v2.x
rednoseday.com- campaign v1.36 as dependency - env vars (queue info, db info, …)- RND17 theme- YML site configuration sites/default/config
- composer / make- hook_update - drush config-devel-import
comicrelief.com
rednoseday.org (USA)
sportrelief.com
you?