Feeds

Author

Oct 19 2018
Oct 19

Where this really becomes frustrating is when you have a pattern that lists a number of items in an array. In that case, all variants will have (at least) that many items, even though you may want fewer.

For illustration:

list.twig has something like this:

Then list.yml has something like this:

Now you want to create a variant of list such as list~related-articles, but with only 2 items. You'd expect this would work

But, no. This will still render as many items as were in the parent component. That's the beauty (a feature, not a bug) of PatternLab's inheritance system. To stop it you need to do something like this:

When we do this with a component such as a card, we might also want to have variants such as card~no-image, card~no-text, etc. In this case, we'd have a card.yml like so:

However, if we create variants, each of the items in card will be inherited to the variant. You'll notice this if you try to create one super mega component for all variants of a hero component for example (hero title, pre-title, sub-title, image, alignment, cta buttons, etc).

In this case, what I do is create a default component card.yml or hero.yml and give it only values for items that will more than likely be in all variants (basically whatever you are going to mark as a required field in Drupal (or whatever CMS you are using)), then set all others to 'false' in the component. Now when I create variants I only need to override the specifics for that variant, since everything else that is being inherited is already set to false. I also create a 'Kitchen Sink' version of the component which shows every item in action but DO NOT create this as the default/reference component.

My default card.yml might look like this:

Now my variants can look as simple as:

And card~long-title will be just one line:

And that is why this is a feature, not a bug - it allows us to write variants very simply and quickly. Is there a better way of doing this? I'm not aware of one. If you are, drop it in the comments. Thanks.

Sep 22 2018
Sep 22

What would make for a first-class, enterprise-ready, front-end development team?

Regular Structured Communications

There can be a tendency to presume everyone knows what they are doing and should be allowed to work on their own initiative. This is a tendency I agree with, but it’s also of utmost importance to make sure others on the team also know what each person is working on.

Without regular, structured communications (at least weekly, if not daily, meetings), it’s quite possible for one person to work on a component (say a “tile” component) while another person works on another component (say a “card” component) and both of these components to be the exact same item. Except now we have two versions of the same component, just different names for them.

Without regular, structured communications, each team member is working in a silo, not aware of the whole of the project, and being responsible for only their section. This makes it harder to integrate each section of the site into each other. It will also mean it takes more time for the diligent developer to understand each part of the project if they wish to. Regular meetings save time.

One of the great things about regular, structured communications is that they lend themselves very well to team building. Let your team know you are very proud of how much has been achieved this sprint. Congratulate someone for solving a particular tricky issue. Allow a space for people to vent any issues they might be having.

Fewer Developers, More Focussed

It’s a truism and a paradox, but the more developers we have on a project, the longer the project is going to take to complete. Every new developer takes time to get up to speed with the codebase and slows down the momentum of the other team members. This causes projects to go over-time and over-budget.

This is not to say we should have only one developer per project, but I would suggest keeping teams as small as possible. A small number of really focussed developers will work much faster (having such an intimate knowledge of the codebase, feature set, sprint goals, etc.) than a large team of developers working on many small features. A large team lends itself too easily to people changing someone else’s code not expecting there to be any ramifications, to people “fixing” up another’s code because it doesn’t meet coding standards or has a security issue – work that shouldn’t have to be redone.

Use a Design System/Pattern Library

Pattern library tools have become very popular in the past few years. They allow everyone to see an inventory of the different components the team has available to work with when building web pages.

The tool I have chosen to standardise on is PatternLab. There are many others. Check out the responses to this Tweet to see what other people are using:

They also allow us to show our clients what the designs will look like on real devices, rather than images of what they might look like in InVision or some other tool like that. For years, yes literally years, I’ve been talking at conferences extolling the virtues of using a ‘Design in the Browser’ approach to front-end development and against the practice of using static design tools (Photoshop/Sketch) to deliver designs to clients. By all means, use these tools to deliver the designs to your team, but let the team code up the designs to deliver to your client.

Clients should be sent URLs, not PDFs.

One Component Per Design Feature

Once we are all agreed that we are going to use a pattern library tool, we can then start coding up the features of the front-end. Often components have variations of themselves. An example could be a “Card” component which has an image at the top, followed by a headline; with a variation which has the headline on top followed by the image. In this case we might create a card component and also a card—reversed component.

Card and Card Reversed Wireframe

Sometimes teams can fall into the trap of thinking that “everything” is a variation of a core component. So, for example, we might have a component which has an image on the left, a headline and some teaser text on the right and/or vice-versa. Surely we can just create a component variation such as card—columns and card—columns-reversed? Yes, we can. But then when we see another component that has the same layout, except the image is a different size, there is no teaser text, we have tags under the headline, etc., we are then going to need to make another variation of card— and yet another variation of card— and yet another variation of card— and so on. Technically this is possible, but in practice you are setting yourself up for a maintenance nightmare.

Column and Column Reversed Wireframe

The reason each of these components might look like variations on a core component is because they designers are following brand guidelines and using the same font, same sizing and rhythm rules, same colour scheme, etc. When you think about it like that, everything should look similar – it’s all supposed to fit together, but that doesn’t mean everything is a variation of a core component.

If we want to create all the variations of display types based off one core component, we are going to have a large core file, with a lot of logic and clauses and “if this then that” statements, and an equally large CSS file to take consideration of all the variations. This makes it harder to read the code, harder for new developers to get on-boarded to the project, and harder to maintain.

My suggestion is to create one component per display type. Based on the examples above, we would have a card component and a columns component. My files in PatternLab might look like this:

/card
– card.twig
– card.js
– card.scss
– card.yml
– card~reversed.yml
– card~
no-teaser-text.yml
– card~
no-teaser--text-reversed.yml
– card.md

/columns
– columns.twig
– columns.js
– columns.scss
– columns.yml
– columns~reversed.yml
– columns~
no-teaser-text.yml
– columns~
no-teaser-text-reversed.yml
– columns.md

This means that all the functionality and styling for the card component is within the card directory. It’s a small core file, with only variations for the image to be top/bottom or for there to be teaser text/no teaser text – very obvious variations of the card. The core file should be easy to read (one CSS class will create the variations), and it’s specific enough to know exactly what this component does.

We can set up a regression test for each component very easily to catch any curveballs that might arise later. None should arise if we use correct BEM naming conventions so that all styling for .card is prefixed with .card and all styling for .columns is prefixed with .columns, like so:

.card { css for card container }
.card__image { css for the image in the card }
.card__headline { css for the headline in the card}

.columns { css for columns container }
.columns__image { css for the image in the columns }
.columns__headline { css for the headline in the columns}

Focus on Features, Not Breakpoints

The Unix philosophy says “do one thing, do it well”. Taking this as a guiding principle, we should focus on developing one feature and completing it (the “card” component, for example) before moving to the next one. Sometimes I talk with teams and they tell me they focus on the desktop first or on the mobile screen views first and try to get the whole website looking correct at one breakpoint before moving on to the next one. While much of the code might be fine for each breakpoint, going over the code to catch all the issues for other breakpoints is going to take longer than completing each feature and having them signed off.

