Drupal

Paragraphs View Mode Field

New Drupal Modules - 6 February 2019 - 7:33am
Categories: Drupal

TMGMT GearTranslations

New Drupal Modules - 6 February 2019 - 6:54am

Under Development.

Categories: Drupal

Mass.gov Digital Services: Introducing Drupal Test Traits

Planet Drupal - 6 February 2019 - 6:34am
Mass.gov dev team releases open source project

The Mass.gov development team is proud to release a new open source project, Drupal Test Traits (DTT). DTT enables you to run PHPUnit tests against your Drupal web site, without wiping your database after each test class. That is, you test with your usual content-filled database, not an empty one. We hope lots of Drupal sites will use DTT and contribute back their improvements. Thanks to PreviousNext and Phase2 for being early adopters.

Mass.gov is a large, content-centric site. Most of our tests click around and assert that content is laid out properly, the corresponding icons are showing, etc. In order to best verify this, we need the Mass.gov database; testing on an empty site won’t suffice. The traditional tool for testing a site using an existing database is Behat. So we used Behat for over a year and found it getting more and more awkward. Behat is great for facilitating conversations between business managers and developers. Those are useful conversations, but many organizations are like ours — we don’t write product specs in Gherkin. In fact, we don’t do anything in Gherkin beside Behat.

Meanwhile, the test framework inside Drupal core improved a lot in the last couple of years (mea culpa). Before Drupal Test Traits, this framework was impossible to use without wiping the site’s database after each test. DTT lets you keep your database and still test using the features of Drupal’s BrowserTestBase and friends. See DrupalTrait::setUp() for details (the bootstrap is inspired by Drush, a different open source project that I maintain).

Zakim Bridge at Night, North End Boston. Photo by David Fox.Using DTT in a Testhttps://medium.com/media/cbe46617878edbc55bbf67c573fbc46a/href
  • Our test cases extend ExistingSiteBase, a convenience class from DTT that imports all the test traits. We will eventually create our own base class and import the traits there.
  • Notice calls to $this->createNode(). This convenience method wraps Drupal’s method of the same name. DTT deletes each created node during tearDown().
  • Note how we call Vocabulary::load(). This is an important point — the full Drupal and Mink APIs are available during a test. The abstraction of Behat is happily removed. Writing test classes more resembles writing module code.
More Featureshttps://medium.com/media/7c921cc06be32c3b0944aef1d597e853/hrefMisc
  • See the DTT repo for details on how to install and run tests
  • Typically, one does not run tests against a live web site. Tests can fail and leave sites in a “dirty” state so it’s helpful to occasionally refresh to a pristine database.

If you have questions or comments about DTT, please comment below or submit issues/PRs in our repository.

More from Moshe: Our modern development environment at Mass.gov

Interested in a career in civic tech? Find job openings at Digital Services.
Follow us on Twitter | Collaborate with us on GitHub | Visit our site

Introducing Drupal Test Traits was originally published in MA Digital Services on Medium, where people are continuing the conversation by highlighting and responding to this story.

Categories: Drupal

Simply Signups

New Drupal Modules - 6 February 2019 - 5:58am

The Simply Signups module allows users to set up a simple event rsvp/signup system. Every event can have its own unique rsvp form. There is also templating available. You can set up a form template that can be loaded and adjusted on a per node/event basis.

Categories: Drupal

DrupalCon News: How to become a DrupalCon Mentor

Planet Drupal - 6 February 2019 - 4:35am

The backbone of every DrupalCon is the community of people who come together at the event, and in particular the involvement of community volunteers who collectively influence and shape the experiences of others in attendance. In short, Mentors!  

 

Categories: Drupal

OPTASY: How to Send Richly Formatted HTML Emails in Drupal 8: Deliver the Experiences that Your Customers Expect in 2019

Planet Drupal - 6 February 2019 - 4:07am
How to Send Richly Formatted HTML Emails in Drupal 8: Deliver the Experiences that Your Customers Expect in 2019 adriana.cacoveanu Wed, 02/06/2019 - 12:07

API first, responsive Bartik, headless and decoupled Drupal, Layout Builder, React admin UI... Drupal's evolved tremendously over these 18 years! Yet: the emails that we send out via its otherwise robust email sending system aren't different from those we used to send a... decade ago. And customers expect rich experiences outside your Drupal website or app. While website administrators expect to be enabled to easily manage, via the admin UI, their email content templates. So: how do you send HTML emails in Drupal 8?

