سیاره دروپال

Drupal.org - aggregated feeds in category Planet Drupal
Subscribe to خوراک سیاره دروپال
Examples for Developer #9 Week of Coding Abhishek Lal B Wed, 08/02/2017 - 20:39

Drupal 8 is quite an improvement over previous versions of Drupal with regard to the reproducibility of a site from a minimal source repository.

The recommended way to set up a new Drupal 8 site is to use composer, and the most convenient way to do that is via drupal-composer/drupal-project, which brings in Drush and drupal-console as per-site dependencies; from there the site can be installed and managed.

However the fact that Drush and drupal-console are per-site dependencies poses a problem: they are not available until the site dependencies have been downloaded, this means that it's not really possible to add “bootstrapping” commands to them to make it easier to set up new projects. This is what motivated me to put together drupal-init-tools: a minimalistic set of wrapper scripts which can be used when Drush and drupal-console are not available yet, or when they have to be combined together to perform a task in a better way.

drupal-init-tools has been developed mainly to speed up prototyping, and it is particularly useful to set up sites under ~/public_html when the web server is using something like the Apache userdir module; however I feel it could be useful in production too after some cleanups.

drupal-init-tools standardizes the setup and installation of new Drupal projects: for example the drin new command makes sure that the original drupal-composer/drupal-project repository is still accessible from an upstream git remote so that the developer can easily track changes in drupal-composer/drupal-project and keep up if appropriate for their particular project.

Some drin commands also provide a nicer interface for frequent and important tasks, like the actual site-install step, or the creation of an installation profile that could replicate the installed site.

Here are some examples of use taken from the drin manual.

Create and install a new Drupal project:

cd ~/public_html drin new drupal_test_site cd drupal_test_site $EDITOR bootstrap.conf drin bootstrap --devel

Create an installation profile from the currently installed project:

drin create-profile "Test Profile" test_profile

Clean and rebuild the whole project to verify that installing from scratch works:

drin clean drin bootstrap

A quick way to test drupal-init-tools is this:

git clone git://git.ao2.it/drupal-init-tools.git cd drupal-init-tools/ make local ./drin --help

Give it a go and let me know what you think.

If it proves useful to others I could have it packaged and uploaded to Debian to make it more “official”, IMHO it makes sense to have such a small meta-tool like drin as a system global command.

Since we released the thunderdemo.com earlier this year a lot of interesting things happened in the Thunder ecosystem. We thought that it is a good time to provide an update.

Have you been waiting for this update? Yes it's that time, I can finally show you the Drupal 8 products we've been working on! In the last 4 months we were 100% focused on upgrading all products to Drupal 8. I tagged today's updates as alpha releasea but the products have come a long way and are practically on par with their matured Drupal 7 counterparts.

Considering the size and scope of this enormous update, we are excited to get people involved in testing the products and to begin testing as soon as possible. To facilitate this I put a link and feedback thread in the support forum, it's only visible to registered users: Glazed Drupal 8 Alpha1 Download & Feedback thread.

For people who are not yet subscribers of our Drupal themes shop, now is the time to get in and get early access to our awesome Drupal 8 product line. Join here to start downloading Drupal 8 themes!

Sneak Preview Oops, YouTube iFrame won't load here. Read this blog here to view the video.

Drupal 8 Related Questions

Will Drupal 8 products cost existing subscribers more money? (No)

At SooperThemes all our subscriptions, including the entry level subscription give you access to all themes and modules. No exception. Drupal 8 products are immediately available to all subscribers regardless of subscription level or sign-up date.

When can we expect a stable release of all products?

We will integrate drupal 8.4 Media fields across all our products so that we don't miss out on critical media-reusability features. This means we are bound by the Drupal 8.4 release schedule with our Drupal 8 products and installation profile. Drupal 8.4 is supposed to have a beta release on September 14th, a release candidate on September 20th and a stable release on October 4th. We will try to provide backwards-compatible beta releases as soon as Drupal 8.4 has a beta release. Before then we recommend you only use our Drupal 8 products for testing, unless you are prepared to migrate or manually fix file fields on your content.

What can we test today?

The alpha release contains the full Main Demo with all features and demo content. It includes upgraded versions of Glazed Builder, Glazed Theme, Glazed GridStack and contrib modules. The Glazed Portfolio module built on top of the MD Portfolio module has been phased out. We built an all-new SooperThemes Portfolio module from the ground up. This module has surpassed feature parity with the Glazed Portfolio module and now provides even more features and design options.

Drupal and GraphQL with React and Apollo

Building an app that displays a list of articles in Drupal in the traditional way is a straightforward task - meaning that we use Drupal for everything: backend configuration and data storage as well as frontend (usually twig in Drupal 8).

However, doing the same thing in a decoupled configuration, where we use for example Drupal for backend and data storage, and React as frontend, is not that easy.

To help you with this, this blog post aims to show how you can successfully build that.

Vasi Chindris Wed, 08/02/2017 - 11:03

There are 3 things you'll need to build this: Drupal, React and something that can bind those two together, meaning that it can fetch the data from Drupal and make it available in React. For this third thing, we will use GraphQL and Apollo.

Drupal Setup

As mentioned, the first thing you'll need to do is to install Drupal. Nothing special to mention here, just do a plain Drupal 8 installation. Additionally, you should also download the GraphQL module or clone it from https://github.com/fubhy/graphql-drupal. For now, we will just install the GraphQL Content and the GraphQL Views modules (they will automatically install the GraphQL and GraphQL Core dependencies).