Remember, signed-off features can have regression tests written against each breakpoint. It also means that if the site is going to go over time, it’s possible to launch with a smaller set of (completed) features, rather than a feature-complete website, the front-end of which does not meet all the brand guidelines.

Automate Code Quality

Following coding standards can take time. You write your code, you check back over it, you fix up the indentation and comments style. And – you still miss something. The simple fix? Using code sniffers and/or linters and/or combing tools to automate this for you.

I have CSSComb set up in all my projects, so every time I save a CSS or SCSS file, it’s automatically formatted to follow the (Drupal) coding standards. I use prettier for my JS files, so again, each time I save my file, it’s automatically formatted to meet our coding standards. I have php_codesniffer installed and set to (Drupal) coding standards, so it notifies me each time I have an indentation wrong or something like that.

Why is this important? This is important when working as part of a team to make sure everyone’s code looks the same. It makes it much easier to read code from other developers when it is formatted the same as your code. It’s even more important when you edit a file that someone else has worked on and then try to commit those changes to git. How many of the changes were changes you made (that actually affect the code) and how many were just the csscomb or prettier auto-formatting your code? You want your git commits to be meaningful, so you only want the commit to announce the changes you have made.

What I do now on any file I need to work on is save it the moment I open it, so if another developer doesn’t have automated code checkers built-in, the file will format itself. Then I commit this save with the git commit message “running csscomb” or “running prettier”. After this, I make my changes and my commits are then meaningful – I can see the actual code I changed. This takes more time that it would if everyone just installed code formatting tools from the outset, and is something I think we should insist on for every project.

Front-end in Tandem with Site Building

The chances are that the designs are going to be sent to the client as Sketch files or PDFs or similar and not as PatternLab URLs (despite my best efforts to encourage this for years). Or maybe another agency won the contract to design the website and our agency won the contract to build/maintain it. If this is the case, by the time they get to the front-end developers, they are signed-off – a fait accompli.

Let’s turn this into a positive. As we are creating our front-end components (one component per design pattern, please!), we should also be building out the CMS functionality that this component will use. So, if we have a listing page showing teasers of events in a card display, then we should build out the fields (in Drupal or whatever CMS we use) that support this, and then create the configuration and templates needed to map 1-to-1 from Drupal to PatternLab.

This allows us to “dog food” our own work very early on. We can create our front-end and backend in tandem and make sure that both work seamlessly. We can ask our clients to sign-off on the front-end and CMS features at the same time; and we can then set up regression testing for the front-end and functional testing (with Behat or something else) for the backend. As the project progresses, we will have a featured-complete, fully-tested website and can move from feature to feature (or new feature to new feature during future phases of work) with less fear of things breaking when we make changes.

Regression Test

Here’s a joke: a css selector walks into a bar; a table in another bar across town falls over.

Writing front-end code can often be like playing Whack-A-Mole. It doesn’t have to be.

Regression testing is basically taking a screenshot of your website that you can use as a “reference” (this is what it is supposed to look like). Then, when you make a change, you can take automated screenshots of the site again to make sure that the only things changed were things you expected to change. The regression testing tool I use is BackstopJS.

An example: you have a header, a main content area, and a footer. You set up your reference shots when these are all signed off by the client. In a future sprint you are asked to change the main content area from 1220px wide to 1440px wide on desktops. You make the change, tell your regression testing tool to run the tests and then you get back a report showing you that the main content area is now wider than the header and the footer – as it should be. You see the header and footer were not affected so you can deploy this new item. Now, think about doing this for every component across your website! The regression testing suite will run all the tests in a matter of minutes (while you can be happily working on another feature – multitasking for the win!), whereas it could take you an hour to check everything and you might miss something.

Like automating code quality, automate regression testing: automate the boring things.

BackstopJS Regression Testing Report for Mark.ie

Set Time Limit for Being Blocked

If a developer is blocked on something and can’t figure out how to complete the task, that is time wasted. Developers need to know they can ask for advice and they need to know whom they should ask – probably the gatekeeper (see next section).

My general rule of thumb for this is: if I feel I am blocked and just looking at the screen for 15 minutes, I need to ask for help. If I haven’t an idea what to do to unblock myself and I’ve thought hard about it for 15 minutes, that’s enough of the company’s money spent on it.

Ask for help sooner rather than later so you can be as productive as possible.

Nominate Code Gatekeeper

If you need to have a large team of developers, you need to have a code gatekeeper: someone whose job it is to know what components are developed, what ones are in progress, and what is in the backlog.

The gatekeeper also needs to know who developed what component and in what manner, so any components that are re-usable are re-used and one-off components are kept to a minimum. It is the gatekeeper’s job to ensure that no component is developed more than once, just using different names (“card” and “tile” as we saw above).

When someone is blocked or unsure of something, they ask the gatekeeper for advice and guidance so they can continue working as soon as possible. As well as that, the gatekeeper can also step in and try to figure out a solution (or even a proof-of-concept for a solution) while the developer works on something else. When the gatekeeper has an approach figured out they can tell the developer about it and then the developer can get back to that feature as soon as possible. The gatekeeper is a pair of fresh eyes.

The gatekeeper might be the lead developer on the project or it could be a separate role. The gatekeeper should write as little code as possible for the actual production version of the site, and, rather, should focus on the high-level overview of the project and working on solutions to unblock developers.

Conclusion

That’s it. That’s my thoughts on putting together and running a front-end (or teams) that can effectively work on large, enterprise websites. If you have a small team or are a freelancer, I think what I have said above also holds true.

Any thoughts or comments, leave them below. Thanks.

Sep 20 2018
Sep 20

Responsive images in PatternLab get a bit of a bad rap sometimes, because they are tricky to have in PL and Drupal. Here's my "easy way" of achieving it.

This came up today in the DrupalTwig Slack (join it). A user wanted to know how to use responsive images with the Emulsify Drupal theme. I don't use the Emulsify theme (yet - I will soon), though Four Kitchens, the geniuses who created it, have responsive images built in. Recently I created my own - simple and rudimentary, but it works a treat.

I first create a "Responsive Image" pattern. In this I have two files - responsive-image.twig and responsive-image.yml. Here's the contents:

responsive-image.twig:

<img srcset="{{ image_src_sets }}" sizes="{{ image_sizes }}" src="https://mark.ie/blog/web-development/responsive-images-patternlab-and-dr...{{ image_src }}">

responsive-image.yml:

image_src_sets:
  join():
    - 'https://placeimg.com/500/500/nature 500w, '
    - 'https://placeimg.com/1000/750/nature 1000w, '
    - 'https://placeimg.com/1440/475/nature 1440w'

image_sizes: '(max-width: 600px) 100vw, (max-width: 960px) 100vw'

image_src: ''https://placeimg.com/1440/475/nature'

To use it in another component, I just call a variable and set that variable in the YML file.

For example, to call the hero image as a responsive image in my event component, I'll print this: {{ hero_image }}. Then in my corresponding event.yml file, I'll define the hero_image item like so:

hero_image:
  join():
    - include():
        pattern: 'basic-elements-responsive-image'
        with:
          image_src_sets:
            join():
              - 'https://placeimg.com/600/600/tech 500w, '
              - 'https://placeimg.com/1200/360/nature 1000w'
         image_src: 'https://placeimg.com/1200/360/nature'