Without relying on external services, of course...

And who could blame customers for expecting 2019-specific user experiences? Experiences that HTML-enabled emails deliver through their great features.

Categories: Drupal

Third & Grove: The 15 Things Your AEM Team Says Drupal Can't Do, But Can

Planet Drupal - 6 February 2019 - 4:00am
The 15 Things Your AEM Team Says Drupal Can't Do, But Can justin Wed, 02/06/2019 - 07:00
Categories: Drupal

ThinkShout: Fear and Loathing in Support Development

Planet Drupal - 6 February 2019 - 4:00am

Consider the following exchange:

Project Manager: “Hey Joe, next week we’d like you to add some new features to [client site].”

Me: “Sure thing! Where is it hosted?”

PM: “Ah, well… we’re not really sure. We’ve asked the client. The thing is, they haven’t been able to do any work on the site for the last couple of years, because someone built the site for them and then launched it without documentation, and with no support.”

Me: *Stunned Look*

PM: “Also, they don’t use any version control. So updates will have to be done via FTP.”

Me, reeling: “I… I don’t even think I have an FTP client on my computer.”

PM: “We believe in you.”

This is a worst-case support development scenario, one likely to bring with it uncertainty and fear. However, with a methodical approach, even the worst case can be turned to your advantage.

Getting started: Docs and detective work.

The very first thing to do when you have a new support project is to find the site documentation, or failing that, create a place for new docs. You are in the best position to document the site, because you don’t have any preconceived ideas about what to do - so document everything. Future engineers (and future you) will thank you.

Starting with the site and its hosting, you can reverse-engineer pretty much anything. You can even reverse-engineer the hosting if you need to, using Robtex! (Find the host, and ask the client to reach out to them for login info).

Once you have the hosting info, you can log in and establish the following: Are they running backups? Do they use a database, and is it backed up? Do they have any version control? Is there any sort of deployment process? Do they have a staging environment?

If the answer is ‘No’ to any of the above, then it’s usually pretty easy to add/enable. Once you have a ‘Yes’ for all of the above, update the documentation, password manager, etc. For example, even if they don’t use version control, there’s nothing stopping you from adding it to your local install, and pushing that code to a (now free!) private GitHub repo.

From there, you can add user accounts for yourself, and if it’s a CMS-based website such as WordPress or Drupal, log in and start investigating the code.

Figuring out the code - locally.

It’s always a good idea to do code investigations on a local installation - any tweaks and debug code can be spotted pre-deploy and removed. Make sure you document the process of getting a local installation up and running as well! Example: letting your co-workers know that they should run the WordPress-based wp-cli command wp search-replace client-site.com client-site.localhost on a newly imported database will save them hours of frustration, as well as preventing terrible accidents from happening (WordPress will quietly redirect you to the live site after logging in if you don’t change the site URLs in the local database. Oopsie!)

Once set up locally, you can start looking for theme-layer build tips. In the root of the project, look for Composer files, (which could indicate an automated build process). A README would also be a good thing to look for - these will often be the hidden documentation for a project.

You should also look for any taskrunner files, such as those used by Gulp or Grunt, or any other files that you wouldn’t expect to see in a clean install of the CMS.

Next, find the active theme. Usually, you can inspect the website and find paths to the theme from images (WordPress), or the favicon link in the header (Drupal).

Once you’ve located (and documented) the theme location, look in the theme for taskrunners, as well as any README files. If there’s are none to be found, look for a Sass or {less} directory. Gemfiles and Rakefiles will also give hints about the type front-end preprocessors in use, and what the scope of the preprocessor is. If it’s an older site, it might still use a Compass-based framework. If there’s no preprocessor, it might be using vanilla CSS!

Once all of that is done (and documented), you can actually start finding and working on code!

Where code?

Actually finding code can be tricky - say it’s a WordPress site, and you’ve been asked to add a menu to ‘campaign’ pages across the site. How to find the template quickly?

This is where a codebase searchable IDE is handy. Sites can have tens of thousands of files, and you want to be able to narrow your search. In the case of a WordPress template, you’d limit the search to the theme directory, preferably with a *.php file extension. From there, you can look at a campaign page and look for specific classes. In our case, hero-area campaign.

