Drupal News

Xeno Media: Xeno Media's Jim Birch presents at DrupalCamp Northern Lights 2017

Planet Drupal -

Organized by the Icelandic Drupal community, the inaugural Northern Lights Drupal Camp will take place on the this weekend, February 24th - 26th, 2017 at the University of Iceland in Reykjavik. We are honored that our Digital Strategist, Jim Birch was invited to speak.

Jim will present his Holistic SEO and Drupal talk--which covers the modern state of Search Engine Optimization and how we at Xeno Media define best practices for technical SEO using Drupal.  It also presents ideas on how to guide and empower clients to create the best content to achieve their digital goals.

This presentation will review:

  • What Holistic SEO is, and some examples of modern search results explained.
  • The most common search engine ranking factors, and how to keep up to date.
  • An overview of Content strategy and how it can guide development.
  • An overview of technical SEO best practices in Drupal.

The presentation is:

  • Session time slot: Sunday 15:15 - 16:00
  • Session room: Room Eyjajallajökull

View the full schedule.

J-P Stacey: Last of the Drupal 8 API blogposts... for now, anyway

Planet Drupal -

I've been having tremendous fun writing tutorials about each of the Drupal 8 APIs in turn, and I hope people have been finding them useful. They've certainly been eye-openers for me, as I've always focussed on achieving a clear worked example, and doing that alone unearths all sorts of questions (and usually—but not always—answers) about how Drupal 8's core itself works.

Read more of "Last of the Drupal 8 API blogposts... for now, anyway"

Wim Leers: OpenTracker

Planet Drupal -

This is an ode to Dirk Engling’s OpenTracker.

It’s a BitTorrent tracker.

It’s what powered The Pirate Bay in 2007–2009.

I’ve been using it to power the downloads on http://driverpacks.net since the end of November 2010. >6 years. It facilitated 9839566 downloads since December 1, 2010 until today. That’s almost 10 million downloads!

Stability

It’s one of the most stable pieces of software I ever encountered. I compiled it in 2010, it never once crashed.

[email protected]:~$ ls -al /data/opentracker total 456 drwxr-xr-x 3 wim wim 4096 Feb 11 01:02 . drwxr-x--x 10 root wim 4096 Mar 8 2012 .. -rwxr-xr-x 1 wim wim 84824 Nov 29 2010 opentracker -rw-r--r-- 1 wim wim 3538 Nov 29 2010 opentracker.conf drwxr-xr-x 4 wim wim 4096 Nov 19 2010 src -rw-r--r-- 1 wim wim 243611 Nov 19 2010 src.tgz -rwxrwxrwx 1 wim wim 14022 Dec 24 2012 whitelist Simplicity

The simplicity is fantastic. Getting up and running is fantastically simple: git clone git://erdgeist.org/opentracker .; make; ./opentracker and you’re up and running. Let me quote a bit from its homepage, to show that it goes the extra mile to make users successful:

opentracker can be run by just typing ./opentracker. This will make opentracker bind to 0.0.0.0:6969 and happily serve all torrents presented to it. If ran as root, opentracker will immediately chroot to . and drop all priviliges after binding to whatever tcp or udp ports it is requested.

Emphasis mine. And I can’t emphasize my emphasis enough.

Performance & efficiency

All the while handling dozens of requests per second, opentracker causes less load than background processes of the OS. Let me again quote a bit from its homepage:

opentracker can easily serve multiple thousands of requests on a standard plastic WLAN-router, limited only by your kernels capabilities ;)

That’s also what it said in 2010. I didn’t test it on a “plastic WLAN-router”, but everything I’ve seen confirms it.

Flexibility

Its defaults are sane, but what if you want to have a whitelist?

  1. Uncomment the #FEATURES+=-DWANT_ACCESSLIST_WHITE line in the Makefile.
  2. Recompile.
  3. Create a file called whitelist, with one torrent hash per line.

Have a need to update this whitelist, for example a new release of your software to distribute? Of course you don’t want to reboot your opentracker instance and lose all current state. It’s got you covered:

  1. Append a line to whitelist.
  2. Send the SIGHUP UNIX signal to make opentracker reload its whitelist1.
Deployment