The {{ image_src }} variable is needed to provide a default fallback for browsers that don't support srcset or sizes, such as IE9/10/11.

Then in my Drupal template I just swap my image field variable for the responsive image one, like this:

{% if node.field_hero_image.value %}
  {% set hero_image: content.field_hero_image %}
{% endif %}
{% include ... usual path to component stuff ... %}

Drupal then renders the image field using whatever settings I have given it in Drupal - presumably responsive image ones.

This post might not help you if you are using Emulsify, but it might help others who stumble upon it.

Sep 08 2018
Sep 08

Here's the task - create a card component with fields for:

  1. Card Image
  2. Card Title
  3. Card Body
  4. Card Link URL
  5. Card Style (sets a colour for a border-top on the card)
  6. Card Size (sets the width of the card)

In PatternLab, here's what our Twig file might look like (with explanations after it):

The classes array at the top allows us to set variations for our card, depending on values chosen by the editor. So, if there is an image, we add a class of .card--has-image; if a style is chosen, we add a class of that style, for example: .card--medium (I create options for small, medium, large, and full - with 'small' being the default - corresponding on large screens to a width within their container of 33%, 50% 66% and 100% respectively).

Next, we set our {{ element }}. This allows us to have the card wrapped in an a tag or a div tag. We check to see if the link field has been filled in and, if so, we use the a element, but if not, we use the div element instead. This will render HTML like one of the following:

Following this, we check if there is an image and, if so, we render our image div. Checking first allows us to have nice bem-style classes, but also means we don't end up rendering emtpy divs. Although, when it comes to Drupal, what's another div!

We then do the same for the title and body.