Result:

Don’t be a hero - use smart search

This site had over 100,000 files! A full search could have taken several minutes instead of the 1-2 seconds it took to search the 244 PHP files in the theme.

From here, you could simply get to work and add the menu, but it can be valuable to run a codesniffer against the template. The more it deviates from the coding standard for a particular CMS, the more likely your ‘correct’ code will run into issues. In addition, if the site is ever migrated to an automated deployment environment, it will fail builds that have coding standard filters.

You can also glean a lot about the mindset of the people who built the site - were they careful and clean in their coding style? Did they document/comment code? Did they make the same style errors over and over (like a lone developer would do) or is it random (like a team)?

You can also occasionally make fun discoveries:

Me: “OK, I installed the site locally and added the menu to the campaign template. I also noticed a coding error in the ‘related content’ section that was causing it to not display.”

PM: “Really? Do they have that on other content on the site?”

Me: “Yeah, every other content type has it. I suspect it was just an error that snuck in when someone was doing a search-and-replace on the code.”

PM: “So… how many pages did that impact?”

Me: “About 500 or so. It’s been that way for at least the last three years too.”

PM: *Stunned Look*

Categories: Drupal

Field Formatter Key Label

New Drupal Modules - 6 February 2019 - 3:38am
Categories: Drupal

VK Database Location Autocomplete

New Drupal Modules - 6 February 2019 - 3:19am
Categories: Drupal

Article test

New Drupal Modules - 6 February 2019 - 2:58am
Categories: Drupal

Appnovation Technologies: Simple Website Approach Using a Headless CMS: Part 1

Planet Drupal - 6 February 2019 - 12:00am
Simple Website Approach Using a Headless CMS: Part 1 I strongly believe that the path for innovation requires a mix of experimentation, sweat, and failure. Without experimenting with new solutions, new technologies, new tools, we are limiting our ability to improve, arresting our potential to be better, to be faster, and sadly ensuring that we stay rooted in systems, processes and...
Categories: Drupal

Brands

New Drupal Modules - 5 February 2019 - 11:06pm

Provides a taxonomy vocabulary that includes product brands.

Features:

This module simply provides a vocabulary named brands.

Categories: Drupal

coil

New Drupal Modules - 5 February 2019 - 8:49pm

This module will enable coil monetization for all site webpages.
After install, go to configuration, save you coil pointer and start using coil.

Categories: Drupal

No admin destination redirect

New Drupal Modules - 5 February 2019 - 7:21pm

Disables the annoying ?destination=/admin/foo/bar redirects for admins when administering a Drupal 8 site.

E.g. After editing & then saving a view, you will not be redirected back to the main views listing page.

This module only works if the current user is an administrator, and is only applied to admin pages.

This module has no configurable options (yet).

Categories: Drupal

Backup S3

New Drupal Modules - 5 February 2019 - 6:12pm

Backup and Migrate extension to support AWS S3 as a destination using AWS SDK for PHP - Version 3.

Categories: Drupal

Commerce Guys: Eliminating barriers to Drupal Commerce growth

Planet Drupal - 5 February 2019 - 5:52pm

At the end of 2018, Dries Buytaert, creator of Drupal, asked folks involved with the project to share their thoughts on what's "holding Drupal back." His prompt came on the heels of two great blog posts related to his company Acquia's growth strategy and lessons he's learned and applied from Amazon's growth strategy. I didn’t beat his third post on overcoming Drupal’s obstacles to the punch, but the series did prompt me to think long and hard about the barriers we face as maintainers and leaders of the Commerce project within the Drupal ecosystem.

For the entirety of our existence, Commerce Guys has focused on building and promoting Drupal as an eCommerce platform, first through Ubercart and then Drupal Commerce. While eCommerce is a huge industry, our reach within the community has only averaged around 5% of all Drupal sites. Given the diverse and varied types of users Drupal serves, I consider this relatively low number unsurprising. (A certain percentage will also choose to integrate third party shopping cart systems, but historically that’s always been a fraction of the number of Drupal sites using our native solutions.)

It’s tempting to be fatalistic about Drupal Commerce’s growth and accept that our growth rate will be pegged to Drupal’s own growth rate so long as our relative percentage holds. It actually is an important baseline to acknowledge - our success is tied to Drupal’s success, and so we prioritize contributing to initiatives that help improve Drupal’s core APIs, make it easier to maintain and upgrade, and attract new audiences through API-first / JavaScript initiatives. However, I think we can and should do better than just waiting for growth to happen upon us.