I’ve been in the process of moving off of my current (super reliable, but also expensive) hosting. There are plenty of specialized HTTP server hosts2 and even rsync hosts3. Thanks to their standardization and consequent scale, they can offer very low prices.

But I also needed to continue to run my own BitTorrent tracker. There are no hosts that offer that. I don’t want to rely on another tracker, because I want there to be zero affiliation with illegal files. This is a BitTorrent tracker that does not allow anything to be shared: it only allows the software releases made by http://driverpacks.net to be downloaded.

So, I found the cheapest VPS I could find, with the least amount of resources. For USD $13.504, I got a VPS with 128 MB RAM, 12 GB of storage and 500 GB of monthly traffic. Then I set it up:

  1. ssh‘d onto it.
  2. rsync‘d over the files from my current server (alternatively: git clone and make)
  3. added @reboot /data/opentracker/opentracker -f /data/opentracker/opentracker.conf to my crontab.
  4. removed the CNAME record for tracker.driverpacks.net, and instead made it an A record pointing to my new VPS.
  5. watched http://tracker.driverpacks.net:6969/stats?mode=tpbs&format=txt on both the new and the old server, to verify traffic was moving over to my new cheap opentracker VPS as the DNS changes propagated
Drupal module

Since driverpacks.net runs on Drupal, there of course is an OpenTracker Drupal module which I wrote. It provides an API to:

  • create .torrent files for certain files uploaded to Drupal
  • append to the OpenTracker whitelist file 5
  • parse the statistics provided by the OpenTracker instance

You can see the live stats at http://driverpacks.net/stats.

Conclusion

opentracker is the sort of simple, elegant software design that makes it a pleasure to use. And considering the low commit frequency over the past decade, with many of those commits being nitpick fixes, it also seems its simplicity also leads to excellent maintainability. It involves the HTTP and BitTorrent protocols, yet only relies on a single I/O library, and its source code is very readable. Not only that, but it’s also highly scalable.

It’s the sort of software many of us aspire to write.

Finally, its license. A glorious license indeed.

The beerware license is very open, close to public domain, but insists on honoring the original author by just not claiming that the code is yours. Instead assume that someone writing Open Source Software in the domain you’re obviously interested in would be a nice match for having a beer with.

So, just keep the name and contact details intact and if you ever meet the author in person, just have an appropriate brand of sparkling beverage choice together. The conversation will be worth the time for both of you.

Dirk, if you read this: I’d love to buy you sparkling beverages some time :)

  1. kill -s HUP pidof opentracker ↩︎

  2. I’m using Gandi’s Simple Hosting↩︎

  3. https://rsync.net ↩︎

  4. $16.34 including 21% Belgian VAT. ↩︎

  5. reload */10 * * * * kill -s HUP pidof opentracker ↩︎

  • DriverPacks.net
  • Drupal
  • deployment
  • open source

Web Wash: How to Create Responsive Image Galleries using Juicebox in Drupal 8

Planet Drupal -

There are a lot of image gallery libraries out there, but today I want to show you how to use Juicebox. Juicebox is an HTML5 responsive image gallery and it integrates with Drupal using the Juicebox module. Juicebox is not open source, instead it offers a free version which is fully useable but you are limited to 50 images per gallery. The pro version allows for unlimited images and more features. If you’re looking for an alternative solution look at Slick, which is open source, and it integrates with Drupal via the Slick module. I will cover this module in a future tutorial. In this tutorial, you’ll learn how to display an image gallery from an image field and how to display a gallery using Views.

Building an Enterprise React Application, Part 1

Lullabot -

Last year, Lullabot was asked to help build a large-scale React application for a major U.S. media company and, lucky for me, I was on the team. An enterprise React application is often part of a complex system of applications, and that was certainly the case for this project. What follows is part one of our discussion. It includes a high-level view of the overall application architecture as well as a look at the specific architecture used for the React part of the project that was the focus of my work.

Web Application Architecture

Take a quick look at the diagram below. It describes the high-level architecture of the collection of applications that comprise the site. It begins with the content management system, or CMS. In this project, the CMS was Drupal, but this could just as well have been Wordpress or any number of alternatives—basically, software for editorial use that allows non-technical content creators to add pages, define content relationships, and perform other common editorial tasks. No pages or views are served to users directly from the CMS.

undefined

