All RPGs and Storygames by Tod Foley are now available at DrivethruRPG and RPGnow. Bring these games to your table!
This module allows to authenticate Drupal resources through the DocCheck login (basic license) mechanism
Block (DocCheck Basic) and page (/doccheck-login) are available.
Hello, Drupal community! My name is Brooke Candelaria, and I’m excited to join the Drupal Association as your new conference director. This is a significant opportunity to support a smart, creative and ambitious community by helping to build event experiences that foster deep learning, meaningful connections, astounding ideas, new partnerships, project incubations and, of course, fun.
Working at the heart of the open source community is an honor and a privilege. This community knows how to collaborate exceedingly well. This community views ‘that can’t be done’ as a throw-down and will mobilize a sprint to do it. This community is glued together by shared purpose, and individually our members want to be part of something bigger than themselves. This is why we’re working hard to ensure that DrupalCon provides purposeful community-based experiences that you can’t get elsewhere.
I’ve been working in communications, PR and event management roles in the tech community for many years. Originally from upstate New York, I’ve worked in Boston, London, Austin and Houston. I worked on the LinuxWorld tradeshow at a time when open source was attracting attention from a large cross-section. Most recently, I’ve been serving the Python user community - also a very dedicated and enthusiastic base.
I’ve been living in Houston for a decade. It’s a vast and diverse city where we compensate for oppressive heat and hurricanes with our Southern hospitality, vibrant art scene and more than 10,000 restaurants. Oh, and did I mention the World Champion Houston Astros?
When not hosting guests at our AirBnB, I’m all about travel (especially international), volunteering, cooking and participating in local cultural events.
This module provides a simple additional feature to redirect module https://www.drupal.org/project/redirect. It allows us to add redirect from a node. This is similar to the Drupal 7 feature provided by the redirect module.
As part of the Decoupled Hard Problems series, in this fourth article, I'll discuss some of the challenges surrounding routing, custom paths and URL aliases in decoupled projects.Decoupled Routing
It's a Wednesday afternoon, and I'm using the time that Lullabot gives me for professional development to contribute to Contenta CMS. Someone asks me a question about routing for a React application with a decoupled Drupal back-end, so I decide to share it with the rest of the Contenta Slack community and a lengthy conversation ensues. I realize the many tendrils that begin when we separate our routes and paths from a more traditional Drupal setup, especially if we need to think about routing across multiple different consumers.
It's tempting to think about decoupled Drupal as a back-end plus a JS front-end application. In other words, a website. That is a common use case, probably the most common. Indeed, if we can restrict our decoupled architecture to a single consumer, we can move as many features as we want to the server side. Fantastic, now the editors who use the CMS have many routing tools at their disposal. They can, for instance, configure the URL alias for a given node. URL aliases allow content editors to specify the route of a web page that displays a piece of content. As Drupal developers, we tend to make no distinction between such pieces of content and the web page that Drupal automatically generates for it. That's because Drupal hides the complexity involved by making reasonable assumptions:
- It assumes that we need a web page for each node. Each of those has a route node/<nid> and they can have a custom route (aka URL alias).
- It means that it is okay to add presentation information in the content model. This makes it easy to tell the Twig template how to display the content (like field_position = 'top-left') in order to render it as the editor intended.
Unfortunately, when we are building a decoupled back-end, we cannot assume that our pieces of content will be displayed in a web page, even if our initial project is a website. That is because when we eventually need a second consumer, we will need to make amends all over the project to undo those assumptions before adding the new consumer.
Understand the hidden costs of decoupling in full. If those costs are acceptable—because we will take advantage of other aspects of decoupling—then a rigorous separation of concerns that assigns all the presentation logic to the front-end will pay off. It takes more time to implement, but it will be worth it when the time comes to add new consumers. While it may save time to use the server side to deal with routing on the assumption that our consumer will be a single website, as soon as a new consumer gets added those savings turn into losses. And, after all, if there is only a website, we should strongly consider a monolithic Drupal site.undefined
After working with Drupal or other modern CMSes, it's easy to assume that content editors can just input what they need for SEO purposes and all the front-ends will follow. But let's take a step back to think about routes:
- Routes are critical only for website clients. Native applications can also benefit from them, but they can function with just the resource IDs on the API.
- Routes are important for deep linking in web and native applications. When we use a web search engine in our phone and click a link, we expect the native app to open on that particular content if we have it installed. That is done by mapping the web URL to the app link.
- Links are a great way to share content. We want users to share links, and then let the appropriate app on the recipient's mobile device open if they have it installed.
It seems clear that even non-browser-centric applications care about the routes of our consumers. Luckily, Drupal considers the URL alias to be part of the content, so it's available to the consumers. But our consumers' routing needs may vary significantly.Routing From a Web Consumer
Let's imagine that a request to http://cms.contentacms.io/recipes/4-hour-lamb-stew hits our React application. The routing component will know that it needs to use the recipes resource and find the node that has a URL alias of /4-hour-lamb-stew. Contenta can handle this request with JSON API and Fieldable Path—both part of the distribution. With the response to that query, the React app builds all the components and displays the results to the user.
It is important to note the two implicit assumptions in this scenario. The first is that the inbound URL can be tokenized to extract the resource to query. In our case, the URL tells us that we want to query the /api/recipes resource to find a single item that has a particular URL alias. We know that because the URL in the React side contains /recipes/... What happens if the SEO team decides that the content should be under https://cms.contentacms.io/4-hour-lamb-stew? How will React know that it needs to query the /api/recipes resource and not /api/articles?
The second assumption is that there is a web page that represents a node. When we have a decoupled architecture, we cannot guarantee a one-to-one mapping between nodes and pages. Though it's common to have the content model aligned with the routes, let's explore an example where that's not the case. Suppose we have a seasonal page in our food magazine for the summer season (accessible under /summer). It consists of two recipes, and an article, and a manually selected hero image. We can build that easily in our React application by querying and rendering the content. However, everything—except for the data in the nodes and images—lives in the react application. Where does the editor go to change the route for that page?
On top of that, SEO will want it so that when a URL alias changes (either editorially or in the front-end code) a redirect occurs, so people using the old URL can still access the content. Note that a change in the node title could trigger a change in the URL alias via Pathauto. That is a problem even in the "easy" situation. If the alias changes to https://cms.contentacms.io/recipes/four-hour-stewed-lamb, we need our React application to still respond to the old https://cms.contentacms.io/recipes/4-hour-lamb-stew. The old link may have been shared in social networks, linked to from other sites, etc. The problem is that there is no recipe with an alias of /recipes/4-hour-lamb-stew anymore, so the Fieldable Path solution will not cover all cases.Possible Solutions
In monolithic Drupal, we'd solve the aforementioned SEO issue by using the Redirect module, which keeps track of old path aliases and can respond to them with a redirect to the new one. In decoupled Drupal, we can use that same module along with the new Decoupled Router module (created as part of the research for this article).
Pages—or visualizations—that comprise a disconnected selection of entities—our /summer page example—are hard to manage from the back-end. A possible solution could be to use JSON API to query the entities generated by Page Manager. Another possible solution would be to create a content type, with its corresponding resource, specific for that presentation in that particular consumer. Depending on how specific that content type is for the consumer, that will take us to the Back-end For Front-end pattern, which incurs other considerations and maintenance costs.
For the case where multiple consumers claim the same route but have that route resolve to different nodes, we can try the Contextual Aliases module.The Decoupled Router
Decoupled Router is an endpoint that receives a front-end path and tries to resolve it to an entity. To do so it follows as many redirects and URL aliases as necessary. In the example of /recipes/four-hour-stewed-lamb it would follow the redirect down to /recipes/4-hour-lamb-stew and resolve that URL alias to node:1234. The endpoint provides some interesting information about the route and the underlying entity.undefined
In a previous post, we discussed how multiple requests degrade performance significantly. With that in mind, making an extra request to resolve the redirects and aliases seems less attractive. We can solve this problem using the Subrequests module. Like we discussed in detail, we can use response tokens to combine several requests in one.
Imagine that we want to resolve /bread and display the title and image. However, we don’t know if /bread will resolve into an article or a recipe. We could use Subrequests to resolve the path and the JSON API entity in a single request.undefined
In the request above, we provide the path we want to resolve. Then we get the following response.undefined
To summarize, we can use Decoupled Router in combination with Subrequests to resolve multiple levels of redirects and URL aliases and get the JSON API data all in a single request. This solution is generic enough that it serves in almost all cases.Conclusion
Routing in decoupled applications becomes challenging because of three factors:
- Instead of one route, we have to think about (at least) two, one for the front-end and one for the back-end. We can mitigate this by keeping them both in sync.
- Multiple consumers may decide different routing patterns. This can be mitigated by reaching an agreement among consumers. Another alternative is to use Contextual Aliases along with Consumers. When we want back-end changes that only affect a particular consumer, we can use the Consumers module to make that dependency explicit. See the Consumer Image Styles module—explained in a previous article—for an example on how to do this.
- Some visualizations in some of the consumers don’t have a one-to-one correspondence with an entity in the data model. This is solved by introducing dedicated content types for those visualizations. That implies that we have access to both back-end and front-end. A custom resource based on Page Manager could work as well.
In general, whenever we need editorial control we'll have to turn to the back-end CMS. Unfortunately, the back-end affects all consumers, not just one. That may or may not be acceptable, depending on each project. We will need to make sure to consider this when thinking through paths and aliases on our next decoupled Drupal project.
Lucky for us, every project has constraints we can leverage. That is true even when working on the most challenging back-end of all—a public API that powers an unknown number of 3rd-party consumers. For the problem of routing we can leverage these constraints to use the mitigations listed above.
Hopefully, this article will give you some solutions for your Decoupled Drupal Hard Problems.
The issue of workforce diversity has been in the news a lot lately, and rightfully so. Diversity data is pretty dismal, particularly in the technology industry. Essentially, there is a long history of white males disproportionately holding leadership roles and minorities being immensely underrepresented. You already knew that though.
A base feature providing a resource content type and related configuration.
Development is on GitLab and mirrored here.
Allows to exclude certain configuration forms to be editable, when the site is on configuration read-only mode.
Filters can be created with set of form id or route name. Since filters are config entities, can be exported/imported like any other configuration.
1. Filter by Form ID
2. Filter by Route name - This is not supported yet.
Simple module that allows lookups of addressesRoadmap
Currently takes postcode and returns longitude and latitude
Import coupons from a CSV file into a selected promotion on Drupal Commerce. For promotions such as Groupon.
At DrupalSouth 2017, I presented a session on the new Workflows module, which just went stable in Drupal 8.4.0. Workflows was split out from content moderation as a separate module, and can be used independently to create custom workflows. In this presentation, I gave a demonstration of how to create a basic workflow for an issue tracker.by Kim Pepper / 29 November 2017
Since 2011 we have had access to a content moderation tool in Drupal 7 in the form of Workbench Moderation. This module introduced the concept of Draft ➡ Review ➡ Published workflows, with different user roles having specific permissions to move from one state to the next.
Unfortunately, the underlying Drupal core revision API was not designed to deal with this, and there were some pretty crazy workarounds.
Content moderation has long been a key feature request for Drupal, and so effort was made to port Workbench Moderation across to Drupal 8.
Content Moderation drove a lot of cleanup in Drupal core APIs, including proper support for forward revisions, and adding revision support to other content entities besides Content Types, such as Custom Blocks. More are on the way.
In Drupal 8.3, the Workflows module was split out of Content Moderation. Why you may ask? Well, because the Workflows module provides the state machine engine that Content Moderation relies on.What is a State Machine?
A state machine defines a set of states and rules on how you can transition between those states.A door state machine
In our simple example of a door, it can only be opened, closed or locked. However, you can't go directly from locked to open, you need to unlock it first.Content Moderation Workflow Configuration
Content Moderation provides a set of Workflow states and transitions by default.Content Moderation StatesContent Moderation Transitions
If we were to put this together in a state machine diagram, it would look like the following:Content Moderation State Machine
From the above diagram, it becomes clear what the allowed transitions are between states.
So now Workflows has been configured with our Content Moderation states and transitions, what is left for Content Moderation to do?What Does Content Moderation Do?
It turns out quite a lot. Remember, that Workflows only provides the state machine. It in no way prescribes how you should manage the current state of a particular entity.
Content Moderation provides:
- Default Workflows configuration
- A fairly complex WorkflowType plugin which works with the Revision API.
- Storage for individual states on content entities
- Configuration of which entity bundles (Content types, etc.) should have Content Moderation
- A number of admin forms for configuring the workflows and how they apply
We want to build a very simple issue tracker for our example. The state machine diagram is the following:Issue Tracker State Machine
That's the simple bits out of the way. Now, in order to build an issue tracker, we will need to replicate the rest what Content Moderation does!
Fortunately there is a module that can do most of the heavy lifting for us.Workflows Field
“This module provides a field which allows you to store states on any content entity and ensure the states change according to transitions defined by the core workflows module.”
Perfect! Let's download and install it.
Next we want to add a new Workflow. We can assign it a label of Issue Status and you'll see that we have a new Workflows Field option in the Workflow Type dropdown.Add new workflow
We can then configure the desire Workflows states and transitions.Issue StatesIssue Transitions
Thats the our Workflows configured. Now we need to create a new Issue content type to attach our workflow to. It's assumed you know how to create a content type already. If not, check out the User Guide.
Next, we need to add our Workflows Field to our Issue content type. Follow the usual steps to add a field, and in the drop down choose Workflows as the field type, and our previously created Issue Status workflow.Add workflows fieldTest it out!
Now we can test our our workflow by creating a new Issue from the Content page. If everything was configured correctly, we should see a new field on the edit form for Status.Issue status form
Given the transitions we defined in our workflow, we should only be allowed to see certain values in the drop-down, depending on the current state.Testing workflow constraintsWhat next?
That's it for setting up and configuring a custom workflow using Workflows Field. Some next steps would be:
- Add permissions for certain users (there's an issue for that #2904573 )
- Add email notifications
Let me know in the comments!Tagged Workflows, Content Moderation
Dated 29 November 2017Add new comment
If you ever have need of timed or delayed payments, we have some good news: recurring billing (also known as subscriptions) is new and improved in Commerce 2. Check out this week's High5 episode and learn more! What is recurring billing?
It's anything where we want to have a transaction happen after the initial time when a customer is on our site. That might be monthly or yearly, or it might be when you want the last half of the payment to go through in a couple days or a week.How does it work?
It's not like we store pictures of everyone's credit cards and just keep applying charges to them. Instead, we store tokens, or references to the credit cards. This is much safer because it means that even if the site got hacked, no one would have access to your actual banking information. At no point does Commerce ever store your actual credit card.
If you're interested in reading more about tokenization, Wikipedia has a lot of good information on the subject.How is this different from Commerce 1?
We sort of had tokenization (a.k.a card on file) in Commerce 1. It was a contrib module and wasn't actually part of Commerce itself. Some payment gateways supported it, some didn't, some did but only partially… it was much more of an ad hoc thing.
Now, tokenization is built into Commerce, so any major payment gateway that gets set up and has the capacity to store tokens (which is most of them), will do so. You don't need to do anything special for your payment gateway to handle recurring billings. As long as we have that token, we can keep making charges to it until that token becomes invalid (i.e. the card gets cancelled).
It was actually a credit to Commerce 1 that it had tokenization at all. It's a complex thing. For instance, if a payment doesn't go through, do we have to cancel the subscription? Do we have to get the product back? Do we do that immediately, or give them a window of time to put in the new card? A lot of ecommerce setups just avoided that entirely, so it was definitely a strength of Commerce 1, and now it's really a strength of Commerce 2.The bottom line
Recurring billing rocks, and is now built right into Commerce 2.
Advanced Access is an access control suite designed to provide an extensible access control system that leverages plugins to determine access pathways. The module extends the concepts of the node_access implementation in code to support additional entity types and to make the interface between access modules simple.
I have decided to remove paid promotions from the Webform module to focus on promoting the Drupal Community as a whole, the Drupal Association, and Webform module, I am also comfortable stating that I am not asking for forgiveness for my decision.
It is important that the Drupal community understand that I reached out to Lingotek and chose to promote their services within the Webform module's UX. Lingotek has made and continues to make amazing contributions to Drupal and the community. I want to thank them for allowing me to promote their services in such an experimental way.
Removing the paid promotion
I documented my original intentions in a blog post about promoting paid services within the Drupal community. I have come to fully agree with lslinnet's comment...
The Drupal community needs to explore ways to help support and fund core contributors and project maintainers. The goal of the paid promotion experiment was to see how everyone, including myself, felt about this concept.
MortenDK's (mortendk) very upset and direct tweet triggered the largest debate...
Yes, the promotions of third-party services within a module's UX could open some floodgates that could create a horrendous user experience and first impression of Drupal. First impressions are very...Read More