Why should I think we can do better?

After Dries’s posts last year I compared our usage statistics for Commerce 2.x (on Drupal 8) to our usage statistics for Commerce 1.x (on Drupal 7) at the same point in its life-cycle. What I saw convinced me we have plenty of room to grow:

  • In 2013, Drupal Commerce 1.x grew from 23,224 to 33,989 sites.
  • These numbers represent growing from 4.02% to 4.50% of all Drupal 7 sites.
  • Our average growth rate that year was 3.89% month over month; Drupal’s own growth rate was 2.72%.
  • In 2018, Drupal Commerce 2.x grew from 3,097 to 6,980 sites.
  • These numbers represent growing from 1.41% to 2.85% of all Drupal 8 sites.
  • Our average growth rate last year was 8.65% month over month; Drupal’s own growth rate was 1.23%.

Just based on those numbers, even though Commerce 2.x grew over twice as fast last year as Commerce 1.x did in a similar timeframe in its life-cycle, we still represent only half of the relative number of Drupal sites we did back then. We can double our user base on Drupal 8 without challenging our historical average representation at all. That’s good news!

Our growth rate right now is fantastic, especially compared to Drupal's own. There are likely a variety of factors at play here, but I think it boils down to some combination of recognized maturity, excellent word of mouth from a steady stream of case studies, and our contributed module ecosystem stabilizing to a point that Drupal 7 / Commerce 1.x sites are finally porting to Drupal 8 / Commerce 2.x. As our 2.x project lead recently observed, we’re now up to over 250 contributed modules on drupal.org and maintain a community support Slack channel with over 1,000 participants.

Eliminating barriers to growth in 2019

In order for us to keep up and even accelerate our rate of growth, Commerce Guys has been working hard to identify our barriers to growth and develop solutions to them. As a small team playing in a large market (against very well-funded competitors), we can only do so much … but every bit of progress on any of the following fronts will help.

1. Features and integrations

The biggest barrier to growth has historically been our under-developed contributed module and integration ecosystem. Ecosystem development is incredibly important - agencies don’t often have the expertise or confidence to develop new features or integrations themselves. Our major competitors (Magento, Shopify, et al) all have massive ecosystems that third-party software vendors take the initiative to join while our own ecosystem remains dependent on our own team or the core of our development community to expand.

2. Developer support and education

It’s tempting to point to performance and scalability as another barrier to growth, but we see poorly performing Drupal Commerce sites as a symptom of another issue - lack of exposure by the average Drupal developer to best practices for scaling sites with a large amount of authenticated (or otherwise cache-breaking) traffic. We know that we can scale Drupal Commerce to support 10,000+ transactions per hour and thousands of concurrent users, but we also know that otherwise capable Drupal teams struggle at a fraction of that scale. In other words, it’s not a capabilities gap, it’s a knowledge gap, and we’re to blame for not sharing what we've learned with our userbase.

3. Reaching our core audience

Finally, we’re hardly communicating to the market at all about why they should be choosing Drupal Commerce. Our websites are aging, and organizations who do decide upon Drupal are often confused about what sort of support, if any, we might offer them if they choose to adopt our software. We understand how our solution differs from other major players in the market and where it should be seriously evaluated (e.g. cross-border commerce, digital product sales, subscription billing), but we aren’t doing enough to demonstrate our capabilities or provide a vision for why merchants will be better off using Drupal Commerce than a competing application.

We certainly have our work cut out for us in 2019, but we’re encouraged by last year’s growth and the support of our friends and champions within the Drupal community. We believe we can work to eliminate these barriers to growth while building a sustainable business that allows us to grow without compromising our values. In reverse order, the basic roadmap we’re targeting to address those known-blockers above will be:

  1. Relaunch our company and project websites to more clearly communicate who we are, what our software can do, and how we support eCommerce teams to build with confidence on Drupal.
  2. Standardize our consulting efforts and support retainers into concrete, documented offerings that anyone can understand.
  3. Coordinate our development roadmap with more agency and technology partners to ensure essential contributed modules receive the attention they deserve and our integration roster continues to grow.