It’s not uncommon to have additional data sources besides the CMS feeding the API, as was the case on this project. In that sense our diagram oversimplifies things, but it does give a good sense of the data flows.

The API The API is software that provides a consistent view into the data of the CMS (as well as other data sources, when present). The database in a CMS like Drupal is normalized. One important task of the API is to de-normalize this data, which allows clients—web browsers, mobile apps, smart TVs, etc.—to make fewer round trips.

The API is a critical part of the application. The real business case for an architecture like this is to have a single data source serve content across a range of platforms in a consistent, efficient way. Client devices make an HTTP request to the API and receive a response with the requested data, usually in JSON format.

Caching Layers Having a caching layer in front of your API and Node.js servers helps reduce load on the API server and decreases response time. Our client uses Akamai as a CDN and caching solution, but there are many other options.

Node.js Server We’ve finally gotten to where the code for the React web app lives. We used the server-side JavaScript application framework, Express, on the project. Express was used to create an HTTP server that responds to requests from web clients. It’s also where we did the server-side rendering of the React application.

Clients In the diagram, I’ve added icons to represent mobile apps and web browsers, respectively, but any number of devices may consume the API’s data For example, our client serves not only web browsers and a mobile app from the API, but also Roku boxes and Samsung TVs.

What’s happening with the web client is pretty interesting. The first request by a browser goes to the Node.js server, which will return the pre-rendered first page. This is server-side React and it’s helping provide a faster load time.

Without rendering first on the server, the client would have to retrieve the page and then begin rendering, creating a lag on first load as well as potentially having an adverse impact on SEO. Subsequent pages will be routed on the client using a library like React Router. The app will then make requests directly to the API for the data it needs for a specific “page” or route.

React Architecture

When thinking of JavaScript application architecture, the MVC pattern immediately comes to mind for many people. React isn’t a MVC framework like Angular or Ember, but is instead a library that handles views. If that’s the case, then what architecture does a typical large-scale React application use?

On this project, we used Redux. Redux is a both a library and an architecture/pattern that is influenced by the Flux architecture from Facebook.

Two distinguishing characteristics of Redux are strict unidirectional data flow (shared with Flux) and storing all application state as a single object. The data lifecycle in a Redux app has four steps:

  1. Dispatch an action.
  2. Call to a reducer function.
  3. A root reducer combines the output of the various reducer functions into a single state tree.
  4. The store saves the state returned by the root reducer triggering view updates.

The diagram below illustrates this data flow:

undefined

Let’s walk through this step by step.

1. Dispatch an action Let’s say you have a list of items displayed in a component (represented by the blue box in the diagram) and you’d like the user to be able to delete an item when clicking a button next to the item. When a button is clicked, there will be a call to the Redux dispatch function. It’s a common pattern to also pass a call to an action creator into this function. It may look something like this:

dispatch(deleteItem(itemID));

In the example above, the function deleteItem is an action creator (yellow box). Action creators return plain JavaScript objects (orange box). In our case the return object looks like this:

{ type: 'DELETE_ITEM', itemId: itemId }

Note that actions must always have a type property. In this simple example, we could have just passed the plain object in the dispatch function and it would have worked just fine. However, an advantage to using an action creator is that they can be used to transform the data before it’s passed to the reducer. For example, action creators are a great place for API calls, adding timestamps or anything else that may cause side effects.

2. Call to a reducer function Once the action creator returns the action to the dispatch function, the store then calls the reducer function (green box). The store passes two things to the reducer: the current state and the action. An important thing to note is that Redux reducers must be pure functions. Passing the same input to a reducer function should result in exactly the same output every time.

The reducer then computes the next state. It does this using a switch statement that checks for the action type, which in our example case is “DELETE_ITEM”, and then returns the new state. An important point here is that state is immutable in Redux. The state object is never changed directly, but rather a new state object is created and returned based on the specified action passed to the reducer.

In our example this might look like this:

// The code below is part of our itemsReducer. Default state is defined in reducer // function definition. switch (action.type) { case DELETE_ITEM: return { ...state, lastItemDeleted: action.itemId }; default: return state }

3. Root reducer combines reducer output into a single state tree A very common pattern is to split your reducer functions into separate files based on what part of the app they address. For example, we might have a file in our hypothetical app called itemsReducer and perhaps another one called usersReducer.