We want to list some articles, so just go ahead and create a few (or use the Devel generate module if you want). Be sure to also create a simple view that lists articles (don't worry about displays right now, just list the title of them).

So now you have the Article content type (which was already there) and the Articles view which you just created, and you want to expose them via GraphQL. For this, you need a schema. You don't have to write it yourself, you just have to expose your configuration.

To expose content, just go to /admin/config/graphql/content and there you should see a list with all your entity types and bundles that you can expose. We want to expose the Article content type, so just click on Content and then Article.

Then you have the possibility to choose which fields to expose. And you do that by selecting a View mode. So before actually exposing the Article bundle, we need to configure a view mode. I recommend creating a new one, let's call it graphql, so that you can easily see it is used to expose data to GraphQL.

Go to admin/structure/display-modes/view and create the new view mode. Now you can go back to admin/config/graphql/content, click again on Content and Article and you should be able to select GraphQL from the view modes list. Don't forget to click on the Save configuration button.

Next you can go to the Manage display tab of the Article content type (/admin/structure/types/manage/article/display), and configure the GraphQL display.

Let's say we want to expose the body field(the title is automatically exposed).


 

The second thing we want to expose is the Articles view. To do that, just go to edit your view and add a GraphQL display. Let's change the machine name to graphql_articles. Rebuild the cache and that's it. You just exposed your view to the GrapqQL schema.

Now, how can you be sure that what you did has really changed the schema. There is a very easy way to check this. There is a tool called GraphiQL which you can use to run GraphQL queries and also check the schema. For this, just install the GraphQL Explorer module, and then navigate to /graphql/explorer on your site. On the top right you should have a link called Docs which will expand the Documentation Explorer on click.

In the search box, just input Article and you should see two entries: NodeArticle (this is the article content type you exposed) and articlesGraphqlArticlesView which is your view. If you see those, then you properly configured the schema.


As mentioned, with GraphiQL you can run GraphQL queries. It's time to see if we get any data.

So for the article view, just use this query:

{   articlesGraphqlArticlesView {     ...on NodeArticle {       entityId       title       body     }   } }

Put this in the left panel, click the run button and you should see the results in the right panel. The above query can be translated like this: give me the results from the articlesGraphqlArticlesView view, and when the type of the object is NodeArticle, give me the title, the body and the entityId fields.

With the query above we just tested both things we exposed: the Articles view and NodeArticle content type.


React

The second thing to do is to prepare your frontend. In this example, we'll use React. Probably the easiest is to use create-react-app. So just go ahead and create a new app and make sure you can start it and have the home screen displaying properly.

Let's build now an ArticlesView component which can display a list of ArticleTeaser components.

Here is the ArticlesView component:

import React from 'react'; import ArticleTeaser from '../ArticleTeaser'; const ArticlesView = ({articles}) => (   <ul>     {articles.map(article => <li key={article.id}><ArticleTeaser article={article} /></li>)}   </ul> ); export default ArticlesView;


And here is the ArticleTeaser component:
 

import React from 'react'; const ArticleTeaser = ({ article }) => (   <div>     <h3>{article.title}</h3>     <div>{article.body}</div>   </div> ); export default ArticleTeaser;

 

Finally, the App.js can look something like this for now (with a dummy list of articles):

import React, { Component } from 'react'; import ArticlesView from './ArticlesView'; const articles = [   {     id: 1,     title: 'First article',     body: 'This is the first article',   },   {     id: 2,     title: 'Second article',     body: 'This is the second article',   } ] const App = () => (   <div className="App">     <ArticlesView articles={articles} />   </div> ); export default App;

If you run this you should see a list of two articles with their title and body. This is pretty much the pure frontend you have to do. The rest is just supplying the real data to the frontend. This needs some additional packages to be installed. So here we go!
 

GraphQL and React Apollo

To connect to our GraphQL server from React, we will use the React Apollo library. To install it just run:

yarn add react-apollo

The first thing we will do is to update our ArticlesView component. We want to get the list of the articles injected into the component. So we will use the graphql Higher Order Component provided by the react-apollo library and run a basic query to get the results. 

Here is the updated code for the ArticlesView component:

import React from 'react'; import { gql, graphql } from 'react-apollo'; import ArticleTeaser from '../ArticleTeaser'; const query = gql`   query articlesQuery {      articlesGraphqlArticlesView {       ...on NodeArticle {         id:entityId         title body       }     }   } `; const withQuery = graphql(query, {   props: ({ data: { loading, articlesGraphqlArticlesView } }) => ({     loading,     articles: articlesGraphqlArticlesView   }), }); const ArticlesView = ({ loading, articles }) => {   if (loading) {     return null;   }   return (     <ul>       {articles.map(article => <li key={article.id}><ArticleTeaser article={article} /></li>)}     </ul>   ) }; export default withQuery(ArticlesView);

The first thing to do is to build the GraphQL query that we'll use to fetch our data. We can do this using the gql function. Then we wrap our initial ArticlesView component with the Higher Order Component returned by grapqhl. The GraphQL HOC will get our query as a parameter, as well as a config object where we can specify among other things the props that our ArticlesView component will get.

In our case, the ArticlesView component will receive a loading flag which can be used to check if the data is still loading from the server and the articles which are basically the articlesGraphqlArticlesView result from the GraphQL request.

We also need to update a bit the App component, because we need to wrap everything into an ApolloProvider component.

Here is the code:

import React, { Component } from 'react'; import ArticlesView from './ArticlesView'; import { ApolloClient, createNetworkInterface } from 'apollo-client'; import { ApolloProvider } from 'react-apollo'; const client = new ApolloClient({   networkInterface: createNetworkInterface({     uri: 'http://url_to_drupal_site/graphql'   }), }); const App = () => ( <ApolloProvider client={client}>   <ArticlesView />   </ApolloProvider> ); export default App;

As you can see, the App component wraps the ArticlesView component inside ApolloProvider (which is initialized with an ApolloClient) and this means that any component bellow ApolloProvider can use the HOC returned by graphql to make requests to the GraphQL server using the ApolloClient which we instantiate in the client parameter.

This is a very important thing to keep in mind. If you move the ArticlesView component outside of the ApolloProvider, your app will not work anymore.

At this point, you can try to run your app, but you may receive a few js errors.

The first may be this one:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This means that your backend server does not allow sending content to a different domain than its own. So we'd need to enable the cors.config in your services.yml file (in sites/default). More about that here: https://www.drupal.org/node/2715637

Here's a possible configuration:

cors.config:     enabled: true     # Specify allowed headers, like 'x-allowed-header'.     allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with', 'access-control-allow-origin']     # Specify allowed request methods, specify ['*'] to allow all possible ones.     allowedMethods: ['*']     # Configure requests allowed from specific origins.     allowedOrigins: ['*']     # Sets the Access-Control-Expose-Headers header.     exposedHeaders: false     # Sets the Access-Control-Max-Age header.     maxAge: false     # Sets the Access-Control-Allow-Credentials header.     supportsCredentials: false

Rebuild the drupal cache and this error should dissapear.

A second error you could get is a 403 for the request to /graphql. The problem is that the anonymous user does not have access to run GraphQL queries. Just go to the administer permissions page and give the Execute arbitrary GraphQL requests permission to the anonymous role. Reload the page and you should see a list of articles (which of course you have to create first in Drupal).

This is the most simple listing app that you can do with Drupal, GraphQL, React and Apollo. However, there are many other features you may need. In the next section, we'll discuss pagination and filtering (including contextual arguments).

Filtering

For this example, we need to add a new field on our Article content type. Let's say we add a Year field on our articles, which is of type List (integer) and can have for now 3 possible values: 2017, 2016 and 2015.

It may look something like this:

Then add the Year field as an exposed filter.

And you can also expose the year field in the GraphQL display mode of the Article content type so that you can also fetch it for displaying in the frontend.

And now all you have to do in the frontend is to adjust the query and use the filter, like this:

const query = gql`   query articlesQuery {      articlesGraphqlArticlesView(filter: {field_year_value: "2015"}) {       ...on NodeArticle {         id:entityId         title         body       }     }   } `;

One important thing to keep in mind for now: if you have a filter on a view, you must provide a value for it in the query, otherwise the empty string will be used and most probably you will not get any results. And in this case, if you just want to print all the articles, use 'All' for the field_year_value filter.

Now, of course, having that year value hardcoded in the query is good enough for a demo, but in real apps you will probably want to have that variable. For this, we have to update our query to contain variables and our config object which is used by the graphql HOC to inject that variable into our query.

First, let's see the new query:

const query = gql`   query articlesQuery($year: String!) {      articlesGraphqlArticlesView(filter: {field_year_value: $year}) {       ...on NodeArticle {         id:entityId         title         body         fieldYear       }     }   } `;

And second, let's see the new GraphQL call:

const withQuery = graphql(query, {   options: () => ({     variables: {       year: 2016,     },   }),   props: ({ data: { loading, articlesGraphqlArticlesView } }) => ({     loading,     articles: articlesGraphqlArticlesView   }), });

What we did so far was to just move the hard-coded value from the query into the config object. It's a step forward, but it is still kind of hard-coded. Ideally, we'd have the year specified as a prop on the ArticlesView component.

And in fact we can do that, because the options function can get the component props as a parameter, like this:

options: (props) => ({   variables: {     year: props.year,   }, })


Which means you will use the ArticlesView component in App.js like this:

<ArticlesView year={2016} />


If you try now the app and replace the year with different values you should get different results.

Contextual filters are pretty much the same as filters. So, for example, if we want to add the author of the articles as a contextual filter to the view, to query that in fronted just add the contextual_filterI argument to the articlesGraphqlArticlesView field, like this:

articlesGraphqlArticlesView(filter: {field_year_value: $year}, contextual_filter: {uid:"2"}) {   ... }

And just like for the year filter, you can use a variable for the uid filter.


Pagination

To use pagination, first, you have to update the view itself. It is not important how many items per page you set, it is just important that the view has a page. The number of items per page will be specified in the query.

If you do that the articlesGraphqlArticlesView field will get two additional arguments: page and pageSize.

You will have something like this:

articlesGraphqlArticlesView(page: 0, pageSize: 2, filter: {field_year_value: $year}, contextual_filter: {uid:"2"}) {   ... }

And if you run now your app you will actually see that there are no results returned. The reason is that the articlesGraphqlArticlesView will now return a different structure. It will be an object with two attributes: count that represents the total number of results and results which are the results of the current page.

The new query therefore is (for simplicity, the filters and contextual filters are removed):

const query = gql`   query articlesQuery {      articlesGraphqlArticlesView(page: 0, pageSize: 2) {       count       results {         ...on NodeArticle {           id:entityId           title           body           fieldYear         }       }     }   } `;

Of course, now we have to update the props of the graphql config object.

props: ({ data: { loading, articlesGraphqlArticlesView } }) => ({   loading,   articles: articlesGraphqlArticlesView && articlesGraphqlArticlesView.results, }),

If you reload the page, you should see now 2 articles. The last thing to do is to have a link or a button that when clicked it will load more entries.

Here is the LoadMore component:

import React from 'react'; const LoadMore = ({ loadMoreHandler }) => (   <a onClick={(e) => loadMoreHandler(); e.preventDefault()} href="https://www.amazeelabs.com/en">Load more</a> ); export default LoadMore;

And add the LoadMore component in the ArticlesView component:

<div>   <ul>     {articles.map(article => <li key={article.id}><ArticleTeaser article={article} /></li>)}   </ul>   <LoadMore /> </div>

 

Now we have to supply a loadMoreHandler to the LoadMore component. Luckily, when using the config object of the grapqhl we have access to a function called fetchMore() which we can use to rerun the query and fetch more (or other) results. Using that function, we will add a new prop which will be injected into our ArticlesView component, which will be the loadMoreHandler.

Here is the updated query (which now contains the page and pageSize as variables) and the updated graphql call:

const query = gql`   query articlesQuery($page: Int!, $pageSize: Int!, $year: String!) {      articlesGraphqlArticlesView(page: $page, pageSize: $pageSize, filter: {field_year_value: $year}) {       count       results {         ...on NodeArticle {           id:entityId           title           body           fieldYear         }       }     }   } `; const withQuery = graphql(query, {   options: (props) => ({     variables: {       year: props.year,       page: 0,       pageSize: 2,     },   }),   props: ({ data: { loading, articlesGraphqlArticlesView, fetchMore } }) => ({     loading,     articles: articlesGraphqlArticlesView && articlesGraphqlArticlesView.results,     total: articlesGraphqlArticlesView && articlesGraphqlArticlesView.count,     loadMoreEntries() {       return fetchMore({         variables: {           // The page number will start with 0, so the next page is basically           // the number of current results divided by the page size.           page:             articlesGraphqlArticlesView.results &&             Math.ceil(               articlesGraphqlArticlesView.results.length / 2,             ),         },         updateQuery: (previousResult, { fetchMoreResult }) => {           // If there are no new results, then just return the previous result.           if (!fetchMoreResult.articlesGraphqlArticlesView.results) {             return previousResult;           }           return {             articlesGraphqlArticlesView: {               ...previousResult.articlesGraphqlArticlesView,               count: fetchMoreResult.articlesGraphqlArticlesView.count,               results: [                 ...previousResult.articlesGraphqlArticlesView.results,                 ...fetchMoreResult.articlesGraphqlArticlesView.results,               ],             },           };         },       });     },   }), });

So fetchMore will rerun the query. The config object it gets as a parameter has two main properties: the variables which will be used to merge new variables into the existing ones (in our case we just want to get the next page) and updateQuery, which is actually a function that can access the previous result as well as the new result and has to return the new articlesGraphqlArticlesView field.  

As seen above, we use that to merge the new results into the existing ones. And it's now time to use the new props that we inject into our ArticlesView component.

Here is the updated component:

const ArticlesView = ({ loading, articles, total, loadMoreEntries }) => {   if (loading) {     return null;   }   return (     <div>       <ul>         {articles.map(article => <li key={article.id}><ArticleTeaser article={article} /></li>)}       </ul>       { total > articles.length ? <LoadMore loadMoreHandler={loadMoreEntries}/> : null}     </div>   ) }; export default withQuery(ArticlesView);

And that's all I wrote, folks! You now have a view built in Drupal that you expose in GraphQL and use Apollo and React to display it in frontend, with pagination and filters.

Introducing Vardot's New Drupal 8 Website Mohammed J. Razem Wed, 08/02/2017 - 08:44

The cobbler's children always go barefoot! Is a saying we no longer want to be associated with. As a Drupal-specialized development house, it's no longer an excuse to keep a Drupal 7 website.

You're currently reading this post from our new Drupal 8 website, built using the ultimate Bootstrap distribution available for Drupal 8; Varbase (see project page on drupal.org). We've built Varbase with the basic concept of DRY (Don’t Repeat Yourself), so that we relieve ourselves from repeating all the modules, features, configurations, best-practices that are included in every Drupal website we built.

Did you know that Varbase is available for free to install and build websites on it yourself? You can test-drive it now on Simplytest.me. Or contact us to build one for you.

 

New Website Sections

Our new website features our Products in a new section where you can learn more about each product we build.

We also highlight how we deliver business solutions for various industries and verticals, including Higher-ed and SchoolsCorporates and Enterprises, Non-profits and NGOs, and News, Media and Entertainment.

 

Paragraphs to Build Nice Pages

The new website (and Varbase) uses the famous Paragraphs module, and suite of other modules that we have specifically built for Varbase, such as Varbase Bootstrap Paragraphs.

You can now leverage this functionality with an intuitive page building experience when you use Varbase.

 

It's worth noting that it took us 2 weeks to build the new website! Amazing, right? Let us know what you think.

And contact us to discuss your next project.

Who cares about shopping offline if one can do it online? Thanks to attractive ready-to-use commerce templates, the process of selling and buying things in the Interner is becoming more smooth and pleasant day by day. For this article we chose ten Drupal e-commerce themes which can be used for different kind of stores. 

Retail, fashion, food store - Drupal can do it all.

 

Read the full article and choose your theme.

 

When migrating from Drupal 7 to Drupal 8, it is important to remember to migrate over the redirects as well.

Read more...

Just a quick post to share a simple way to assert some markup is ordered correctly using BrowserTestBase

Week 9: Finishing Base Social Auth Implementer And Work on Social Post Implementer himanshu-dixit Tue, 08/01/2017 - 23:40

Ever wonder how websites go from initial design to code? What steps and tools are involved? What are the common pitfalls and how can you avoid them? In this blog post, I will recap the process our designers and front-end developers take to when creating a new website design for our clients. Hopefully, this will give you a little more insight into Mediacurrent’s methodology and in turn help you develop a more robust workflow of your own.
 

Build the Foundation

Before design even begins, there are a few key items to set the project up for success:

The Webform module in Drupal 8 makes it easy to create complex forms in no time. The basics are easy to learn but when you start digging below the surface, the huge power of the Webform module starts to reveal itself. While the Contact module in Drupal 8 core does allow you to create simple personal and site-wide contact forms, functionality is limited. This is where Webform module steps in. In the first part of this tutorial, we’ll use some Webform elements to create a simple but fully functioning form. We’ll show what you can do with the results of submissions and then add some additional elements. We’ll also demonstrate how one of the built-in JavaScript libraries can improve the look of form elements. In part two, we’ll add additional pages to our Webform, apply conditional logic, show how to create great layouts and much more!

The smart drop and the clever whale — there is no doubt that Drupal and Docker are highly compatible! It seems like their element is water, however, their true “element” is efficiency. Flexibility, security, and open-source standards are also worth mentioning. So after sharing a collection of useful links for working with Docker, we would like to take a closer look at this great “couple” and see why it’s worth using Docker to boost your Drupal development.

Read more

By now it’s no secret that the recommended approach for building websites is using components.  Component-driven development is breaking entire web pages into smaller pieces and working with those pieces individually.  As Stephen Hay puts it in his talk on Responsive Design Workflow, “We’re not designing pages, we’re designing systems of components."

Setting the Stage: Hosting a Decoupled Drupal site Setting the Stage: Hosting a Decoupled Drupal site root Tue, 08/01/2017 - 09:28

We’ve launched many websites with Acquia, but a recent project for the ski industry is especially notable and worth spending some time with. Over the next month, through a series of posts, we will take a deep dive into decoupled Drupal. With our hosting partner, we will outline how Elevated Third, Hoorooh Digital, and Acquia worked together to create a decoupled site for the Powdr Resorts, one of the largest ski operators in North America.

 

Corey Wood, Technical Account Manager at Acquia, starts us off with...

Part 1: Setting the Stage: Hosting a Decoupled Drupal site.

Powdr Ski Resorts was facing a familiar challenge: the websites in their network of ski resorts were on a collection of disparate content management systems, which made it difficult to govern their digital properties across multiple brands and sites. Powdr needed a digital solution that provides each brand in the Powdr family the flexibility required to deliver customized web experience for their users.

Powdr turned to Elevated Third, Hoorooh Digital, and Acquia to build and design the first in the next generation of sites, a Decoupled Drupal 8 site for Boreal Mountain Resort. Elevated Third spearheaded the decoupled Drupal development; Hoorooh Digital supported the website’s frontend design; Acquia provided the cloud hosting, the technical account manager, and 24/7 global support.

This series will detail how the three teams worked together to bring the project to the finish line.

But first, a refresher.

What is Decoupled Drupal?

A decoupled CMS allows developers to utilize any technology to render the front-end experience (“the glass” where a user interacts with an application) in lieu of the theming and presentation layers that come with a coupled CMS out-of-the-box. In a decoupled Drupal architecture, the Drupal back end exposes content to other front-end systems, such as native mobile applications, conversational UIs, or applications built in JavaScript frameworks.

JavaScript frameworks are increasing in popularity due to the demand for more flexibility in the front end, in addition to the promise of increased productivity and maintainable code. Many JavaScript frameworks exist, but some of the most popular include Ember, React, and Angular.

Drupal can function as a services layer to allow content created in the Drupal CMS to be presented through a JavaScript framework. Drupal’s robust collection of web services and flexible APIs means that any system can consume data from Drupal with ease.

 

Read the entire article, including Corey’s take on hosting a decoupled Drupal project, here.

TL;DR:
  • Structured data has become an important component of search engine optimization (SEO).
  • Schema.org has become the standard vocabulary for providing machines with an understanding of digital data.
  • Google prefers Schema.org data as JSON LD over the older methods using RDFa and microdata. Also, JSON LD might be a better solution for decoupled sites.
  • Google provides tools to validate structured data to ensure you’re creating the right results.
  • You can use the Schema.org Metatag module to add Schema.org structured data as JSON LD in Drupal and validate it using Google’s tools.
Why does structured data matter to SEO?

Humans can read a web page and understand who the author and publisher are, when it was posted, and what it is about. But machines, like search engine robots, can’t tell any of that automatically or easily. Structured data is a way to provide a summary, or TL;DR (Too long; didn't read), for machines, to ensure they accurately categorize the data that is being represented. Because structured data helps robots do their job, it should be a huge factor in improving SEO.

Google has a Structured Data Testing Tool that can provide a preview of what a page marked up with structured data will look like in search results. These enhanced results can make your page stand out, or at least ensure that the search results accurately represent the page. Pages that have AMP alternatives, as this example does, get extra benefits, but even non-AMP pages with structured data receive enhanced treatment in search results.

undefined Who is Schema.org and why should we care?

Schema.org has become the de-facto standard vocabulary for tagging digital data for machines. It’s used and recognized by Google and most or all of the other search engines.

If you go to the main Schema.org listing page, you’ll see a comprehensive list of all the types of objects that can be described, including articles, videos, recipes, events, people, organizations, and much much more. Schema.org uses an inheritance system for these object types. The basic type of object is a Thing, which is then subdivided into several top-level types of objects:

  • Thing
    • Action
    • CreativeWork
    • Event
    • Intangible
    • Organization
    • Person
    • Place
    • Product

These top-level Things are then further broken down. For example, a CreativeWork can be an Article, Book, Recipe, Review, WebPage, to name just a few options, and an Article can further be identified as a NewsArticle, TechArticle, or SocialMediaPosting.

Each of these object types has its properties, like ‘name,' ‘description,' and ‘image,' and each inherits the properties of its parents, and adds their own additional properties. For instance, a NewsArticle inherits properties from its parents, which are Thing, CreativeWork, and Article. Finally, NewsArticle has some additional properties of its own. So it inherits ‘author’ and ‘description’ from its parents and adds a ‘dateline’ property that its parents don’t have.

undefined

Some properties are simple key/value pairs, like description. Other properties are more complex, such as references to other objects. So a CreativeWork object may have a publisher property, which is a reference to a Person or Organization object.

Further complicating matters, an individual web page might be home multiple, related or unrelated, Schema.org objects. A page might have an article and also a video. There could be other elements on the page that are not part of the article itself, like a breadcrumb, or event information. Structured data can include as many objects as necessary to describe the page.

Because there’s no limit to the number of objects that might be described, there's also a property mainEntityOfPage, which can be used to indicate which of these objects is the primary object on the page.

What are JSON LD, RDFa, and Microdata, where do they go, and which is better?

Once you decide what Schema.org objects and properties you want to use, you have choices about how to represent them on a web page. There are three primary methods: JSON LD, RDFa, and Microdata.

RDFa and Microdata use slightly different methods of accomplishing the same end. They wrap individual items in the page markup with identifying information.

JSON LD takes a different approach. It creates a JSON array with all the Schema.org information and places that in the head of the page. The markup around the actual content of the page is left alone.

Schema.org includes examples of each method. For instance, here’s how the author of an article would be represented in each circumstance:

RDFa <div vocab="http://schema.org/" typeof="Article"> <h2 property="name">How to Tie a Reef Knot</h2> by <span property="author">John Doe</span> The article text. </div> Microdata <div itemscope itemtype="http://schema.org/Article"> <h2 itemprop="name">How to Tie a Reef Knot</h2> by <span itemprop="author">John Doe</span> The article text. </div> JSON LD <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "Article", "author": "John Doe", "name": "How to Tie a Reef Knot". “description”: “The article text”. } </script> Which is better?

There are advantages and disadvantages to each of these. RDFa and Microdata add some complexity to the page markup and are a little less human-readable, but they avoid data duplication and keep the item's properties close to the item.

JSON LD is much more human-readable, but results in data duplication, since values already displayed in the page are repeated in the JSON LD array.

All of these are valid, and none is really “better” than the other. That said, there is some indication that Google may prefer JSON LD. JSON LD is the only method that validates for AMP pages, and Google indicates a preference for it in its guide to structured data.

From the standpoint of Drupal’s theme engine, the JSON LD method would be the easiest to implement, since there’s no need to inject changes into all the individual markup elements of the page. It also might be a better solution for decoupled sites, since you could theoretically use Drupal to create a JSON LD array that is not directly tied to Drupal’s theme engine, then add it to the page using a front-end framework.

What about properties that reference other objects?

As noted above, many properties in structured data are references to other objects. A WebPage has a publisher, which is either an Organization or a Person.

There are several ways to configure those references. You can indicate the author of a CreativeWork either by using a shortcut, the string name or URL of the author, or by embedding a Person or Organization object. That embedded object could include more information about the author than just the name, such as a URL to an image of the person or a web page about them. In the following example, you can see several embedded references: image, author, and publisher.

<script type="application/ld+json">{ "@context": "http://schema.org", "@graph": [ { "@type": "Article", "description": "Example description.", "image": { "@type": "ImageObject", "url": "https://www.example.com/582753085.jpg", "width": "2408", "height": "1600" }, "headline": "Example Title", "author": { "@type": "Person", "name": "Example Person", "sameAs": [ "https://www.example-person.com" ] }, "dateModified": "2017-06-03T21:38:02-0500", "datePublished": "2017-03-03T19:14:50-0600", "publisher": { "@type": "Organization", "name": "Example.com", "url": "https://www.example.com//", "logo": { "@type": "ImageObject", "url": "https://www.example.com/logo.png", "width": "600", "height": "60" } } } ] }</script>

JSON LD provides a third way to reference other objects, called Node Identifiers. An identifier is a globally unique identifier, usually an authoritative or canonical URL. In JSON LD, these identifiers are represented using @id. In the case of the publisher of a web site, you would provide structured data about the publisher that includes the @id property for that Organization. Then instead of repeating the publisher data over and over when referencing that publisher elsewhere, you could just provide the @id property that points back to the publisher record. Using @id, the above JSON LD might look like this instead:

<script type="application/ld+json">{ "@context": "http://schema.org", "@graph": [ { "@type": "Article", "description": "Example description.", "image": { "@type": "ImageObject", "@id": "https://www.example.com/582753085.jpg" }, "headline": "Example Title", "author": { "@type": "Person", "@id": "https://www.example-person.com" }, "dateModified": "2017-06-03T21:38:02-0500", "datePublished": "2017-03-03T19:14:50-0600", "publisher": { "@type": "Organization", "@id": "https://www.example.com//" } } ] }</script> How can we be sure that Google understands our structured data?

Once you’ve gone to the work of marking up your pages with structured data, you’ll want to be sure that Google and other search engines understand it the way you intended. Google has created a handy tool to validate structured markup. You can either paste the URL of a web page or the markup you want to evaluate into the tool. The second option is handy if you’re working on changes that aren't yet public.

Once you paste your code into the tool, Google provides its interpretation of your structured data. You can see each object, what type of object it is, and all its properties.

If you’re linking to a live page rather than just providing a snippet of code, you will also see a ‘Preview’ button you can click to see what your page will look like in search results. The image at the top of this article is an example of that preview.

Schema.org doesn’t require specific properties to be provided for structured data, but Google has some properties that it considers to be “required” or “recommended.” If those are missing, validation will fail.

You can see what Google expects on different types of objects. Click into the links for each type of content to see what properties Google is looking for.

undefined How and where can we add structured data to Drupal?

The next logical question is what modules are available to accomplish the task of rendering structured data on the page in Drupal 8. Especially tricky is doing it in a way that is extensible enough to support that gigantic list of possible objects and properties instead of being limited to a simple subset of common properties.

Because of the complexity of the standards and the flexibility of Drupal’s entity type and field system, there is no one-size-fits-all solution for Drupal that will automatically map Schema.org properties to every kind of Drupal data.

The RDFa module is included in core and seems like a logical first step. Unfortunately, the core solution doesn’t provide everything needed to create content that fully validates. It marks up some common properties on the page but has no way to indicate what type of object a page represents. Is it an Article? Person? Organization? Event? There is no way to flag that. And there is no way to support anything other than a few simple properties without writing code.

There is a Drupal Summer of Code project called RDF UI. It adds a way to link a content type to a Schema.org object type and to link fields to Schema.org properties. Though the module pulls the whole list of possible values from Schema.org, some linkages aren’t possible, for instance, a way to identify the title or creation date as anything other than standard values. I tried it out, but content created using this module didn’t validate for me on Google’s tool. The module is very interesting, and it is a great starting point, but it still creates RDFa rather than JSON LD.

The architecture of the Schema.org Metatag module.

After looking for an existing solution for Drupal 8, I concluded there wasn’t a simple, valid, extensible solution available to create JSON LD, so I created a module to do it, Schema.org Metatag.

Most of the heavy lifting of Schema.org Metatag comes from the Metatag module. The Metatag module manages the mapping and storing of data is managed, allowing you to either input hard-coded values or use tokens to define patterns that describe where the data originates. It also has a robust system of overrides so that you can define global patterns, then override some of them at the entity type level, or at the individual content type level, and or even per individual item, if necessary. There is no reason not to build on that framework, and any sites that care about SEO are probably already using the Metatag module already. I considered it an ideal starting point for the Schema Metatag module.

The Schema.org Metatag module creates Metatag groups for each Schema.org object type and Metatag tags for the Schema.org properties that belong to that object.

The base classes created by the Schema.org Metatag module add a flag to groups and tags that can be used to identify those that belong to Schema.org, so they can be pulled out of the array that would otherwise be rendered as metatags, to be displayed as JSON LD instead.

Some Schema.org properties need more than the simple key/value pairs that Metatag provides, and this module creates a framework for creating complex arrays of values for properties like the Person/Organization relationship. These complex arrays are serialized down into the simple strings that Metatag expects and are unserialized when necessary to render the form elements or create the JSON LD array.

The primary goal was to make it easily and endlessly extensible. The initial module code focuses on the properties that Google notes as “Required” or “Recommended” for some basic object types. Other object types may be added in the future, but could also be added by other modules or in custom code. The module includes an example module as a model of how to add more properties to an existing type, and the existing modules provide examples of how to add other object types.

Also, there is a patch for the Metatag module to refactor it a bit to make it possible for a decoupled Drupal back end to share metatags with a front-end framework. Since this module is built on the Metatag model, hopefully, that change could be exploited to provide JSON LD to a decoupled front end as well.

This approach worked well enough in Drupal 8 that I am in the process of backporting it to Drupal 7 as well.

Enough talk, how do I get JSON LD on the page?

It’s helpful to understand how Schema.org objects and properties are intended to work, which is the reason for going into some detail about that here. It helps to figure out ahead of time what values you expect to see when you get done.

Start by scanning the Schema.org lists and Google’s requirements and recommendations to identify which objects and properties you want to define for the content on your site. If you’re doing this for SEO, spend some time reviewing Google's guide to structured data to see what interests Google. Not all content types are of interest to Google, and Google considers some properties to be essential while ignoring others.

Some likely scenarios are that you will have one or more types of Articles, each with images and relationships to the People that author them or the Organization that publishes them. You might have entity types that represent Events, or Organizations, or People or Places, or Products. Events might have connections to Organizations that sponsor them or People that perform in them. You should be able to create a map of the type of content you have and what kind of Schema.org object each represents.

Then install the Schema.org Metatag module and enable the sub-modules you need for the specific content types on your site. Use this module the same way you would use the Metatag module. If you understand how that works, you should find this relatively easy to do. See the detailed instructions for Metatag 8.x or Metatag 7.x. You can set up global default values using tokens, or override individual values on the node edit form.

In Conclusion

Providing JSON LD structured data on your website pages is bound to be good for SEO. But it takes a while to get comfortable with how structured data works and the somewhat confusing Schema.org standards, let alone Google’s unique set of requirements and recommendations.

No solution will automatically configure everything correctly out of the box, and you can’t avoid the need to know a little about structured data. Nevertheless, this article and the Schema.org Metadata module should enable you to generate valid JSON LD data on a Drupal site.

Maestro Overview Video randy Tue, 08/01/2017 - 09:13

We've put together a Maestro overview video introducing you to Maestro for Drupal 8.  Maestro is a workflow engine that allows you to create and automate a sequence of tasks representing any business process. If it can be flow-charted, then it can be automated. Workflows typically include the movement of documents or forms for editing and review/approval. A number of condition checks (if tasks) can be incorporated through simple admin functions and without any coding.

GSoC’17 Coding period | Week #9 | Drupal chiranjeeb2410 Tue, 08/01/2017 - 09:01
Dr. Serkan Aygin Clinic Website, Turkey’s Top Hair Clinic Dmitrii Susloparov Tue, 08/01/2017 - 12:55 Overview

Dr. Serkan Aygin is one of the first hair transplant doctors in Turkey, and has been performing successful hair transplant operations through the Dr. Serkan Aygin Clinic since 2013. As a world renowned hair transplant specialist, Dr. Aygin travels to international conferences and engages with a global audience. The Dr. Serkan Aygin Clinic regularly serves patients from all around the world.

 

The Dr. Serkan Aygin Clinic had an old website, built on a CMS that didn’t satisfy today’s business needs. The website did not support multiple languages, a definite limiting factor to expanding its multinational and multilingual customer base. Also, the site was not responsive, resulting in a negative user experience for the predominantly mobile world today.

 

Vardot was approached by the Dr. Serkan Aygin Clinic to develop a new website with the mandate to increase sales and business growth. The Dr. Serkan Aygin Clinic signed up specifically with Vardot, a company headquartered in Jordan with offices in Jordan, USA, and Egypt, because of its expertise in developing multilingual websites (including Arabic language). The inclusion of Arabic in its website enables the Dr. Serkan Aygin Clinic to market more effectively to the Gulf region.

 

Vardot successfully built a multilingual website for the Dr. Serkan Aygin Clinic using Varbase, a custom optimized distribution based on Drupal 8 CMS. As part of the overall solution, Vardot also translated the web contents to Arabic. In addition to multilingual support, the new website features significant SEO enhancements which improve its visibility to search engines.

Why Drupal was chosen

Drupal is an industry-leading website development platform renowned for its support of multilingual websites. The new Dr. Serkan Aygin Clinic website currently supports 3 languages (English, Arabic, and Turkish). Over time, 6 more languages will be added.

 

Another advantage of using Drupal in this project is the ability to easily build unique landing pages for different marketing campaigns. This is critical for Dr. Serkan Aygin Clinic in order to satisfy the mandate to increase sales and expand its business.

 

Last but not least, customization is a competitive advantage to the Dr. Serkan Aygin Clinic to stay as the top hair transplant clinic in the region. Drupal, by design, is a modular framework. As a result, a Drupal-based website can be customized to fully satisfy unique business requirements, both now and in the future.

Describe the project (goals, requirements and outcome)
  • Design, UI and UX
    The user interface for the Dr. Serkan Aygin Clinic website was redesigned from scratch. The new interface was planned, first and foremost, with user experience in mind. A modern reality is that mobile web users outnumber their desktop counterparts. To maximize user experience, a mobile-first approach was adopted in the implementation of the Clinic website. This approach constituted a clean break from the antiquated model of first creating the desktop UI and later somehow fitting the interface on mobile devices.

 

  • The CMS foundation
    The new website was developed using Varbase, a Vardot base distribution built on top of the Drupal 8 CMS framework. Varbase provided out-of-the-box mobile-ready functionalities in standard-compliant modules. This made customization easy, resulting in the quicker development of the Dr. Serkan Aygin Clinic website.

 

  • Multilingual site
    The new Dr. Serkan Aygin Clinic website supports 3 languages (English, Arabic, and Turkish) with plans to add 6 more. Without software support, creating and maintaining the website with potentially 9 languages would have greatly strained developer and editor resources. The Drupal 8 framework coupled with Varbase customization laid a solid foundation of multilingual support, for both now and later. The Varbase pre-built configuration options enabled editors to easily translate the Clinic website into multiple languages.

 

  • SEO
    The Dr. Serkan Aygin Clinic website was redesigned and implemented altogether on a different CMS. From the search engine perspective, this was a migration project from one set of URLs to another. The SEO risk in the migration project was that organic traffic, painstakingly built up by the previous website, might be lost for the new one due to obsolete URLs or a drop in search ranking. To mitigate the risk, upon migration of the website, all URLs from the legacy site were imported, and redirects were set up in the Drupal CMS. In addition, descriptive meta tags were used to facilitate indexing by search engines such as Google, Yandex, and Bing. Language-aware XML sitemaps comprised another SEO tool to prop up webpage visibility. Furthermore, optimized markups were implemented to comply with the web accessibility standard WCAG 2.0 level AA. As a result of using meta tags, markups, XML sitemaps, and other tools, search ranking for the Dr. Serkan Aygin Clinic website was optimized for the migration.
     

  • The outcome
    In February of 2017, Vardot completed and delivered the multilingual SEO-friendly website for the Dr. Serkan Aygin Clinic on Varbase, an optimized Drupal 8 distribution. The newly minted website fully supports English, Arabic, and Turkish. The resounding success of the new website was measured quantitatively using objective verifiable web metrics. The new website experienced an 800% increase in organic traffic after the launch. Data analysis further showed that site visitors stayed longer and were more engaged in the new website than the old one. More specifically, the bounce rate dropped from 70% to 26%, and the pages viewed per session increased over 200% from 1.2 to 3.7. Overall, the relaunching of the Dr. Serkan Aygin Clinic website drove the mandated business growth via an engaging multilingual web presence.

آخرین ارسال ها

محتواهای محبوب

درباره ما

Author
اینجا دروپال یعنی همه چیز. در مورد دروپال صحبت میکنیم. ماژول هامون رو به اشتراک میزاریم در مورد قالب دروپال ، فروشگاه دروپال، دروپال فارسی و تاریخ شمسی دروپال صحبت میکنیم و هرچیزی که در مورد طراحی سایت با دروپال میدونیم به هم انتقال میدیم. دروپالیون یک سایت شخصی نیست. ما دست همه کسانی که برای پیشرفت دروپال تلاش میکنند رو میفشاریم و با آغوش باز اونها رو در این سایت میپذیریم.

تماس با ما

با ما تماس بگیرید.

logo-samandehi