We'll be encoding our expertise into productized solutions that allow us to grow a team focused on ensuring eCommerce sites built with Drupal are optimized for stability, security, and scalability. We've always valued the impact we have on the Drupal community even as a small team, and we believe addressing these issues will afford us the opportunity to grow, broaden our impact, and grow Drupal itself as a result.

Categories: Drupal

DrupalEasy: 11 Tips to start your Drupal 8 project right

Planet Drupal - 5 February 2019 - 1:55pm

As someone who has been building Drupal sites for over 12 years now, I'd like to think that my knowledge and expertise has grown at a rate similar to the power, flexibility, and complexity of the Drupal project itself. For well over 10 years, Drupal training and development has been the focus of my consulting business; over the holidays I took some time to look back and really think about the lessons I've learned and how I can utilize them moving forward. 

In addition to documenting the process for myself as well as my current and future clients, I also wanted to share what I've learned with the Drupal community. After all, it is this community that has made it possible for me to have the success that I have found so far. I have worked on projects of all sizes from large Fortune 500 companies to small local businesses. I’ve been alone on project as well as with large teams of developers. There have also been projects with massive budgets as well as projects with no budget. The breadth of this experience has really contributed to my ability to provide more value for my clients. 

One word I use often when speaking with current as well as prospective clients is "sustainability". I always want to be involved in a solution that provides good value not only now, but for the lifetime of the project. I want to build sites that are easy to maintain, easy to update, and easy for different developers to cycle in-and-out of. With sustainability, and all of the elements that contribute to it in mind, I present the 11 tips to start a Drupal project right. 

1. Commit to a Local->Dev-Stage->Prod developer workflow

Having a professional developer workflow should go without saying, but I often come on-board small, single-developer projects that have a remote development environment and a live environment - and nothing else. At the very least, projects of all sizes should have not only a dev and live environment, but developers should have local environments as well. 

There's a lot of focus on DevOps in the Drupal ecosystem (with good reason), but before you jump into a continuous integration/continuous development (CI/CD) system, be sure you have the basics first and then add complexity only as necessary. I've seen way too many projects invest in a full-on CI/CD system only to have it ignored because developers didn't have the time and/or expertise to utilize it properly.

2. Commit to the entire team using a project tracker

This is a bit of a pet-peeve of mine. I'm a firm believe that commitment to a project tracker must include 100% of the development team and stakeholders. Note the "and stakeholders" - this includes project managers, content and QA folks, and anyone else who has a role in the project. How often is a project ready to launch and then at the last minute a stakeholder chimes in requesting changes? This is demoralizing and frustrating for the entire development team.

Project tracker tasks should be focused. Large tasks like "theme the site" aren't very helpful and comment threads in tasks like this often become unwieldy, defeating the purpose of using a project tracker. Train the entire team on using the project tracker and committing to using it for the majority of project task communication. 

3. Utilize a remote Git repository

You're not using Git yet? Seriously? Stop reading this and go get yourself and your team trained up (we offer training). Also - commit early and often. Smaller, more focused commits (like project tasks) are easier to manage.

4. Use Composer to manage the code base

This is an article about Drupal 8, so this isn't really optional. While there is work in the community on various Composer-related projects, for now the Composer template for Drupal projects is the de-facto standard for managing your Drupal 8 project's codebase. Don't know how to use Composer? Learn it (we also offer Composer training).

5. Use consistent local development environments for development team

Avoid "it works on my machine" conversations for the rest of your life by ensuring that the entire development team is using identical local environment configurations. Docker-based solutions are tailor-made for this type of thing, but it has been possible for awhile with virtual machine-based solutions as well. A solid local development environment will pay dividends - making it easy to get new developers up-and-running, and allowing developers to focus on building the project, not monkeying around with their local environment.

I've been a fan of DDEV-Local, a Docker-based solution, for awhile - I provide training and I also wrote a book about it! 

6. Define information architecture with all stakeholders

This is where I see projects go sideways more often than not. When defining the information architecture (IA) for the site, all stakeholders must be involved. This tip really goes hand-in-hand with the next one, but the bottom line is that this needs to be a discussion. There's nothing worse than getting near the end of a project and showing it to a content author and finding out that there are gaps. Generally, the goal is to get the granularity right when defining IA. This is next to impossible to do without feedback early in the process from all stakeholders.