The output of these two reducers will then be combined into a single state object when you call the Redux combineReducers function.

4. The store saves the state returned by the root reducer Finally the store saves the state and all the subscribers (your components) will receive the updated state and the view will be updated as needed.

That’s a general overview of what a Redux architecture looks like. It’s obviously missing many implementation details. To learn more about how Redux works, I highly recommend reading the documentation in its entirety. The Redux docs are very well written and comprehensive. If you prefer video tutorials, Dan Abramov, the creator of Redux, has a couple of great courses here and here.

If you’re interested in getting a quick start playing around with React and Redux, I’ve put together a boilerplate project that’s a good starting point for building a medium-to-large application. It’s informed by many of the lessons learned working on this project.

Until Next Time…

Enterprise applications are often enormously complicated and take the efforts of multiple, dedicated teams each specializing in one area of the application. This is particularly true if the technology stack is diverse. If you’re new to a big project like I’ve described here, try to get a good handle on the architecture, the workflows, the roles of other teams, as well as the tools you are using to build the application. This big picture view will help you produce your best work.

Next week we’ll publish part two, where we’ll go over the build tools and processes we used on the project as well as how we organized the code.

Web Omelette: How to render your images with image styles in Drupal 8

Planet Drupal -

In this article we are going to look at how we can render images using image styles in Drupal 8.

In Drupal 7, rendering images with a particular style (say the default "thumbnail") was by calling the theme_image_style() theme and passing the image uri and image style you want to render (+ some other optional parameters):

$image = theme('image_style', array('style_name' => 'thumbnail', 'path' => 'public://my-image.png'));

You'll see this pattern all over the place in Drupal 7 codebases.

The theme prepares the URL for the image, runs the image through the style processors and returns a themed image (via theme_image()). The function it uses internally for preparing the url of the image is image_style_url() which returns the URL of the location where the image is stored after being prepared. It may not yet exist, but on the first request, it would get generated.

So how do we do it in Drupal 8?

First of all, image styles in Drupal 8 are configuration entities. This means they are created and exported like many other things. Second of all, in Drupal 8 we no longer (should) call theme functions like above directly. What we should do is always return render arrays and expect them to be rendered somewhere down the line. This helps with things like caching etc.

So to render an image with a particular image style, we need to do the following:

