Playing with the Sculpin static site generator
I can hear you asking: "What the hack is that?" Let me quote the Sculpin's authors:
Sculpin is a static site generator written in PHP. It converts Markdown files, Twig templates and standard HTML into a static HTML site that can be easily deployed.
Few days ago a need for a very simple website arose which was way too simple to use Drupal 8 for it. Even Wordpress would be way over the top. On the other hand I really wanted to try static HTML generators for a while and this seemed a perfect opportunity to do that.
There are many static HTML generators out there, Jekyll probably being the most popular (it is also supported by GitHub pages, which makes hosting trivial). I, however, decided to go with Sculpin because it is written in PHP and is using Symfony and Twig. I am already more or less familiar with all this technologies, which made the task a bit easier.
Result?
Few hours, very simple Bootstrap based theme, FlexSlider, some Markdown and violà! Site was done and running. It is performant, I can host it literary everywhere, no need to clear caches every time when something behaves strange, no updates, security out of the box, ...
I could totally use something similar for this blog too. Heresy against The religion of Drupal™ you say? Maybe.... But think about it. I am already using Markdown (not really a WYSIWYG fan) to write my posts. That wouldn't change at all. I use Disqus for comments, which would play perfectly fine with static HTML. I could use Liquid Forms or something similar to run the contact form or simply ask people to reach out via Twitter or IRC. That's it. It could probably be done in a day while it took me 3 or 4 days to migrate my Drupal 7 blog to Drupal 8. Not to mention the significantly easier maintenance.
I might even consider doing that when the migration to Drupal 9 comes around. We'll see what the hip thing at that time will be...
All this got me thinking...Solutions like Jekyll and Sculpin are gaining popularity in the lowest end of the web market. By that they are eating into what used to be market of CMSes like Drupal and Wordpress just a few years ago. Benefits are clear (mainly performance and easy maintenance). The user experience and the ease of use is still on the CMS side, but for slightly tech savvy users it is completely doable. And this might very likely change in the next few years (every software tries to improve over time, right). That said, this kind of tools might (together with pure SaaS solutions) dominate the lower-end web market in the future.
"But Drupal 8 is enterprise-oriented. That's what we care about!" you'll say. OK. Probably true, but...
It is easier than ever to build custom web projects in PHP. In the times before Composer, Packagist and all other nice stuff that we have today existed it was total PITA to find and bring a bunch of 3rd party libraries together to help you build a custom app. In just a few short years this became much simpler and will become even easier as our tools and ecosystem evolve. And PHP is not alone in this world. There are many new and modern languages/platforms that are all doing similar things from this perspective. All of them have some kind of package manager, dependency resolver, repositories of 3rd party packages, etc. It is to be expected that this will only continue. Tools will become even easier to use, 3rd party libraries/packages will become more powerful and building custom projects based on them even faster.
Higher-end projects usually have some budget to invest into development. What would you choose if the cost of development using a CMS like Drupal would be similar to the cost of building a custom project? Specially if you don't need all the features and complexity that CMS offers?
"Are you saying that Drupal is going away?" you ask.
Of course not. Drupal is a great tool that can efficiently solve many problems. But there are definitely better tools for some others. It also seems that there is strong competition on all sides of the web market, which is eating into the pie that was reserved for traditional CMSes in the past. Drupal will need to think about this and position itself into that segment of the market where it is the strongest. The days of "Drupal for everything" are clearly over.
What is your opinion about this? What do you think future will bring us? Let's continue the discussion in the comments below!
slashrsm Sun, 29.01.2017 - 22:08 Tags Drupal web Enjoyed this post? There is more! Join us at the next Drupal Media sprint at the Mountain camp in Davos! Drupal dev environment on Docker Entity browser feature freeze will happen in two weeksDo you really need Drupal for that? How to choose the right technology for your project
We're moving house soon, and we're planning to rent out the flat we live in now. We could use an estate agent, and get the flat up on all the usual property boards. But, in the spirit of the IndieWeb, and because we don't want to pay commission to agents, we decided to put up our own website advertising the flat.
As with most developers, as soon as I had the idea of a project, my mind was racing with possibilities, and I had to stop myself from jumping straight into a code editor.
What technology will we use?Whenever a web project starts, this is one of the most fundamental questions to answer. Until you've decided this, you can't get very far with building the thing.
A lot of developers will default to their standard toolkit. We tend to use what we've used before, what we're comfortable with. Most of the sites I've built over the last few years have used Drupal. For a while I used to choose Wordpress for smaller, simpler sites, and Drupal for anything that needed more flexibility and complexity, but as I got more familiar with Drupal, I became more efficient with it, to the point where it was quicker and easier to use Drupal.
Besides, often those smaller sites will end up evolving into something more complex, and with Drupal it's fairly straightforward to set the CMS up so that it isn't too intimidating to the editors. In my mind, that leaves the ease of updates as the only thing in favour of Wordpress, and that's a double-edged sword if people don't test updates properly.
But it's important to remember that developer convenience shouldn't be the deciding factor in how you approach a project. Your technology choice should be guided by the needs of the project and its stakeholders.
Does the site even need a CMS?
There are two questions I’d always ask when planning a project:
- How often is the content going to be updated?
- Who’s going to be updating it?
Content management systems are very useful and very powerful, but they bring additional complexity with them. You have to make sure that the software and the server it's running on are configured correctly, and that they're kept up to date. The more you can reduce the complexity, the fewer challenges you'll have.
These days, for simple sites, I'd be more inclined to use a static site generator like Jekyll, as long as the people editing the content would be able to handle writing in Markdown. Security and performance both get a lot easier to handle if you're just serving flat files.
For this project, the content is hardly ever going to change, and when it does, it will be me who edits it, and I’m comfortable editing raw HTML. So no, we don't need a CMS. And because there's only enough content to fill a single page, we don't even need any kind of site generator. Just a single HTML file, with some CSS and JavaScript - keep things as simple as possible.
Where do we start?No matter how complex your project, there’s always the option of starting from a completely blank slate, but unless what you're doing is very bespoke, do you really need to roll your own every single time? The problems that you’re likely to face in a web project are almost certainly problems that somebody else has already solved, so why not stand on the shoulders of giants?
Having decided to build a single page site, I found a single page template based on Bootstrap that looked OK. Bootstrap and Foundation are often criticised for contributing to a culture where a lot of websites look the same, and perhaps rightly so. But a lot of the time, the people who publish content websites don't want or need their site to be unique. There's a reason why a lot of startups use these frameworks - they want to get something out there quickly, so that they can show the market what they've got, so that they can get some income and start iterating.
Yes, I feel a little lazy for spending five minutes googling single page templates, but what would be the value for me of doing something else? Perhaps I could use this side project as a learning opportunity? A chance to try out a new technology, or a new way of doing things?
Those can be good reasons to choose a technology, especially for a personal project, but I wanted to get a basic site together quickly. I wanted it to be good enough with minimal effort on my part. By starting with a template, I very quickly had something presentable enough to start showing to people. If I’d started from an empty file, perhaps I would have built something with more of myself in it, something I could be more proud of, but it would have taken a lot longer. Moving house is stressful, and I've got a day job and a family, and a bunch of other things on the go, so I didn't want to spend enormous amounts of time on this.
In short, I had a fairly clear idea of my minimum viable product, and using a template meant that I was quickly able to reach the point where I could focus on the content. After all, the content should always be the main thing.
Being a developer, I'm always looking for things to improve. For instance, perhaps I could get the site loading faster by converting FontAwesome to inline SVG, or maybe I could do something clever with the images or critical CSS.
But the point is that the website isn't there to impress other developers - it's there to get a message out to the world - that we're looking for someone to rent our flat.
Tags: development technology Drupal All tagsDrush commands for every day usage
Read more »
Continuous integration and testing with Drupal on AppVeyor
You can now easily test your Drupal projects on AppVeyor. Currently, AppVeyor is the major player in CI regarding Windows Servers. On other CI systems (Travis, Bitbucket pipelines) you are limited to Docker containers for the *nix platform. (This will soon change as some CI will throw Windows containers into the mix).
Until then, the only tool to CI your Drupal (or any PHP project) on a Windows based environment using IIS is AppVeyor.
Language English More articles...- Remote debugging production PHP applications with XDebug
- Setting up Code Syntax Higlighting with Drupal
- Database Transactions in Drupal
- Drupal 8 Performance: Moving the service container cache away from the database
- Drupal: Fields or Properties (or something else)
- PDF Generation in PHP
- Using Heatmaps to boost conversions: Heatmap.me Drupal integration
- Deploying Drupal Like a Pro - Part 1: File Structure
- When PHP crashes: how to collect meaningful information and what to do with it
- Drupal 8 Couchbase Integration
Drupal 8 survey Feeds/Migrate usage and functionality
Vote for your favorite MidCamp T-Shirt Design
We need your help. We have all these great options for this year's MidCamp T-Shirts, and we just can't decide which one to make. Please fill out our poll to make your voice heard!
Visit the site for the poll.
Sponsor MidCampWe're currently seeking Lunch and Coffee sponsors for MidCamp 2017. Lunch is the perfect opportunity to get your name in front of all of the attendees! Drupalers like coffee. Some might even say Drupalers love coffee! Earn the gratitude of our attendees by having your name and logo associated with the liquid refueling station! We are looking to four sponsors for each day to cover the costs. Find out more.
Join Us Stay connected:- Visit http://www.midcamp.org
- Like Midcamp on Facebook
- Follow @midwestcamp on twitter
- Watch MidCamp on Youtube
Drupal 8 and 7 core release window on Wednesday, February 01, 2017
The monthly core patch (bug fix) release window is this Wednesday, February 01. Drupal 8.2.6 and 7.54 will be released with fixes for Drupal 8 and 7.
Also, Drupal 8.3.0-alpha1 will be released during the window.
To ensure a reliable release window for the patch release, there will be a Drupal 8.3.x and 8.2.x commit freeze from 12:00 UTC Tuesday to 12:00 UTC Thursday. Now is a good time to update your development/staging servers to the latest 8.2.x-dev or 7.x-dev code and help us catch any regressions in advance. If you do find any regressions, please report them in the issue queue. Thanks!
To see all of the latest changes that will be included in the releases, see the 8.2.x commit log and 7.x commit log.
Other upcoming core release windows after this week include:
- Wednesday, February 15 (security release window and beta window for 8.3.x)
- Wednesday, March 01 (patch release window and release candidate window for 8.3.x)
- Wednesday, April 5 (scheduled minor release)
Drupal 6 is end-of-life and will not receive further releases.
For more information on Drupal core release windows, see the documentation on release timing and security releases, as well as the Drupal core release cycle overview.
Dev Environments With ZFS and Containers
Development environments are used to develop and test changes before pushing code further through the release pipeline. Giving each developer their own environment allows changes to be made within the codebase without affecting other developers or environments.
Traditionally, these environments would be locally based on the developer’s machine with all of the libraries and programs needed to run the code being installed too. We’ll examine development environments from the perspective of a web developer, so the needed programs would include a web server and a database server.
The ProblemThere are two main issues with local development environments: isolation and resources.
Isolation
Before virtual machines (VMs) were common, many developers had a single web server and database server installed on their computer. Multiple sites (and multiple copies of the same site) were separated at the directory level with each copy of the site taking up the same amount of space as its parent.
Having all sites served by the same web and database servers presents a few problems:
-
Server level configuration is applied to every site
-
Software versions are limited at server level
-
Each site could potentially access other sites data
-
Configuration becomes cluttered over time
Once virtualisation became available to desktop hardware, software such as Virtualbox made it possible to create VMs which allowed the developer to have an entire server for each website or for each client. This approach meant that the development environment could now be tailored to match production environments and can be completely isolated from other development environments.
Resources
Before VMs, each site would only take up the code and database’s size of disk space. Generally, as only one web server and one database server ran at a time, the resources of only a single instance of each would be used.
A VM is an entire computer, from the virtual hardware assigned, to the Linux operating system, to the applications such as the web server. This means that each VM needs more resources to run than just a single web server with multiple copies of code. Each VM will be allocated its own memory, CPU and disks - taking up more resources on a developers local machine.
Solving the problemTo solve the problems of isolation and resources, we’ll need to use different technologies to address the individual concerns of each.
To address the issues of isolation and indirectly address resource usage, container technology can be used. Amazon Web Services (AWS) describe containers as being “a method of operating system virtualization that allow you to run an application and its dependencies in resource-isolated processes”. Using containers grants several benefits:
-
Isolation - each container will be isolated from other containers
-
Better resource use - unlike VMs, we don’t need to assign memory and disk space for the operating system
-
Faster - even with VM snapshots, creating new containers is very quick
Even though containers can reduce the disk space usage of development environments compared to VMs, it’s possible to further save space by using a filesystem that supports snapshotting and copy-on-write (COW) resource management. Copy-on-write allows data to be shared until a change is made to that data, at which point, a copy is made. This allows multiple copies of the same code & database to exist without taking up the expected amount of disk space, which is beneficial if a developer wants to use a container to work on several features on the same site at the same time.
Tech used
To demonstrate container technology, Docker will be used. Although there are other container engines available for use, Docker is the currently ubiquitous choice.
ZFS will be used for snapshotting and for copy-on-write.
Although ZFS is available for OSX (https://openzfsonosx.org/wiki/Downloads), at the time of writing, 10.12 does not have a stable version. Ubuntu Xenial will be used instead for the OS.
ZFS
ZFS is a filesystem that was originally designed by Sun Microsystems in the early 2000s. ZFS was designed to solve several problems that filesystems at the time had. It was designed to be easily scalable, have native snapshots for easy backup and restoration of data and check for corruptions via checksumming and if necessary, self heal. By controlling both of the, traditionally separate, facets of data management - the physical management (such as hard disks) and the file management (a filesystem such as NTFS), ZFS has knowledge of and complete control of everything that makes use of it.
ZFS filesystems are built on top of virtual storage pools called zpools. A zpool is made up of virtual devices that are made up of block devices, for example a disk.
ZFS snapshots
When ZFS writes new data, the blocks containing the old data can be retained, allowing a snapshot version of the file system to be maintained. ZFS snapshots are created very quickly, since all the data composing the snapshot is already stored. They are also space efficient, since any unchanged data is shared among the file system and its snapshots.
Creating filesystems from snapshots
Writeable snapshots ("clones") can also be created, resulting in two independent file systems that share a set of blocks. As changes are made to any of the clone file systems, new data blocks are created to reflect those changes, but any unchanged blocks continue to be shared, no matter how many clones exist. This is an implementation of the copy-on-write principle and is what we’ll be taking advantage of to create new environments.
ZFS example
Installation
Install ZFS
apt install zfsutils-linux
Before creating a ZFS filesystem, we need to create a zpool for it:
zpool create blogpost /dev/sdb
/dev/sdb is a 2GB disk attached to the machine. The zpool will take up the entire available space of the disk.
zpool list shows:
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH
blogpost 1.98G 64K 1.98G - 0% 0% 1.00x ONLINE
And mount shows:
/blogpost on /blogpost type zfs (rw,relatime,xattr,noacl)
You can change the mountpoint at creation time by passing -m and a path.
To create the filesystem:
zfs create blogpost/master
zfs list will show the filesystem we created and the root filesystem:
NAME USED AVAIL REFER MOUNTPOINT
blogpost 250K 1.92G 19K /blogpost
blogpost/master 19K 1.92G 19K /blogpost/master
Snapshots
To demonstrate the copy-on-write/snapshot features, create some test data:
dd if=/dev/zero of=/blogpost/master/file-1mb.txt count=1024 bs=1024
dd if=/dev/zero of=/blogpost/master/file-2mb.txt count=2048 bs=1024
And now create the snapshot:
zfs snapshot blogpost/master@testsnapshot
zfs list -t snapshot will show snapshots:
NAME USED AVAIL REFER MOUNTPOINT
blogpost/master@testsnapshot 0 - 3.02M -
Clone the snapshot by specifying the clone and the destination filesystem. In this case, we’re taking the clone of master called ‘testsnapshot’ and creating a filesystem called development:
zfs clone blogpost/master@testsnapshot blogpost/development
Listing the files in /blogpost/development will show the files:
drwxr-xr-x 2 root root 4 Jan 10 17:51 ./
drwxr-xr-x 4 root root 4 Jan 10 17:57 ../
-rw-r--r-- 1 root root 1048576 Jan 10 17:51 file-1mb.txt
-rw-r--r-- 1 root root 2097152 Jan 10 17:51 file-2mb.txt
Even though you can see the files and their sizes, only 1k of space is taken up instead of 3MB. The 3MB of data is being referenced rather than existing.
zfs list:
NAME USED AVAIL REFER MOUNTPOINT
blogpost/development 1K 1.92G 3.02M /blogpost/development
blogpost/master 3.02M 1.92G 3.02M /blogpost/master
After making a change to the 1mb file in /blogpost/development, zfs list now looks like:
NAME USED AVAIL REFER MOUNTPOINT
blogpost/development 1.14M 1.92G 3.15M /blogpost/development
blogpost/master 3.02M 1.92G 3.02M /blogpost/master
Docker
Docker Example
Installation
(Steps below are for Ubuntu 16.04. See https://docs.docker.com/engine/installation/ for other operating systems)
sudo apt install apt-transport-https ca-certificates
sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt-cache policy docker-engine
sudo apt install linux-image-extra-$(uname -r) linux-image-extra-virtual
sudo apt install docker-engine
Usage
docker run -d -p 80:80 tutum/hello-world
The command above will automatically download an image called “hello-world” from the Tutum repository on the docker hub. Once downloaded, it will start the container in detached mode (runs in the background) and publishes port 80 so that we can connect. Once running, opening the page in the browser gives:
Now that the image is downloaded (and already built as it’s stored in the Docker Hub), starting another container is as simple as changing the port and running the command again:
docker run -d -p 8080:80 tutum/hello-world
This will instantly start another container. We can use ‘docker ps’ to see the running containers:
CONTAINER ID IMAGE COMMAND STATUS PORTS
21def91c5b50 tutum/hello-world "/bin/sh -c 'php-fpm " Up 28 seconds 0.0.0.0:8080->80/tcp
fe4b2176f151 tutum/hello-world "/bin/sh -c 'php-fpm " Up 39 minutes 0.0.0.0:80->80/tcp
So using two docker commands, we have 2 separate containers running Nginx and PHP - yet only using the process’ amount of resources instead of an entire operating systems, in the case of the VMs:
CONTAINER CPU % MEM USAGE / LIMIT
21def91c5b50 0.02% 3.977 MiB / 488.4 MiB
fe4b2176f151 0.01% 4.516 MiB / 488.4 MiB
Putting it all together
Using the above examples, it should be possible to see how containers and a copy-on-write filesystem can be used together in order to create new development environments quickly and cheaply.
The proof of concept techniques used above can be expanded into working with a minimal PHP developer’s setup - Nginx, PHP & MySQL. Docker-compose will be used in order to simplify the defining and running of multiple containers.
Note:
The PHP container uses a custom image which extends the official php-7 image and adds mysql pdo extensions. To create this image, create a file called Dockerfile containing:
FROM php:7-fpm
RUN docker-php-ext-install mysqli pdo pdo_mysql
Running the following will build the image.
docker build -t blogpost-web .
Docker-compose reads a docker-compose.yml file to determine what to do. The syntax is similar to that of a normal Dockerfile. Create a file in /blogpost/master called docker-compose.yml and use the following:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./code:/code
- ./site.conf:/etc/nginx/conf.d/site.conf
links:
- php
php:
image: blogpost-web
volumes:
- ./code:/code
links:
- db
db:
image: mysql
volumes:
- ./database:/var/lib/mysql/
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: master
MYSQL_USER: master
MYSQL_PASSWORD: master
MYSQL_DATABASE: master
docker-compose up will download the images (if needed) and start the containers.
Test Data
In order to test the functionality, a small file is placed in the code directory that connects to the DB and prints out the contents of the messages table. An example is:
$db = new PDO('mysql:host=db;dbname=master;charset=utf8mb4', 'master', 'master');
echo("I am master
Messages:");
foreach($db->query('SELECT * FROM messages') as $row) {
echo $row['message'];
}
The disk space usage now looks like:
NAME USED AVAIL REFER MOUNTPOINT
blogpost/master/code 20K 1.72G 20K /blogpost/master/code
blogpost/master/database 210M 1.72G 210M /blogpost/master/database
So the database is currently taking up 210MB. Traditionally, if we wanted to duplicate the database for another branch/feature, we’d copy the directory, thereby increasing the disk space usage to 420MB.
To snapshot the master branch, use the following commands:
zfs snapshot blogpost/master/database@masterdatabase
zfs snapshot blogpost/master/code@mastercode
Then create the development filesystem and then clone the master snapshots to the development filesystem:
zfs create blogpost/development
zfs clone blogpost/master/code@mastercode blogpost/development/code
zfs clone blogpost/master/database@masterdatabase blogpost/development/database
zfs list now shows the master & development filesystems:
NAME USED AVAIL REFER
blogpost/master/code 20K 1.72G 20K
blogpost/master/database 210M 1.72G 210M
blogpost/development/code 1K 1.72G 20K
blogpost/development/database 1K 1.72G 210M
The code and database for the development branch is only taking up 2KB disk space instead of 210MB! Quite a saving if used with large databases and codebases.
Running docker-compose up in the development directory brings up the 3 containers. Edit the test PHP and replace ‘master’ with ‘development’, so that we can prove which codebase is being used.
When visiting the master site, you should see
And when visiting the development site, you should see:
zfs list shows:
NAME USED AVAIL REFER
blogpost/master/code 29K 1.70G 20K
blogpost/master/database 210M 1.70G 210M
blogpost/development/code 9.50K 1.70G 20K
blogpost/development/database 12.6M 1.70G 210M
So although some extra space has been used, nearly 200MB is still saved even though an entirely new development environment now exists.
Get a shell on the development DB container by running: docker exec -it development_db_1 /bin/bash
And insert some data:
mysql -umaster -pmaster master -e ‘insert into messages (message) values ("This is the development branch");’
Refreshing the page on your development web server should now show another message:
NAME USED AVAIL REFER
blogpost/master/code 29K 1.70G 20K
blogpost/master/database 210M 1.70G 210M
blogpost/development/code 9.50K 1.70G 20K
blogpost/development/database 12.8M 1.70G 210M
So even with a change in the database, the majority of the data is referenced from the snapshotted data with only 12.8MB taking up space on the disk.
ConclusionThe examples above have shown that it is possible to create quick andresource effective development environments locally. We have shown how containers can be used to isolate environments which provide a layer of security and cleanliness whilst still saving space and time when compared to traditional VMs. We have also shown how using a copy-on-write filesystem such as ZFS can be used to quickly and easily clone environments and reduce disk space usage, allowing a developer to have more environments than a traditional setup might allow.
The commands used can easily be scripted to make the process interactive and even faster.
Friday 5: 5 Tips for Preparing for the Acquia Certification Test
![Mediacurrent Friday 5 Logo Mediacurrent Friday 5 Logo](http://web.archive.org./web/20170130000224im_/https://www.mediacurrent.com/sites/default/files/styles/thumb_blog_spotlight/public/friday-5-blog-graphic.png?itok=_cbspLjG)
Happy Friday, everybody. This episode Front End Developer Tim Dickens and a special guest give you some tips on how to prepare for the Drupal Certification Exams.
Have a topic that you'd like to learn more about? Feel free to email us at Friday5@mediacurrent.com with any suggestions and stay tuned for the next episode. Have a great weekend!
Matt Westgate and Seth Brown on Doing Good with Drupal
Adding Bootstrap button stylings to Drupal 8's action links and node links
When all goes according to plan—which is surprisingly often—theming in Drupal 8 is a straightforward matter of editing templates and stylesheets. We found things did not go according to plan when styling page-level action links (such as "Add new Forum topic") and content-level action links (or node links as Drupal 8 still calls them, such as "read more" or "add comment"). We are going to show how to add Bootstrap-specific styles, but the same approaches would be useful to add special stylings, button-like or otherwise, to selected action links and node links.
First, let's revisit the steps to follow when trying to add classes to Drupal-produced markup:
- Enable Twig debugging.
- Using your browser's inspector, identify the template providing the code you need to modify.
- Copy the template from where Twig debug output says it lives in Drupal core (or contrib) to your theme. If needed, use template name suggestions with a
--modifier
to selectively override the template in specific cases. - Add BEM-compliant classes to your template. This is usually accomplished by tacking the
addClass("here are--my-classes")
method onto anattributes
variable. - Use the classes you added in your CSS.
Now let's try applying that to styling action links and node links (but only the actual link parts, not the surrounding text) as buttons.
Page-level action links
Here is an action link provided by Drupal core in the Forum module. It's classes don't align with Bootstrap's, so it displays without style.
The process
If we open the template that is providing the HTML for each link, menu-local-action.html.twig
, it is only one line of code (and 12 lines of comments). It couldn't be simpler!
{# /** * @file * Default theme implementation for a single local action link. * * Available variables: * - attributes: HTML attributes for the wrapper element. * - link: A rendered link element. * * @see template_preprocess_menu_local_action() * * @ingroup themeable */ #} <li{{ attributes }}>{{ link }}</li>
Except... the attributes
variable we have available is on the list item (li
tag), not the link itself. Using this template we can't add classes to the already-rendered link element. Putting the button class on the list item would result in a common UX problem: button-looking elements with parts that are not clickable.
Even though this template cannot be used directly, it points us in the right direction. On line 10, a comments suggest us to see template_preprocess_menu_local_action()
. So we shall.
A symbol finder in an IDE or grep
will quickly take us to line 65 of core/includes/menu.inc
:
/** * Prepares variables for single local action link templates. * * Default template: menu-local-action.html.twig. * * @param array $variables * An associative array containing: * - element: A render element containing: * - #link: A menu link array with 'title', 'url', and (optionally) * 'localized_options' keys. */ function template_preprocess_menu_local_action(&$variables) { $link = $variables['element']['#link']; $link += array( 'localized_options' => array(), ); $link['localized_options']['attributes']['class'][] = 'button'; $link['localized_options']['attributes']['class'][] = 'button-action'; $link['localized_options']['set_active_class'] = TRUE; $variables['link'] = array( '#type' => 'link', '#title' => $link['title'], '#options' => $link['localized_options'], '#url' => $link['url'], ); }
Here we can see exactly how Drupal is adding classes ('button' and 'button-action') to the buttons. Let's add our own preprocess function assuming our theme is name exampletheme
:
- Add a function to our .theme file. In this example, the file would be
exampletheme.theme
. - Name the function
exampletheme_preprocess_menu_local_action()
. That is, replace the word 'template' with the name of our theme name. - Modify the
$variables
array to add our classes.
We could even remove the existing classes from the link, but we'll leave them for now. Note that the link that gets processed is $variables['link']
rather than $variables['element']['#link']
.
The solution
/** * Extends template_preprocess_menu_local_action(). * * Add Bootstrap button classes to a single local action link. * * Default template: menu-local-action.html.twig. * * @param array $variables * An associative array containing: * - element: A render element containing: * - #link: A menu link array with 'title', 'url', and (optionally) * 'localized_options' keys. */ function exampletheme_preprocess_menu_local_action(&$variables) { $variables['link']['#options']['attributes']['class'][] = 'btn'; $variables['link']['#options']['attributes']['class'][] = 'btn-success'; }
Content-level action links
Next let's style node links as buttons. It's well-nigh impossible to get the btn
and btn-success
classes on the login and register links within the sentence "Log in or register to post comments". Therefore, we will use Bootstrap's handy mixins. The following is a SCSS code snippet which is turned into CSS by a SASS preprocessor.
.links--node a { @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border); @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base); }
Finally, we just need to add the links--node
class. Assuming our theme is called exampletheme
:
/** * Implements hook_preprocess_links() for node entities. */ function exampletheme_preprocess_links__node(&$variables) { $variables['attributes']['class'][] = 'list-unstyled'; $variables['attributes']['class'][] = 'links--node'; }
Bonus: Link field links as buttons
For styling the output of link fields as buttons, the aptly-named Button link formatter module can help you out without the need for custom code nor templating.
Are you styling action links, node links, and other links?
Have you faced similar needs for changing the look of links, to be buttons or otherwise? How have you met them? Let us know in the comments!
Email Authentication – SPF, DKIM, DMARC
When email was first designed, security was not considered important and up until fairly recently it was still possible to send an email from any address and get away with it.
However, as spam, phishing and spoofing attacks by email have become increasingly common there have been various attempts to make email more secure. In the last year or so the major providers (AOL, Google, Microsoft etc.) have all seriously tightened their security and authentication requirements for validating and receiving email. The result of this is that a lot of legitimate email is now being classified as spam or rejected by those providers. In order to ensure that your email continues to be marked as legitimate and received by these larger providers it is now almost essential that you implement SPF, DKIM and DMARC on your domains otherwise many of your recipients will never see the emails you are sending!
As an implementer of CiviCRM I've had to learn all this pretty quickly... There's a lot of detailed information out on the web but hopefully this post covers what you actually need to know to make sure your clients emails are delivered and read!
Read the rest of my blog post here.
ToolsCiviMailDrupalSecurityWordPress
Keep Your Site Evercurrent: Security Updates Just Got Easier
![Evercurrent logo](http://web.archive.org./web/20170130000224im_/http://blog.kalamuna.com/sites/default/files/news_articles/evercurrent.png)
At Kalamuna we not only build Drupal websites, but we also provide support services for a plethora of clients. One of these is providing security updates; we pride ourselves on keeping our clients’ sites safe and free from vulnerabilities. But, I have to admit that when I hear of new security releases I cringe. I think about the tedious process of going through each site or trying to recall who has what modules installed on their site. But I just discovered an app that finds all of the new security updates for me: Evercurrent. Read on to see how it works.
How Deploy Drupal to Heroku
How to Build Drupal 8 Triple Display Slideshow Using Slick
![How to Build Drupal 8 Triple Display Slideshow Using Slick](http://web.archive.org./web/20170130000224im_/https://www.ostraining.com/images/drupal8/drupal-8-slick-slideshow.jpg)
One of our OSTraining members asked how it was possible to make multiple displays for Drupal 8 slideshows.
In this tutorial, I will show you how to build a slideshow that uses your article content type to make a slideshow with a teaser.
Webinar: Customize Content Pages using Display Suite in Drupal 8
The quest for performance improvements - 5th sprint
The last two days we spent another sprint at socialist party to improve performance. And again we used a guy with database knowledge to analyze our queries. We have optimized a few things so far one of the major areas to improve next was the ACL part of queries. That is the part of the query to decide which contacts you are allowed to see. So at the socialist party they have local chapter administrator who are only allowed to see the active members in their local area.
To decide which contacts you are allowed to see a search query is rebuild to include this ACL part. So there is a join on the membership table and a join on the chapter-structure table and then a where expression is to filter on the chapter and to filter on active memberships. Meaning that the MySQL will scan all records in the table civicrm_contact which at the socialist party is around 350.000.
We have worked on a proof-of-concept solution so far which is to create a table with the user_id and which contact_ids the user is allowed to see. We then do a join on this table resulting that only that subset of contacts is scanned by mysql. Which in fact improved the search query from running a few seconds to just a few milliseconds.
When a user logs in we check how long ago it was when we last updated this table and if it is longer than 24 hours we will delete the entries for that user and re-insert the entries.
We have also reported this at the CiviCRM issue Queue see: https://issues.civicrm.org/jira/browse/CRM-19934
The next thing we are going to work on is to make the proof-of-concept stable and do some refactoring of the core civicrm_acl_contact_cache table. As this proof-of-concept looks like a bit what civicrm_acl_contact_cache should do but does not do. Also we want to add a setting in the user interface where site-administrators could set the value for the validity time.
We are also wondering what your thoughts are about our performance quest so far and about our proposed solution.
Drupal
Drupal 8 DIY: Creating Content Tabs with Theme Libraries and Slick
![](http://web.archive.org./web/20170130000224im_/https://dev.acquia.com/sites/default/files/styles/blog__190_x110_/public/blog/lidar2.png?itok=ea0EJQ6S)
Continuing from our previous post, Drupal 8 DIY: Creating a Slideshow with Theme Libraries and Slick, we wanted to build on the power of theme libraries provide us in Drupal 8.
Tags: acquia drupal planet245: Drupal Association Board Community Elections 2017 - meet Megan Sanicki
![DrupalCon-2013-BrokenBanjo-6.jpg - Photo by Trav Williams, Broken Banjo Photography www.BrokenBanjo.net DrupalCon-2013-BrokenBanjo-6.jpg - Photo by Trav Williams, Broken Banjo Photography www.BrokenBanjo.net](http://web.archive.org./web/20170130000224im_/https://dev.acquia.com/sites/default/files/styles/blog_node_image/public/podcast/images/8810235392_4d108003a2_k.jpg?itok=H7q_FlV9)
In this podcast and video, Megan Sanicki, Executive Director of the Drupal Association, and I talk about what the DA Board is all about and why you might want to run for a community directorship. The 2nd half of the podcast is also a chance to get to know Megan. Megan fell in love with the intersection of tech and community work and has been with us in the community since 2009 (or 2010, she's not sure ...).
Talking about the business side of Drupal, I really like what she has to say:
Should you run for the Drupal Association Board of Directors?"It's more important to me how we move through life together as a community to create amazing software."
One interesting aspect of the DA Board that sets it apart from the rest of the community is that it goes against the grain, the nature of how we usually go about things. We're a community of doers. If you want to fix something specific, there are probably better places for you in the Drupal community, places where you can get busy, help, and improve stuff. The Board is an odd corner of the Drupal community where it's not about getting things done. I imagine a lot of people would be frustrated by that.
Listen to my conversation with Megan and if you want to serve the community in this capacity, here's what you need to do:
- Self-nomination for the election runs February 1-19, 2017.
- Read Megan's blog post 2017 Community Board Election Begins 1 February.
- Follow any of the links it contains to get a full picture of the process.
- Watch the Community Election Candidate Brief video (also embedded in Megan's post). Request a transcript if you need one.
- Read the Drupal Association bylaws
- Read the board member agreement
- Read The Drupal Association mission statement
- The 2017 Drupal Association Board Elections page contains further information and it is where you can begin your self-nomination from February 1 to 19, 2017.
- Michael Schmid and I recorded a follow up and analysis of the 2016 DA Board community election that I published audio and video of as Acquia Podcast 225.
- I recorded a conversation with the 2016 DA Board community election, Shyamala Rajaram and published audio and video of it as Acquia Podcast 243.
Transitioning from Drupal 7 to Drupal 8: programatically creating blocks
If you are used to creating Drupal 7 modules, one of the major challenges of moving to Drupal 8 is all the changes under the hood. Almost everything has changed and that can be very overwhelming. But it doesn't have to be. One method to learn how to create Drupal 8 modules is to compare it to what you are used to in Drupal 7 module development.