Review any existing content that is to be migrated to the new system, ask content authors what the issues with their current system are, and be careful not to over-engineer a solution that won't provide enough bang-for-the-buck. 

7. Prototype information architecture with content authors

This tip goes hand-in-hand with the previous one - an important part of defining the IA is testing and confirming that everything is accounted for. In my experience, the absolute best way to do this is by prototyping the system. Allow your actual content authors, editors, and admins to test-drive the new architecture by adding and editing content on a prototype of the site. This needs to be done very early in the development process, so the focus should be 100% on the add/edit forms - not the output. In fact, I recommend not putting any effort into theming the output at this point, making it crystal clear that the prototyping exercise is to confirm that the set of entities, bundles, and fields designs are on-target.

I really cannot stress enough how important this step is. IA mistakes made early that are not corrected will be a burden until they are corrected (if ever). It's normally relatively easy (and inexpensive) to fix IA mistakes early - quite the opposite if they are left to fester and other parts of the site are built upon them. I have never been part of a project where the IA prototyping didn't result in important updates to the IA. 

8. Create a style guide

If you're building a custom theme, then you probably need a style guide. Part of a solid UX/UI design is consistency in design. Consistency brings user comfort. When users are more comfortable on your site, they'll spend more time there. 

Style guides can be as simple or as complex as they need to be. At the absolute minimum, I would recommend that a style guide contain basic typography and a color palette. You'll need to consider how/if typography will change based on responsive mode (are H1s the same pixel size on mobile as they are on a desktop display?) Similarly, you'll want to think about how the header/navigation/footer respond to various screen widths as well. Have an element that appears throughout your site? Then define rules how it looks in various places and various screen widths. 

9. Create wireframes and mockups as necessary

Similarly, if your project is going to have a custom theme, then you're going to need to design the layout of key pages. How are landing pages arranged? How do they respond at various screen widths? Think about the entire site and design wireframes for a representative sample of pages. Only 2 or 3 wireframes are necessary for many projects (home page, content page, interior landing page). 

Consider these representative pages as a group, not individually. Look for common elements (easier to theme) and value consistency. If every page is a one-off, then implementation costs will rise. 

Start with wireframes and generate only the mockups you need. Often, between a solid style guide and some good wireframes, mockups aren't necessary in many cases. Think of the style guide as a box of LEGO bricks that can be assembled into mockups in various configurations. If time and budget is limited, favor the style guide over mockups.

10. Use the Configuration System

Drupal 8's configuration system provides a powerful tool to easily push non-code configuration changes between environments. The "trick" to using it is that the entire team has to understand and participate in the process. If the development team is five people, and only two are using the configuration system, you're going to have rough sledding. 

The configuration system will help enforce a solid developer workflow, encouraging team members to update and test configuration (like a new View) locally before pushing it to remote development environments. A byproduct of using the configuration system is that config changes can easily tracked by the project tracker via commit messages. 

11. Define realistic and meaningful milestones

There's not much that kills developer morale and confidence in a project more than lack of project leadership. At the core of this is often a lack of project planning and milestones. All team members should be involved in the setting of goals and milestones for the project. A single milestone of "the site must be done in 5 months" doesn't cut it. The entire team should work together to define realistic and meaningful milestones. Take into account non-project responsibilities of team members, identify and plan for potential pain points in the project. 

Project leaders need to listen to team members and provide training and professional guidance when necessary. Most developers are problem solvers who like to learn new things. Project leaders should embrace and leverage this for the betterment of their projects, the result will be a positive one for the entire team!

Mike Anello is the architect and instructor for DrupalEasy’s Drupal Career Online, which includes intensive live online sessions, rich learning resources, an active learning community and hands-on projects designed to provide those who need to get skilled up in Drupal with the best possible start. The next session of the DCO starts February 25th. If you’d like to learn more, you can sign up for a no-cost Taste of Drupal mini-webinar.

Categories: Drupal

Death Link

New Drupal Modules - 5 February 2019 - 12:57pm

This module provide a way to redirect death links to the canonical url of any entity. This way a common 404 page can be redirected to a valid new url. It stores the redirects as config entities.

GitHub

If you prefer to make pull/merge request, when you have a nice addition, instead of creating a patch, you can do that on GitHub.

Categories: Drupal

Pages

Subscribe to As If Productions aggregator - Drupal