$render = [ '#theme' => 'image_style', '#style_name' => 'thumbnail', '#uri' => 'public://my-image.png', // optional parameters ];

This would render the image tag with the image having been processed by the style.

Finally, if we just want the URL of an image with the image style applied, we need to load the image style config entity and ask it for the URL:

$style = \Drupal::entityTypeManager()->getStorage('image_style')->load('thumbnail'); $url = $style->buildUrl('public://my-image.png');

So that is it. You now have the image URL which will generate the image upon the first request.

Remember though to inject the entity type manager if you are in such a context that you can.

Drupal Association membership campaign: February 20 to March 8

Drupal News -

Drupal.org is home of the Drupal project and the Drupal community. It has been continuously operating since 2001. The Engineering Team— along with amazing community webmasters— keeps Drupal.org alive and well. As we launch the first membership campaign of 2017, our story is all about this small and productive team.

Join us as we celebrate all that the engineering team has accomplished. From helping grow Drupal adoption, to enabling contribution; improving infrastructure to making development faster. The team does a lot of good for the community, the project, and Drupal.org.

Check out some of their accomplishments and if you aren't yet a Drupal Association member, join us! Help us continue the work needed to make Drupal.org better, every day.

Share these stories with others - now until our membership drive ends on March 8.

Share

Tweet

Share

Thank you for supporting our work!

Drupal Association blog: Drupal Association membership campaign: February 20 to March 8

Planet Drupal -

Drupal.org is home of the Drupal project and the Drupal community. It has been continuously operating since 2001. The Engineering Team— along with amazing community webmasters— keeps Drupal.org alive and well. As we launch the first membership campaign of 2017, our story is all about this small and productive team.

Join us as we celebrate all that the engineering team has accomplished. From helping grow Drupal adoption, to enabling contribution; improving infrastructure to making development faster. The team does a lot of good for the community, the project, and Drupal.org.

Check out some of their accomplishments and if you aren't yet a Drupal Association member, join us! Help us continue the work needed to make Drupal.org better, every day.

Share these stories with others - now until our membership drive ends on March 8.

Share

Tweet

Share

Thank you for supporting our work!

Learn Drupal 8 Theming and more at MidCamp

Twin Cities Drupal Group -

Drupalize.Me is excited to be going to MidCamp this year! If you haven't been before, it's a really well-run camp that offers a lot of fun and opportunity. This year, in addition to attending the camp, Joe and Blake are going to running a full-day workshop on Drupal 8 theming. This is one of four different workshops you can attend at the MidCamp Training Day, which is on Thursday, March 30th. In addition to our theming class, you can choose from an Introduction to Drupal 8, Drupal Development Best Practice Workflows on Pantheon, and A Drupal Crash Course for Non-developers.

The workshops are all only $40 for the full day (thanks to so many great camp sponsors!), so it's a great opportunity to learn from some very knowledgeable Drupal folks.

Gábor Hojtsy: Improving Drupal 8's usability and the impact

Planet Drupal -

We started regular Drupal usability meetings twice a week almost a year ago in March 2016. That is a long time and we succeeded in supporting many key initiatives in this time, including reviews on new media handling and library functionality, feedback on workflow user experience, outside-in editing and place block functionality. We helped set scope for the changes required to inline form errors on its way to stability. Those are all supporting existing teams working on their respective features where user interfaces are involved.

However, we also started to look at some Drupal components and whether we can gradually improve them. One of the biggest tasks we took on was redesigning the status page, where Drupal's system information is presented and errors and warnings are printed for site owners to resolve. While that looks like a huge monster issue, Roy Scholten in fact posted a breakdown of how the process itself went. If we were to start a fresh issue (which we should have), the process would be much easier to follow and would be more visible. The result is quite remarkable:

Drupal core announcements: Updates from Drupal 8 core initiatives for February 2017

Planet Drupal -

Now that Drupal 8.3 is in beta, it is time to look at progress around core initiatives again and see how you can help move one or more of them forward. Once again I asked initiative contributors to help compile this post to inform you all of progress across the board. This is just a sampling of some improvements, there are a lot more that we could not cover here.

Default content and new core theme

The default content and new core theme teams decided to join forces because the goals are intertwined. The teams found it hard to demonstrate good default content without a supporting visual look and vice versa. The plan to go with a farmer's market site changed to a more general publication site, but that still allows for plenty of things to showcase. We are looking for a designer / art director for the project (deadline today!).

Use the Slack channel if you want to help or if you just want to follow our progress. Get an invite at https://drupaltwig-slack.herokuapp.com/.

Media

The media team held a sprint in Berlin in December. Unfortunately none of these media improvements landed in Drupal 8.3, however we are very close to complete the base media functionality early in Drupal 8.4. There was significant progress on the visual media library too. Next step is to finalise the plugins for images, documents and oEmbed.

Join in the #drupal-media channel on IRC.

Migrate

The Migrate API became beta in Drupal 8.2.x with 8.2.5 and will apply to 8.3.0 as well. On the other hand other parts of the migration system like the Migrate Drupal API are still alpha stability and received some big updates. Two huge additions are the migration path for Drupal 7 node translations to Drupal 8 content translation and support added for configuration translations (and implemented initially for user profile fields).

Join in the #drupal-migrate channel on IRC.

Multilingual

Most of the recent progress on the multilingual initiative was in collaboration with the migration team and that is still heavily ongoing. Further feature development around multilingual features is not on the table currently, as most contributors moved on to more pressing areas given the advances achieved in multilingual with Drupal 8 already. Therefore it is being proposed to officially remove the multilingual initiative from the list.

PHPUnit

The work in the PHPUnit initiative is focusing on converting a large part of old Simpletest web tests to PHPUnit based browser tests. The goal is to commit a larger patch on February 21st to the Drupal 8.3.x branch. After that one third of Drupal core’s web tests would be converted to PHPUnit browser tests. We are also discussing the timeline for deprecating Simpletest.

We are also working on improving our JavaScript browser tests in multiple issues. For documentation there is also a Javascript browser test tutorial now!

If you want to convert your tests in your contrib / custom module, please read the PHPUnit browser test tutorial and help out on https://www.drupal.org/node/2794285 in case you run into problems. Please follow the PHPUnit initiative issue for status updates. Join us in IRC in #drupal-phpunit.

(This update written by klausi & dawehner)

Workflow

The biggest user facing change with workflows since the last update is the introduction of the Workflows module as a separate concept from content moderation. Now other modules can use workflows for user levels, commerce and other needs as well, when the workflow has nothing to do with content moderation. Many API changes were also made including support for moderation of non-translatable entity types and entity types without bundles (as long as revisions are enabled). Publishing entities implementing EntityPublishedInterface is also possible now, not just nodes.

Wondering how to join an initiative? Meeting information for each initiative is listed at https://groups.drupal.org/node/514585

Drupal core announcements: A big chunk of old tests using WebTestBase wil be converted to PHPUnit BrowserTestBase on Feb 21st

Planet Drupal -

Start:  2017-02-21 18:00 Europe/Vienna Event type:  Online meeting (eg. IRC meeting)

As part of the PHPUnit initiative a considerable part of Simpletests will be converted to PHPUnit based browser tests on February 21st 2017. A backwards compatibility layer has been implemented so that many Simpletests can be converted by just using the new BrowserTestBase base class and moving the test file. There is also a script to automatically convert test files in the conversion issue.

Developers are encouraged to use BrowserTestBase instead of Simpletest as of Drupal 8.3.0, but both test systems are fully supported during the Drupal 8 release cycle. The timeline for the deprecation of Simpletest's WebTestBase is under discussion.

You can now use Google Authenticator and any TOTP app for Two-Factor Authentication

Cloudflare Blog -

Since the very beginning, Cloudflare has offered two-factor authentication with Authy, and starting today we are expanding your options to keep your account safe with Google Authenticator and any Time-based One Time Password (TOTP) app of your choice.

If you want to get started right away, visit your account settings. Setting up Two-Factor with Google Authenticator or with any TOTP app is easy - just use the app to scan the barcode you see in the Cloudflare dashboard, enter the code the app returns, and you’re good to go.

Importance of Two-Factor Authentication

Often when you hear that an account was ‘hacked’, it really means that the password was stolen.

If the media stopped saying 'hacking' and instead said 'figured out their password', people would take password security more seriously.

— Khalil Sehnaoui (@sehnaoui) January 5, 2017

Two-Factor authentication is sometimes thought of as something that should be used to protect important accounts, but the best practice is to always enable it when it is available. Without a second factor, any mishap involving your password can lead to a compromise. Journalist Mat Honan’s high profile compromise in 2012 is a great example of the importance of two-factor authentication. When he later wrote about the incident he said, "Had I used two-factor authentication for my Google account, it’s possible that none of this would have happened."

What is a TOTP app?

TOTP (Time-based One Time Password) is the mechanism that Google Authenticator, Authy and other two-factor authentication apps use to generate short-lived authentication codes. We’ve written previously on the blog about how TOTP works.

We didn’t want to limit you to only using two-factor providers that we'd built integrations with, so we built an open TOTP integration in the Cloudflare dashboard, allowing you to set up two-factor with any app that implements TOTP. That means you can choose from a wide array of apps for logging into Cloudflare securely with two-factor such as Symantec, Duo Mobile and 1Password.

Get Started

If you want to enable Two-Factor Authentication with Google Authenticator or any other TOTP provider, visit your account settings here. It’s easy to set up and the best way to secure your account. We also have step by step instructions for you in our knowledge base.

Valuebound: Beginner’s guide to Mail System in Drupal 7 and 8

Planet Drupal -

This blog is all about How Drupal handles the Mail system & the stages it has to go through.
In Drupal to sends an email we need to take care of two rules

  1. Declare all the required properties under hook_mail().
  2. Call drupal_mail() with argument for actually sending the email

However in the scenario like bigger & complex site the above steps won’t be enough. But Drupal gives us a Flexibility to customize email sending process, before that it’s necessary to know how stuff works behind the scenes first. In this article I’ll show you how you can customize and extend the Drupal mail system to fulfill your needs.

While sending an email drupal_mail() function uses system class for…

Pages

Subscribe to Cruiskeen Consulting LLC aggregator - Drupal News