The funny looking part at the end about cache was inspired by an article about Drupal block cache bubbling by PreviousNext. The specific code came from this Drupal.org issue. The PreviousNext article says to render the {{ content }} variable with our fields set to 'without', because without the {{ content }} variable rendering, caching is not working properly (I don't know enough about caching to explain more). However, on a content type with loads of fields, it's very cumbersome to add every field in with {{ content|without('field_image', 'field_tags', 'field_other', etc) }}. Instead, I put that {{ catch_cache = content|render }} at the bottom of each of my content patterns - node, block, paragraphs, etc, then don't need to add it later in Drupal.

The SCSS for this looks like this:

We can do the site building very easily with the paragraphs module. Create a paragraph of type card, add the fields

  1. Card Image - media image
  2. Card Title - text (plain)
  3. Card Body - text (long, formatted)
  4. Card Link URL - link
  5. Card Style (sets a colour for a border-top on the card) - text (list)
  6. Card Size (sets the width of the card) - text (list)

Then, in our paragraph--card.html.twig file, we write the following code:

What the above does is checks if the card paragraph has values in its fields and then sets variables if it does. This means we don't render empty divs.

You will also notice that I render each field's full content for image, title, and body. This is to keep all the Drupal goodness we have in the attributes object - for accessibility and to make sure things like contextual links/quick edit still work.

You will often see the same template written like this:

I find doing that leads to fields such as {{ content.field_image }} always returning true because of Drupal's rendering system. So, even if we don't have an image, we'll still have an image div, whereas doing an explicit check before we {% include %} our variable seems much safer.

That's it - PatternLab + Drupal integrated beautifully (I think) the "right" way (according to me - you might differ).

===

You can see a sample of this in action on this site's PatternLab.
Note - I call cards in my PatternLab 'tiles' and make them part of a wrapper component called 'Tiled Layout', which allows me lots of flexibility for cool layouts with little effort.

Jul 28 2018
Jul 28

You know the scenario - you want to list nodes that have the same taxonomy term(s) as the node you are currently viewing. Easy, but you also want to exclude the currently-being-viewed node from the list. Always trips me up.

Each time I have to do this, I read a blog or two or a Drupal issue or two and still I always end up with a quirk. Here's what I normally do:

  1. Create the view
  2. Add a contextual filter for the taxonomy field you want to filter by
  3.  Provide default value
  4. Taxonomy term ID from URL
  5. Load default filter from node page, that's good for related taxonomy blocks
  6. Limit terms by vocabulary
  7. Click Apply

Now I'm Stuck

This gives you a list of nodes related to the current one, but the current node will always show up in your list. If you edit that contextual filter and expand the 'More' tab at the end, and then choose 'Exclude: If selected, the numbers entered for the filter will be excluded rather than limiting the view.' you will be forgiven for thinking this will exclude the current node. IT WON'T. In this case, it will exclude the currently selected taxonomy term - which is the opposite of what you want to do.

The Solution? Another Contextual Filter

  1. Create another contextual filter for 'ID', as in, the Node ID.
  2. Provide default value
  3. Content ID from URL
  4. Scroll to bottom of page and expand the 'More' tab
  5. Click Exclude: If selected, the numbers entered for the filter will be excluded rather than limiting the view.

Now, the second filter will exclude the currently-being-viewed node, while the first filter will do the related-node-taxonomy-magic-dance.

Jul 17 2018
Jul 17

Working my way down through one of Drupal's render arrays of doom to try to get the URI of a file in a media field (in a paragraph type), I came up with this. If you can improve it, feel free to drop a note in the comments:

{% set slide_url = file_url(content.field_p_ei_speaker_slides[0]['#media'].field_m_file_file.entity.uri.value) %}

In steps:

  1. Get the {{ content }} variable
  2. Drill down into the media field (Speaker Slides - pdf, ppt, etc)
  3. Get the first element (0 - it's not a multi-value field in this case)
  4. Load up the #media object
  5. Interrogate the field on the media entity that has the file attached (the File field)
  6. Load this entity (entity here is not presented as an item in the {{ dpm() }} but it's very handy to know
  7. Get the uri.value from here
  8. Wrap it all in a file_url() function

For clarity, here's what I had in PatternLab:

  {# Begin Slides Download #}
  {% if event_slide_download %}
    <div class="event-item__slides">
      <a href="https://mark.ie/blog/web-development/getting-value-uri-drupal-media-file...{{ event_slide_download_link }}">
        {% include '@basic-elements/icons/_svg.twig'
          with {
            svgpath : '@basic-elements/icons/svg/download.svg'
          }
        %}
      </a>
    </div>
  {% endif %}
  {# End Slides Download #}

And here's what I have in the corresponding Drupal paragraph.html.twig tempate:

{% if paragraph.field_p_ei_speaker_slides.value %}
  {% set event_slide_download = true %}
  {% set slide_url = file_url(content.field_p_ei_speaker_slides[0]['#media'].field_m_file_file.entity.uri.value) %}
  {% set event_slide_download_link = slide_url %}
{% endif %}

{% include "@building-blocks/event-section/event-item.twig" %}

So now, my future self, you will know where to find this next time.

Jun 21 2018
Jun 21

I'm a big fan of the quick edit module for Drupal. If it could work better with paragraphs module, it'd be a knockout feature. Aligned with that, I'm really impressed with the settings tray module and can see so many uses for it in the future - sidemenus, shopping cart slideouts, node editing, etc. Here's a very short video of using it to edit a menu, which should make many content editors' lives easier.

Jun 18 2018
Jun 18

Let's revisit my recent post and see if we can come up with more user-friendly names for PatternLab items.

My Approach to PatternLab recently got quite an amount of discussion on Slack and other places about PatternLab and naming conventions, especially the line "Clients do not want a science lesson". In that I set out my current naming convention like so:

  • Basic Elements
  • Site Blocks
  • Building Blocks
  • Content
  • Sample Pages

While generally appreciated, some people criticised it for being too Drupal-centred. What happens if your client doesn't want to use Drupal? What happens if you want to use the same PatternLab instance for an app on Android or iOS? Good questions, and they got me thinking more. A number of people on Slack recently have been asking about what naming conventions besides the atoms > molecules > organisms one people have been using.

I had a verrrrry long chat (over 3 hours) with some developers from outside of my work place to see what what naming convention(s) might make sense, be easy for clients to understand, and allow enough scale to be used outside of Drupal. Here's what we came up with:

  • Utilities
    • Items such as utility classes like .visually-hidden or .padding-top
  • Base
    • Items such as colours and fonts
  • Elements
    • Low level elements such as headings, paragraphs, basic lists
  • Components
    • High definition components such as a teaser view mode, an embedded video component, a list of teasers
  • Layouts
    • General layout classes for the different page designs - with sidebar, without sidebar, etc
  • Mock-ups
    • Rendered 'pages' or other UI interfaces
    • We shied away from 'Pages' here because not everything might be a page, such as a login screen on an iPhone app

I'm quite happy with those naming conventions and think I might start porting some of them to my work at Annertech. (Oh, and by the way, if you want to get really good Drupal developers to work on your website, we're available for hire - contact us!)

May 18 2018
May 18

When working with PatternLab, which I use for all my Drupal themes, including the theme for this website, I don’t use the full atomic approach. I don't use the approach of atoms > molecules > organisms > etc. I’m sure many people seriously disagree with me for that ( I do think it's a very clever concept). Instead I’ve renamed things to match the language we use with our clients.

I tried talking about atoms and molecules to some clients and their eyes glazed over. Clients do not want a science lesson. They do not want to be told that we are going to take two of these atoms, and mix them with one of these atom, and eventually we'll have water. No, they want to know what their final website is going to look like. When I changed the conversation and started talking about ‘Building Blocks’ (what we call our Drupal paragraph types), site blocks (Drupal's search block, branding block), display types (Drupal's view modes such as teaser, search result), etc, they immediately understood. Then we started hearing things like, "Oh, so we can create a page by adding a number of different building blocks?" and "I see, so the search results page is made up of a group of pages using the 'Search Result' display type?". And my response, "Yes!". You see, we are using plain English to ease with understanding.

Another aspect of my approach that I really like is that _everything_ for each of my components is within the same directory. For example, if it’s a nested paragraph component such as an accordion (so we need a paragraph type called 'Accordion' and one called 'Accordion Item') each template and css and js and readme and json and yaml is all in the same folder. That means when I want to reuse one in another project, I don’t need to remember what sub-particles (atoms/molecules) are used to create the organism. It also means my CSS is scoped to that specific component and doesn’t bleed out of it, so making changes or adding new features is very easy, you just scope the new component's CSS to it, so it won't affect other previously-created components.

Now the top bar of my PatternLab that used to say Atoms | Molecules | Organisms, etc has tabs for:

  • Base
    • Colours
    • Spacing
    • Breakpoints
  • Basic Elements
    • Headings
    • Paragraphs
    • Lists
  • Site Blocks (Drupal Blocks)
    • Search Block
    • Login Block
    • Branding Block
  • Building Blocks (Paragraph Types)
    • Accordion
    • Image with Text
    • Video
  • Content
    • Display Types (View Modes)
      • Teaser
      • Card
      • Search Result
    • Lists (Views)
      • Blog
      • Search Results
    • Content Types
      • Basic Page
      • Blog
      • Event
  • Page Sections (Regions)
    • Header
    • Footer
    • Sidebar
  • Sample Pages
    • Homepage
    • Blog Listing Page
    • Blog Node

After that, I have Backstop.js set up to regression test all of these, so each time I create a new component I can quickly run the visual regression tests and check that nothing has broken. Since all my CSS/JS is scoped to each individual component, it's rare if something is.

Apr 25 2018
Apr 25

Mission: you have 2 fields in a Drupal paragraph bundle, one a node reference field and one a boolean field. Show certain fields in the referenced node depending on the value of the boolean field.

That's a question that popped up today in the DrupalTwig Slack. Here's my response, which I implemented a version of recently.  (In that particular case, we had an 'Event' content type with fields for 'address', 'phone number', etc and also a reference field for 'Amenity'. If the fields were filled in in the event content type, they were to be presented, but if they were left blank on the event content type, we had to pull in the corresponding fields for address, phone number, etc from the referenced amenity.) Anyway, my response:

{# Check the value of the boolean field #}
{% if paragraph.field_boolean.value === 'on' %}
  {# Just render the title of the referenced node #}
  {{ paragraph.field_reference.0.entity.label }}
{% else %}
  {# Render the title and the image field #}
  {{ paragraph.field_reference.0.entity.label }}
  <img src="https://mark.ie/blog/web-development/showing-fields-referenced-node-depe...{{ file_url(paragraph.field_reference.0.entity.field_image.url) }}" alt="{{ paragraph.field_reference.0.entity.field_image.url }}">
{% endif %}

{# Ensure that the cache contexts can bubble up by rendering the {{ content }} variable #}
{{ content|without('field_boolean', 'field_reference') }}

Just for clarity - variables in that code snippet are simply made up off the top of my head (this is what happens when answering questions on Slack). I'm sure I have things slightly wrong and you'll need to play with them to get them to work correctly.

Also, the reason for the cache contexts bit? Say thanks to Lee Rowlands from Previous Next for his blog post Ensuring Drupal 8 Block Cache Tags bubble up to the Page

Apr 16 2018
Apr 16

Ever gotten this error: User error: “attributes” is an invalid render array key? Here's what I do to get around it. If you've a better solution, let me know.

When building PatternLab-based Drupal themes, I try to get the Twig in PatternLab to match what I expect from Drupal. So, if I know Drupal has a line like this in its node.html.twig:

<article{{ attributes.addClass(classes) }}>

I want to be able to put the same thing into my PatternLab template - even though I am not going to use the {{ attributes }} in PatternLab. This means then I can simply let the Drupal template extend from the PatternLab one and not need to worry about anything.

However, when you do this, you will often get an error to say "attributes” is an invalid render array key. How do I get that error message to go away? Simple - I just add attributes to my Pattern's .yml file, like so:

attributes:
  Attribute():
    class:

Note: to use this, you need to have the plugin-data-transform by @aleksip (thanks to Aleksip for pointing this out to me on Slack). This can be added to your composer.json require-dev section:

"aleksip/plugin-data-transform": "^1.0.0",

The data.json File

You can do this for each individual pattern, but then you might get an error somewhere else talking about "title_attributes” is an invalid render array key. To get around all these errors, I simply add these items globally to the default data.json file, like so:

  "attributes": {
    "Attribute()": {
      "class": []
    }
  },
  "content_attributes": {
    "Attribute()": {
      "class": []
    }
  },
  "title_attributes": {
    "Attribute()": {
      "class": []
    }
  },
  "rows": {
    "Attribute()": {
      "class": []
    }
  },
  "teaser": {
    "Attribute()": {
      "class": []
    }
  }

The PatternLab Teaser Twig File

Taking the teaser view mode as an example, here's what my PatternLab twig file looks like:

{%
set classes = [
  'node',
  'node--type-' ~ node.bundle|clean_class,
  node.isPromoted ? 'node--promoted',
  node.isSticky ? 'node--sticky',
  not node.isPublished ? 'node--unpublished',
  view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
]
%}
<article{{ attributes.addClass(classes) }}>

  {% if display_submitted %}
    <footer class="node__meta">
      <div class="node__meta--item node__meta--published">Published: {{ node.created.value|date("D d M Y") }}</div>
    </footer>
  {% endif %}

  {{ title_prefix }}
    <h2{{ title_attributes.addClass('node__title') }}>
      <a href="https://mark.ie/blog/web-development/adding-attributes-drupal-patternlab...{{ url }}" rel="bookmark">{{ label }}</a>
    </h2>
  {{ title_suffix }}

  {{ content.field_intro }}

</article>

The PatternLab yml (or json) File

Here's the corresponding .yml (or .json) file:

node:
  bundle: article
  isPublished: true
  created:
    value: 1511941986
  changed:
    value: 1512127363

view_mode: teaser

display_submitted: true

label: 'A Blog Post by Mark Conroy, all about PatternLab and Drupal'

content:
  field_intro: <div class="field--name-field-listing-snippet"><p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Curabitur blandit tempus porttitor. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum.</p></div>

The Rendered HTML in PatternLab

This will then print our html like so (notice, no attributes):

<article class="node node--type-article node--view-mode-teaser">

      <footer class="node__meta">
      <div class="node__meta--item node__meta--published">Published: Wed 29 Nov 2017</div>
    </footer>
 
 
    <h2 class="node__title">
      <a href="http://example.com" rel="bookmark">A Blog Post by Mark Conroy, all about PatternLab and Drupal</a>
    </h2>
 

  <div class="field--name-field-listing-snippet"><p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Curabitur blandit tempus porttitor. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum.</p></div>

</article>

The Drupal Template File

Next, my node--teaser.html.twig file is as follows (just one line):

{% extends '@content/01-display-types/teaser/teaser.twig' %}

The Rendered Drupal HTML

And that renders html like so (notice, we have attributes that Drupal will use):

<article data-history-node-id="40" data-quickedit-entity-id="node/40" role="article" class="contextual-region node node--type-article node--promoted node--view-mode-full" about="/blog/web-development/add-slider-your-website-if-you-do-not-want-your-visitors-see-your-content" typeof="schema:Article" data-quickedit-entity-instance-id="0">

      ...

</article>

Full disclosure, I came up with this idea about a year ago after seeing something similar in the Bear Skin theme.

You can see this in action on my PatternLab's teaser pattern.

Jan 19 2018
Jan 19

One of the things most often requested of Drupal has been a better experience "Out of the Box", so that when a new users installs it they see something more positive than a message saying "You have not created any frontpage content yet".

To that end, a strategic initiative called the "Out of the Box Initiative" was set up. I was a member of that team. What we sought to do over the past two years was create a website for a (fictional) publishing company. We decided upon the name "Umami" for a food publishing company, publishing articles and recipes. We went through the full web design process - user stories, validation, requirements gathering, wireframes, design, development ... up to creating what we called the "MEGA Patch". And then submitted about 50 versions of it.

This week we hoped our work would be committed to Drupal 8.5.0-alpha1, but we just missed that deadline. Instead, we had a meeting with the product owners last night to have the final "Needs Product Owners Review" tag removed from the "Create experimental installation profile" issue. Here's the video of that demonstration and meeting:

Following that meeting, the tag was removed and our code was committed to Drupal 8.6.x. This means you'll see it shipping in Drupal in September at the latest, but we hope to get the final beta blockers fixed to have it backported to 8.5.0-beta. If you'd like to help squash some of the bugs, follow these "Out of the Box" issues. Here's the tweet from @webchick (THANKS!) announcing it:

So, what is in this commit?

This commit brings a new installation profile to Drupal. The profile is called "Umami" and has a corresponding "Umami" theme. It creates three content types - basic page, article, and recipe. It has listing pages for articles and recipes, some promotional blocks, a homepage, contact form, and search page. It is a fully-featured (small) website built using only (stable) Drupal core modules.

We are not using experimental modules such as content moderation, layout builder, media, etc. Once they are stable, we hope to bring them into the "Out of the Box" experience as well.

If you'd like to install it, try this link on SimplyTest.me.

Dec 30 2017
Dec 30

It's a fairly common design pattern for clients to request - upload an image, place text beside it, and choose whether we have the image on the left with the text on the right or vice versa. You can see my PatternLab version of it here (I also have an added option to set a dark theme for the background).

PatternLab Image with Text Component

Image Left/Text Right

This is an example of the pattern with the image on the left and the text on the right.

Okay, first off, in my twig file, I have the following:

{%
set classes = [
  'image-with-text',
  'layout-contained',
  paragraph.field_p_it_alignment.value,
]
%}

<div class="image-with-text__bg image-with-text__bg--{{ paragraph.field_p_it_style.value }}">
  <div{{ attributes.addClass(classes) }}>

    <div class="image-with-text__image">
      {{ content.field_p_it_image }}
    </div>

    <div class="padding image-with-text__text">
      {{ content.field_p_it_text }}
    </div>

  </div>
</div>

The only thing that is anyway special here is the paragraph.* variables. I have named them like so because this is what Drupal is going to give me back (since the machine name of those fields is p_it_alignment (I namespace all my entity fields with the first letter of the entity type - in this case the name stands for Paragraph Image (with) Text Alignment). This then allows me to have options in PatternLab for alignment and background style (light/dark). To achieve this, I have the following in my pattern's .yml file:

paragraph:
  field_p_it_alignment:
    value: left
  field_p_it_style:
    value: light

And in my image-with-text~right.yml file, I just need to override those variables like so:

paragraph:
  field_p_it_alignment:
    value: right

Following that, I have variables named content.field_p_it_image and content.field_p_it_text. Again, these are deliberately named like so, because this is what Drupal will give us back after I create a field with those machine names. Again and again, I try to keep my pattern variables in PatternLab the same as what I will get back from Drupal so when I come to adding the Drupal template, it's just one line of code to say "Hi Drupal template, you'll find the code for this file over here!". So, you can decide in PatternLab what the machine name for the Drupal fields is going to be and then get your site-builders to create fields with matching names, or you can ask your site-builders what machine names are being used in Drupal and then use those in PatternLab.

In my pattern's .yml file, I then set those variables like this:

content:
  field_p_it_text: '<h2>A Short Heading</h2><p>Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>'
  field_p_it_image: '<img src="http://placeimg.com/600/600/nature">'

Finally, in our paragraph--image-with-text.html.twig file we have just one line of code:

{% extends "@building-blocks/image-with-text/image-with-text.twig" %}

You can probably guess what the sass looks like:

.image-with-text {
    display: flex;
    &.left {
      flex-direction: row;
    }
    &.right {
      flex-direction: row-reverse;
    }
}

The images with text above and below this post are examples of this pattern in use on a Drupal website.

PatternLab Image with Text Component

Image Right/Text Left

This is an example of the pattern with the image on the right and the text on the left.

Dec 21 2017
Dec 21

I see a lot of blog posts and talks around about the benefits of using component-based design, about how we should use design in the browser principles to present designs to our clients, about how styleguides are the best way to have sustainable frontends. I've even written some and given many presentations about it myself. What I don't see a lot of is blog posts about how to actually do it.

So, here's how to (or at least how I) integrate my PatternLab theme (it's based on the Phase 2 PatternLab Drupal theme) with a simple paragraph type.

PatternLab

Create a pattern - you can put it wherever your setup says it should go. Paragraph bundles are probably molecules, but I'm not sure how you set up yours. In my case, I have hacked PatternLab and created a folder called "Building Blocks" - this is where all my paragraph bundles go (and then I also have a "Building Blocks" field in each content type - more about my set up in another blog post.

Call the pattern something meaningful - in this case, I call mine "Text". Next, we write the Twig for the text pattern. This can be as simple as this:

{%
set classes = [
  "text"
]
%}

<div{{ attributes.addClass(classes) }}>
    {{ content }}
</div>

Then in my corresponding text.yml or text.json file, I put in some sample content, like so (I like yml):

content: '<h2>This is a Level 2 Heading</h2><p>This is a paragraph of text followed by a list. Sed posuere consectetur est at lobortis. <strong>This is strong</strong> while <em>this is emphasised</em> Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Aenean lacinia bibendum nulla sed consectetur. Curabitur blandit tempus porttitor. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Vestibulum id ligula porta felis euismod semper.</p><ul><li>A text item in a list</li><li>Another text item</li><ul><li>A sub-item</li><li>Another sub-item</li></ul><li>A third item in a list</li></ul><h3>This is a Level 3 Heading</h3><p>Followed by some more text. <a href="#">This is a link</a> sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Aenean lacinia bibendum nulla sed consectetur. Curabitur blandit tempus porttitor. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Vestibulum id ligula porta felis euismod semper.</p>'

Drupal

Finally, in my Drupal paragraph--text.html.twig file, I extend the above PatternLab file, like so:

{% extends "@building-blocks/text/text.twig" %}

Yes, there is only one line of code in that file.

Some Explanation

Why do I call my variable {{ content }}? Simple, I know that the default variable in Drupal's paragraph module to print the contents of the paragraph is {{ content }}, so if I give my pattern in PatternLab the same variable name, I won't have to worry about matching any variables. I do not need to do something like this:

{% include '@building-blocks/text/text.twig' with {
  content: text
  }
%}

This will become much clearer when we work with more complex paragraph types in later blog posts.

You can see an example of this pattern in PatternLab here, and the text you are currently reading is an example of it in use in a Drupal template. Simple, eh?

Oct 14 2017
Oct 14

Metatag cannot directly extract an image url from a media field referenced by another entity.

I upgraded my site from Drupal 7 to Drupal 8 this week (yes, that's why it's running on Bartik - a PatternLab developed theme will be installed in time).

This morning I enabled the Metagtag module and set some defaults for page title, description, image, etc. The help notes on the image metatag field says "An image associated with this page, for use as a thumbnail in social networks and other services. This will be able to extract the URL from an image field." This is true, except in my case, all the image fields on the site use the Media Entity module, so they are entity reference fields rather than image fields.

When I put in a token of [node:field_main_image], the result in the outputted metatags was:

<meta property="og:image:url" content="Mark Conroy | DrupalCon Dublin 2017" />

In that case, "Mark Conroy | DrupalCon Dublin 2017" is the name of the referenced media. I needed to output the image field of the referenced media.

After a little trial and error, I came up with this:

[node:field_main_image:entity:field_m_image_image]

which outputs:

<meta property="og:image:secure_url" content="https://mark.ie/sites/default/files/media/images/2017-10/mark_presenting_1.jpg" />

In this case, "field_main_image" is the name of the image field on my content type, and "field_m_image_image" is the name of the image field on my image media bundle.

If you wish to output a specific image style, you can append :default:url to the token like so:

[node:field_main_image:entity:field_m_image_image:default:url]

or

[node:field_main_image:entity:field_m_image_image:large:url]

I hope that helps!

Oct 11 2017
Oct 11

Seems like just yesterday since we held DrupalCon in Dublin, now we're back with our annual Drupal Camp Dublin.

This year's Drupal Camp Dublin has a great line up of speakers from Ireland and abroad, covering such topics as:

  • Building multi-lingual, multi-region websites (Stella Power)
  • Working as a developer with attention-deficit disorder - add (Levi Govaerts)
  • Planning for disruptions (Jochen Lillich)
  • Migrating from Drupal 4 to 5 to 6 to 7 to 8 (Alan Burke)
  • Automating deployments (Luis Rodriguez)
  • Working webform and commerce and paragraphs and display suites and more (Chandeep Khosa)
  • Live debugging a site that's giving issues (Anthony Lindsay)
  • Stop estimating, start forecasting (Mike King)
  • Deploy with Fabric, and test driven development (Oliver Davies)
  • Design in the Browser (yours truly, me, Mark Conroy)
  • Teaching web development at third level (Ruairi O'Reilly)
  • The QA process (Daniel Shaw)
  • Getting started with Docker (Ed Crompton)
  • The new theme coming to Drupal core (Mark Conroy)

And then there's some socials, and our Drupal Ireland AGM, and at least one other talk not announced yet, and ... you get the idea.

The full schedule is available on our website. There are some tickets left (only €20), get them before they are all gone.

Jul 29 2017
Jul 29

You know you want a t-shirt at DrupalCon Vienna, right? I do. read on...

At this year's DrupalCon in Vienna, the Drupal Association will only be providing 'free' t-shirts to people who purchase an early bird ticket (not exactly 'free' when the ticket costs almost €500) - a position I don't agree with (if you can't afford to give a t-shirt in a welcome pack when charging €500 a ticket, there seems to be something drastically wrong with your business model).

After a tweet last night of me sporting a Druid.fi t-shirt that I received at DrupalCon Dublin, I got thinking: how can we do something to make sure everyone gets a free t-shirt? Then I thought, 'why not provide our own'? Heaven knows we all have loads of them.

Today I'm sporting some haute couture from @druidfi pic.twitter.com/hZm4YYDZ4g

— Mark Conroy (@markconroy) July 28, 2017

So, here's the plan. Everyone brings a Drupal-related t-shirt to DrupalCon. It could be one from your company, one from a previous DrupalCon (I've never been to an non-European one so would like one from somewhere else in the world), one from your local DrupalCamp, a DevDays t-shirt, etc. Then, after the Driesnote, while we are all getting into position for the group photo you give that t-shirt to someone of a similar size to you, and they give you they one they brought (if they brought one). Feel free to bring more than one t-shirt to cover those who don't bring any (it might be some people's first Drupal event).

Oh, and by the way, my size is 'medium'!

Apr 07 2016
Apr 07

Mossack Fonseca's 'client portal' (the part where all the information the world is interested in was uploaded) is running on a version of Drupal (7.23) that they haven't updated in over 3 years. We're now on version 7.43.

There was a MASSIVE deal when 7.32 came out as it patched a very serious security hole. If you're site wasn't patched within 7 hours, you could consider it hacked. We had all ours patched within 45 minutes.

Not keeping your website's security update patches applied will get you in trouble.

They still haven't updated their website, so if you wanted to hack them again, you could simply use one of these scripts: https://github.com/…/drupalg…/blob/master/attack/exploit.php

(P.S. I am NOT suggesting anyone should hack them - just illustrating how easy it is - be careful when you trust your sensitive information to others.)

If you're anyway interested, the theme to power their portal cost a whopping $48.

And it seems their server is running on PHP 5.2, which reached end of life over 5 years ago.

Sep 14 2015
Sep 14

As the title says, I am announcing the launching (soon) of the Drupal Showcase Podcast. This will be a forthnightly podcast showcasing the best new Drupal websites.

Each show will be a friendly conversation (lasting approximately 30 minutes) giving participants a chance to share their thoughts on a recent project, how it was built, what others can learn from it, and contributions made to the Drupal community from the project.

The site is complete in terms of functionality, some more theming is needed, and some more interviews need to be added to the backlog. I'm hoping to launch within about 6 weeks.

In the mean time, join the mailing list for updates and/or suggest a website for the podcast, or chat with me at DrupalCon Barcelona about participating in a show.

Thanks, and keep Drupalling!

(Oh, and the website is here: http://dscpc.mark.ie)

Jun 23 2015
Jun 23

Sometimes, when testing an update hook to a Drupal module, you may need to revert it.

For example, you are setting some permissions for a certain role, you run the update but then realise there was another permission you should have enabled. Instead of adding another update hook, you can revert the update you just ran, amend your update hook, and then re-run the update.

Note*: this is only for reversible changes - like adding/removing permisisons; it will fail if the update had created a new field for example.

It's as simple as this SQL query:
update system set schema_version = XXXX-1 where name = 'module_name';

This means, you are telling your database to update the table 'system' using scheme_version 'XXXX-1' (this will be something like 7001 or 7137 or whatever N equals in your hook_update_N() function minus 1, so if the update was hook_update_7138 you would use 7137 where XXXX-1 is), and apply this update to 'machine name of the module'.

Note*: Do not try this unless you know what you are doing. Make sure you have a backup of your database in case things go wrong - of course you do, don't you?

*Note - notes were added from items left in the comments, to bring them to the body.

Nov 06 2014
Nov 06

I love Karl Marx's maxim, from each according to his abilities, to each according to his needs.

I try to live my life along the lines of open source philosophy. Actually, I try to live my life following the tenets of anarchism - no hierarchies, a system of relations towards others built on trust, friendship, helping each other, solidarity, and distributed leadership (if leadership is the right word here).

When I came upon open source software (specifically Drupal), I quickly realised that anarchism and open source software have so much in common. Drupal is distributed, it is without formal leaders (except Dries as project lead - I know, this is a very simplistic reading of Drupal's set up). Developers work in solidarity/cooperation with each other, sharing code and knowledge to build the best product we can. We are friends, we trust each other.

It was inevitable, then, that I would think an organisation such as CoderDojo was such a good idea. Many, many groups around the world. Everyone helping each other to learn. All sharing knowledge. However, living in a small town in rural Ireland, I wasn't sure it would work here - we don't have coders, we don't have a meeting room, we don't ... Hang on. Let's not be negative, let's give it a try.

So tonight, we have our inaugural meeting of Portumna CoderDojo in the local adult education centre. With use of the computer room. And me as mentor. And some more parents as supervisors. And about 20 kids ready to start coding.

This looks workable. And exciting. Wish us luck.

Oct 11 2014
Oct 11

I'm lazy. So I create shortcuts. You should be like me!

When site building in Drupal, I am constantly using the drush si (site install) command to rebuild the site and check that my new feature is working correctly. Whilst this is a great way to get the site re-installed in super-quick time, it has a built in security feature of creating a user called admin (fine by me) and a new password for this user (which I then change to something simple like "admin" - just for development purposes). This is quite simple:

drush user-password admin --password="admin"

When I'm given a new project to work on, the first thing I do with my local instance is set the admin password to "admin".

To speed things up, I decided to write a drush alias to make these two use-cases easier to manage (yes, I know, first world problems!). And then I thought, why not share this and some of my other aliases. So, here goes (with comments):

alias dr='drush' // general alias for drush
alias drcc='drush cc all' // clear all the caches
alias drup='drush up' // update core and contrib modules
alias drupdb='drush updb' // run update.php
alias dren='drush en' // enable a module/theme
alias drdis='drush dis' // disable a module/theme
alias drfl='drush fl' // list all features on the site
alias drflo='drush fl | grep Overridden' // list all overridden features
alias drfu='drush -y features-update' // update a feature - you must put the feature's name after this
alias drfua='drush -y features-update all' // update all feature
alias drfr='drush -y features-revert' // revert a feature - you must put the feature's name after this
alias drfra='drush -y features-revert all' // revert all features
alias drpad='drush user-password admin --password="admin"' // change password for user admin to admin

Note: to get these working, I put them in my bash_profile file. Every time I add a new one, I run source ~/.bash_profile to reload the file and make the alias available to drush.

What aliases do you use?

Jul 23 2014
Jul 23

It's not difficult. It really isn't, but people struggle over it. Lots. Let's see how to make an image gallery in Drupal 7 (the same theory will hold for Drupal 6 and, I presume, Drupal 8).

This will create an "Image Gallery" content type, with images within each gallery re-orderable by 'drag and drop'. Here we go.

You will need:

Technique

  • First off, enable the modules listed above.
  • Then we need to create a content type. In this case, we'll call it "Image Gallery".
  • Next, we need to create an image field inside this content type.
    • Choose "Image" as the field type and "Multiupload" as the widget type
    • Set the number of allowed values for this field to "Unlimited".
  • Create some image presets, such as:
    • Gallery Thumbnail (150px x 150px) - used on the gallery page to list the images in that gallery.
    • Gallery Full Size (1000px wide) - used in an overlay when Gallery Thumbnail images are clicked on.
  • Go to your "Manage Display" page for this content type and for "Full Content" set the following displays for the image field
    • Label = Hidden
    • Image = Colorbox
      • On the colorbox settings, set "Content Image Style" as "Gallery Thumbnail" and "Colorbox Image Style" as the "Gallery Full Size"
      • There are some other options here as well. Feel free to experiment.
      • Click "Update".
    • Click "Save".

Now you are ready to create an image gallery. You may need some CSS to float the images left/right and set some margins/padding.

You can then use Views to list the galleries and link each item in the list to its corresponding gallery.

(Note: a version of this is available on Drupal.org.)

Jun 28 2014
Jun 28

It's not rocket science, this building installation profiles/distributions with Drupal!

Creating your own Drupal installation profile is a great way to save time when building a new website if you have many features that you use again and again on projects, such as news content type, image galleries, rotating slider. It's a great way to store your configuration in code and build and rebuild your site while in development. It's also best practice if you want to share code and rebuilds between developers working on large projects.

So, how do ywou make an installation profile, the easy way? The easiest way to create an installation profile is to just copy one that comes with Drupal core and modify it. To do this;

  • Open up your profiles folder, find the folder called "standard" and copy it, then rename it to whatever you want. I call mine "adfl" as I do work as a freelancer under the name "A Design for Life".
  • Next, rename each file in your new folder from standard.profile to adfl.profile, standard.install to adfl.install, standard.info to adfl.info.
  • In the .info file, edit the description to something more meaningful for your installation profile.
  • Finally, open each file and replace the word "standard" in the code with the word "adfl".

You now have a working installation profile called adfl, but it does the exact same as the standard installation profile. Let's customise it.

In the .info file, you'll see a number of modules already installed, like so:

dependencies[] = block
dependencies[] = color
dependencies[] = comment
dependencies[] = contextual
dependencies[] = dashboard
dependencies[] = help
dependencies[] = image
dependencies[] = list
dependencies[] = menu
dependencies[] = number
dependencies[] = options
dependencies[] = path
dependencies[] = taxonomy
dependencies[] = dblog
dependencies[] = search
dependencies[] = shortcut
dependencies[] = toolbar
dependencies[] = overlay
dependencies[] = field_ui
dependencies[] = file
dependencies[] = rdf

We can turn these off by deleting some, like so (or simply placing a semi-colon before them to comment them out):

dependencies[] = block
dependencies[] = comment
dependencies[] = contextual
dependencies[] = image
dependencies[] = list
dependencies[] = menu
dependencies[] = number
dependencies[] = options
dependencies[] = path
dependencies[] = taxonomy
dependencies[] = dblog
dependencies[] = search
dependencies[] = field_ui
dependencies[] = file
; this is commented out dependencies[] = overlay
dependencies[] = rdf

Now, if you reinstall your website, you'll see that we only have the above modules installed. We can now add in some modules that we use on every website. Place these modules in profiles/adfl/modules/contrib. We add them like so:

dependencies[] = admin_menu dependencies[] = ctools dependencies[] = features dependencies[] = views

Keep adding whatever modules you need. Now, when you resinstall your site drush si adfl, you'll see these modules also installed. To add custom functionality, you create features, and then add those features to your install profile, like so:

dependencies[] = adfl_blog dependencies[] = adfl_views_blog dependencies[] = adfl_gallery dependencies[] = adfl_views_gallery

A new site install will have these features enabled as well. A site install gives some simple errors at the moment: since I don't have dashboard enabled, the blocks placed in the dashboard can't be placed. Opening the .install file, we can find where this is and delete it:

array( 'module' => 'search', 'delta' => 'form', 'theme' => $default_theme, 'status' => 1, 'weight' => -1, 'region' => 'sidebar_first', 'pages' => '', 'cache' => -1, ), array( 'module' => 'node', 'delta' => 'recent', 'theme' => $admin_theme, 'status' => 1, 'weight' => 10, 'region' => 'dashboard_main', 'pages' => '', 'cache' => -1, ), array( 'module' => 'user', 'delta' => 'login', 'theme' => $default_theme, 'status' => 1, 'weight' => 0, 'region' => 'sidebar_first', 'pages' => '', 'cache' => -1, ),

In the above case, we need to delete the array

array( 'module' => 'node', 'delta' => 'recent', 'theme' => $admin_theme, 'status' => 1, 'weight' => 10, 'region' => 'dashboard_main', 'pages' => '', 'cache' => -1, ),

Then, just keep building up your profile with features, theme, variable settings, etc. There you go, a custom installation profile, the easy way. (Might be better to start with minimal as your base, I'm only using standard for illustration.)

Mar 04 2014
Mar 04

Drupa Open Days 2014 - two days of discussions, workshops, presentations, Q&As, and socialising - all built around the theme of Drupal and what it can do for you - has just been announced.

\r\n

Come to Drupal Open Days 2014, 16-17th May, to find out how you can use Drupal for your next website or online application. This free event has a variety of guided training, presentations and small group discussions. You’ll learn loads, get your questions answered and meet some friendly people too.

\r\n\r\n

Drupal is an open source CMS (content management system) that allows an individual, a community of users, or an organization to easily publish, manage and organize a wide variety of content on a website or application. http://drupal.org/

\r\n\r\n

Full details at: http://2014.drupal.ie

\r\n\r\n

The event is at the the Guinness Enterprise Center. This event is free, however registration is required.

\r\n\r\n

*Note: I am in charge of organising speakers. If you have a session/presention to you like to give or be in attendance for, just let me know.

\r\n
Dec 13 2013
Dec 13

Back in the good old days (circa 2008, Drupal 6.3) there was me. Me and my Drupal installations. And not much of a clue about anything. Then I thought, if only I had a WYSIWYG editor, my life would be complete. Then I tried to install one (TinyMCE specifically) and  lo!, my nightmares began in earnest.

\r\n

These days, it's quite simple - in Who Wants to be a Millionaire terms ("it's only easy if you know the answer"). These days, I use CKEditor. Why? Well, it's going to be in core for Drupal 8, so I thought I might as well get used to it, but since making that decision a year ago, I find it a very pleasant editor to use. Then there was a damsel person in distress on Twitter wondering how to install it, so I thought "time to jump into character and save the poor soul".

\r\n\r\n

@AgentCD are you sure? I've never paid for it. Can you send a link to it being premium. Perhaps I should write a blog post on installing it.

\r\n\r\n

@AgentCD are you sure? I've never paid for it. Can you send a link to it being premium. Perhaps I should write a blog post on installing it.

— Mark Conroy (@markconroy) December 11, 2013 \r\n\r\n\r\n

So, here goes.

\r\n\r\n
  1. \r\n
  2. Download the CKEditor module for Drupal.\r\n\r\n
    1. \r\n
    2. This gives you a Drupal module to power the CKEditor WYSIWYG - it is NOT the editor itself, merely a bridge to it.\r\n
    \r\n\r\n
  3. Download CKEditor library from CKEditor.com.\r\n
    1. \r\n
    2. Extract the .zip folder you get from this.\r\n
    3. This is the editor itself. You need the Drupal module from 1 above to act as a bridge to this.\r\n
    \r\n\r\n
  4. Download the Libraries module for Drupal.\r\n
  5. In your sites/all/libraries module, drop in the CKEditor folder that you have downloaded from CKEditor.com, so you should have sites/all/libraries/ckeditor\r\n
  6. Enable the CKEditor and Libraries modules in your Drupal installation on your modules page.\r\n
  7. Take a bow. That should do it, now you can go to admin/config/content/ckeditor on your website and start playing with your sexy new WYSIWYG.\r\n
\r\n

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web