Drupal https://atendesigngroup.com/ en The body field is dead https://atendesigngroup.com/articles/body-field-dead <span>The body field is dead</span> <figure> <picture> <source srcset="/sites/default/files/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg?itok=TbgXmbKT 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg?itok=Fu66Vu4d 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg?itok=Fu66Vu4d 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg?itok=Fu66Vu4d 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg?itok=O0f_qjbU 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg?itok=O0f_qjbU 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2021-04/AUTHORING_EXPERIENCE_TYPESETTING_05.jpg" alt="" typeof="foaf:Image" /> </picture> </figure> <span><a title="View user profile." href="/user/james-nettik" lang="" about="/user/james-nettik" typeof="schema:Person" property="schema:name" datatype="">jnettik</a></span> <span>Thu, 04/15/2021 - 09:56</span> <a href="/articles/authoring-experience" class="tag" >Authoring Experience</a> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>Content authoring on the web has evolved. Compelling web content uses a variety of multimedia elements to engage users, tell stories, build brands, and share new ideas. Images, video clips, slideshows, static or parallax backgrounds, block quotes and text pullouts — more than ever, content creators need a tool that embraces an evolving medium and keeps pace with the author’s creativity. We believe <a href="https://atendesigngroup.com/articles/expressive-authoring-layout-paragraphs">Layout Paragraphs</a> is that tool. But first, let’s all agree that the body field is dead.</p> <h3>What is the body field</h3> <p>Web editors and content authors who have been around over the last decade of digital media are intimately familiar with the body field. Many popular content management systems (looking at you, Drupal and Wordpress) feature a standard “post” or “content” type — like page, article, or blog post — right out of the box. These content types often have a couple of fields to fill out before you can publish your post, things like title, tags, friendly URL / slug, and of course <i>body</i>.</p> <p>The body field, traditionally, is where all your content goes. In the early days of blogging and web publishing that was likely to be all or mostly text, but with time came images, videos, and eventually an array of other multimedia elements.<i> And the body field adapted.</i> Tokens became standard for plenty of web editors — cryptic chunks of text like <i>[[nid:376 align:right]]</i> that would be auto-magically replaced with other elements once you click Publish. WYSIWYG editors (What You See Is What You Get) started shipping with <i>Insert image</i> and <i>Insert video</i> buttons, and began including a variety of tools for encapsulating, aligning, and positioning lengths of text or various media elements. And while these accommodations started to connect content creators with the boundless possibilities of multimedia authoring, they were (and are) clumsy and unpredictable.</p> <h3>Structured content: Reduce, reuse, recycle</h3> <p>One major problem with all of these innovations is that once you click Publish, all that complex content <i>still ends up in the body field</i> — that is, saved into your database as one giant clump of complicated text, tokens, style codes, etc. If you’d like to publish another page with a similar look &amp; feel, get ready to re-inject all of your tokens or go through the same WYSIWYG click-a-thon to reestablish your styles and layout. Thinking of producing a list of all the images used in your posts? Good luck! With all content mushed together into a single field, your site doesn’t “know” the difference between a paragraph of text, an image, or a video.</p> <p>A structured approach to content organizes each individual element — a pane of text, an image, slideshow, video, or a “donate now” banner — as its own self-contained entity which, ideally, could then be placed within flexibly configured regions on a page. Creating other, similar pages then becomes as simple as swapping out individual elements or shifting them around between regions of a page. And libraries of reusable content elements become the norm — so that you’re now picking your images, videos, donate banners and more from lists of existing content or existing content styles, instead of trying to hunt down how you did something similar the last time.</p> <p>Structuring your content into individual, reusable elements drives a lot of collateral benefits:</p> <ul> <li><b>Ease of content creation.</b> Authoring with a consistent set of components lets you focus more on content, hierarchy, and intent — instead of trying to remember how you got a video in there at all the last time.</li> <li><b>Styling and restyling.</b> Using discrete elements of content means that your HTML markup and CSS remains consistent across all of your various pages. When the time comes to update the look &amp; feel of your website, changes made on one article page will “just work” on the rest of your articles and all of their elements.</li> <li><b>Content migration.</b> The day might arrive when you consider migrating your content to a newer platform or different software. Structured content makes that a snap: Each image, video, slideshow, or paragraph of text gets individually ported to its new home on the new platform. On the contrary, migrating a mess of markup, tokens, and style codes stored in a single body field means writing complex, custom code to recognize those items and deal with them appropriately — not a simple task.</li> <li><b>Syndication.</b> Want to feature your content in a collection via RSS or deploy it to an app with XML? With structured content apps and other websites can consume just the elements they want of your content (maybe the first paragraph, a title, an image, or a link) then display those elements appropriately according to their own styles — rather than just grabbing a few hundred lines of a single, messy body field and making do.</li> <li><b>Libraries, lists, and cross-promotion.</b> Want to see all the slideshows that appear in articles with a specific tag? Maybe a list of pull-quotes from your most recent blog posts? Structured content creates a world of opportunity around libraries, lists and cross-promotions.</li> </ul> <p>Structuring content facilitates reuse, and it positions your content to go on living in a variety of platforms or a variety of presentations — long after you first click the Publish button.</p> <h3>The two faces of web content</h3> <p>Structuring content is an essential part of beautiful, intuitive digital authoring, but it’s only one side of the coin. The other side is putting an end to the two faces of your web content. Excepting some of the advances of modern WYSIWYG editors, web content has always had two very different faces: <em>View</em> and <em>Edit</em>.</p> <p>The way content is <em>edited</em> and the way it’s <em>presented</em> are often strikingly different. Especially if you’re still holding on to “one giant body field” innovations like custom tokens, BBCode, Markdown, or short codes, it can take a handful of <em>Preview</em> to <em>Edit</em> to <em>Preview</em> roundtrips to get your content exactly how you want it. Even if you’ve made the move to structured content, a majority of web-based editors are marked by a dramatic difference between the “back end” and the “front end” — just one more digital convention getting between inspired authors and publishing beautiful content easily.</p> <h3>The king is dead, long live the king</h3> <p>The body field is dead. It’s taken center stage in publishing digital content for long enough. Plenty of web products (<a href="https://medium.com/">Medium</a> and <a href="https://www.notion.so/">Notion</a>, to name a couple) have driven nails in that coffin for publishers creating content on those specific platforms. But what about content creators and web editors working within their organizations’ websites, in custom web applications where content authoring is just one of several important features? What about you, and your organization’s website? <em>What’s next for your web application?</em></p> <p>For Drupal websites, we think Layout Paragraphs is what’s next. It was first released to the Drupal community nearly a year ago, and has been the beneficiary of ambitious development ever since.</p> <p>The Layout Paragraphs module makes it dead simple for authors to create robust, multimedia content from a library of available components. It offers intuitive drag-and-drop controls for managing content flow and layout, and with appropriate styling can bring the two faces of web content — <em>View</em> and <em>Edit</em> — closer than ever before. We built Layout Paragraphs to embrace the future of multimedia content authoring and to solve the problems we watch clients work through every day.</p> <p>You can watch a short, <a href="https://atendesigngroup.com/articles/expressive-authoring-layout-paragraphs">two-minute demo of Layout Paragraphs</a> here, or follow the instructions in that post to see it in action for yourself.</p> <!-- google doc id: 1tYNNuOS56RvD2_m4n1VKh6uWSS3lv07dnnPriKu_J3I --></div> <a href="/about/james-nettik" hreflang="en">James Nettik</a> Thu, 15 Apr 2021 15:56:20 +0000 jnettik 10251 at https://atendesigngroup.com https://atendesigngroup.com/articles/body-field-dead#comments Drupal 7 to Drupal 8, 9 and beyond: Your last major upgrade? https://atendesigngroup.com/articles/drupal-7-drupal-8-9-and-beyond-your-last-major-upgrade <span>Drupal 7 to Drupal 8, 9 and beyond: Your last major upgrade?</span> <figure> <picture> <source srcset="/sites/default/files/2021-03/DRUPAL_UPGRADES_05.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2021-03/DRUPAL_UPGRADES_05.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2021-03/DRUPAL_UPGRADES_05.jpg?itok=ovlpIBcj 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-03/DRUPAL_UPGRADES_05.jpg?itok=zRCf3XEW 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-03/DRUPAL_UPGRADES_05.jpg?itok=zRCf3XEW 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-03/DRUPAL_UPGRADES_05.jpg?itok=zRCf3XEW 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2021-03/DRUPAL_UPGRADES_05.jpg?itok=iR0-tnMo 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2021-03/DRUPAL_UPGRADES_05.jpg?itok=iR0-tnMo 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2021-03/DRUPAL_UPGRADES_05.jpg" alt="" typeof="foaf:Image" /> </picture> </figure> <span><a title="View user profile." href="/user/joel-steidl" lang="" about="/user/joel-steidl" typeof="schema:Person" property="schema:name" datatype="">Joel Steidl</a></span> <span>Thu, 03/11/2021 - 11:41</span> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>Upgrading from Drupal 7 to Drupal 8 is a major project (a full rebuild in most cases) that can rival or even top the original cost of application development. Upgrading from Drupal 8 to 9 and beyond, in comparison, requires just a tiny fraction of that effort. Here’s a look at why — and why you should take the leap from Drupal 7 to Drupal 8 and 9.</p> <p>The upgrade from Drupal 7 to Drupal 8 was a major theme for plenty of our clients over the last few years. Drupal 8 — and versions beyond — boast a wide range of benefits that stem from a more modern architecture, but one of the biggest wins in my mind is the advent of <a href="https://semver.org/">semantic versioning</a> (for Drupal) and a <a href="https://dri.es/making-drupal-upgrades-easy-forever">renewed commitment to making Drupal upgrades easy forever</a>. Moving to Drupal 8 could be your last major upgrade.</p> <h3>The ghost of Drupal past</h3> <p>The move from Drupal 7 to Drupal 8 isn’t easy. While it’s often still touted as an “upgrade process” the reality is that it boils down to a complete rewrite of the codebase <i>and a content migration</i>. We’ve worked on more than a handful of Drupal 7 to Drupal 8 upgrades in the last years, and the majority constitute a “six months or more” sized project.</p> <p>One reason for that is Drupal’s new <a href="https://symfony.com/">Symfony</a> reliant architecture that leans far closer to the tenets of object oriented programming (OOP) versus the more procedural approach used in previous Drupal versions — a significant technical change which in most cases means<i> Drupal 7 code simply won’t work in Drupal 8.</i> Add to that a completely revamped templating system and you get a similar obstacle on the front-end: <i>Drupal 7 templates &amp; templating systems won’t work in Drupal 8</i>. Those major changes along with a potentially long list of complications with Drupal 8 data migrations is likely to land your Drupal 7 to Drupal 8 upgrade squarely in “rebuild the application” territory.</p> <p><i>The good news is that it’s the last time.</i></p> <h3>Drupal 8 and beyond: Your last major upgrade</h3> <p>Drupal 8, 9 and beyond promise a continued investment in modern architecture, incremental major feature releases, greater stability and sustainability, and a much larger network of invested developers — among lots of other perks. Perhaps the best news to come along with the new Drupal architecture is that large-scale, overhaul-style major version upgrades will be a thing of the past. And we’re beginning to see that now as we begin moving Drupal 8 sites to Drupal 9.</p> <h4>Clearing the road ahead: A commitment to easy upgrade paths</h4> <p>With Drupal 8 comes the commitment to semantic versioning. Semantic versioning isn’t just a naming convention for software versions, it’s a descriptive norm that guides how new versions of code should be written and establishes strict backwards compatibility requirements. The upshot for end users is significant but manageable incremental changes between major versions (say 8.x and 9.x) which aim towards seamless major version upgrades. Major versions can no longer make dramatic jumps (like Drupal 8’s move to OOP or the Twig templating system) which necessitate major code rewrites, but instead make small, reasonable changes between minor versions.</p> <p>With the new approach to versioning developers get a variety of automated tools that ease the shift&nbsp;between minor and major versions. <a href="https://www.drupal.org/docs/updating-drupal/how-to-prepare-your-drupal-7-or-8-site-for-drupal-9/deprecation-checking-and">Deprecation checking</a> means developers get notices in their code editors when parts of the existing codebase have been marked as deprecated, i.e., queued for change or removal in an upcoming major version. Automated tools like <a href="https://www.drupal.org/project/upgrade_status">Upgrade Status</a> or <a href="https://github.com/palantirnet/drupal-rector">Drupal Rector</a> and its Drupal front-end <a href="https://www.drupal.org/project/upgrade_rector">Upgrade Rector</a> can provide detailed upgrade status information and even automatically update code between major versions. All in all, upgrade paths are looking easier than ever.</p> <h4>A wider foundation: Sustainability through community (and Symfony)</h4> <p>Building Drupal on top of Symfony means even further specialization on the Drupal end. The new Drupal versions use Symfony for a host of standard web application tasks — things like form validation, data serialization, data storage and retrieval, content translation, templating, easy and human-readable configuration management with YAML — the list goes on. Building on top of Symfony lets Drupal developers build closer to the <i>consumer level</i>, i.e., build the media libraries, authoring experiences, layout managers, etc that really matter to users.</p> <p>Drupal’s reliance on Symfony — a robust and mature web application framework with more than 600,000 registered developers — also translates to greater sustainability through a larger active community. Besides adding Symfony’s 600K developers to Drupal’s roughly 1 million, the move to a modern architecture and more collaborative versioning system makes Drupal <i>more attractive to developers on the leading edge of their disciplines</i>. That fact alone stands to benefit the Drupal community through new, top-tier talent driving further innovation.</p> <h4>Regular new stuff: Incremental feature releases</h4> <p>With Drupal’s new versioning cycle comes another benefit: major new features in minor version core releases. As Drupal 8 churns through minor releases (the second place in the three place version number, e.g. “y” in x.y.z) it continues to add brand new features to core. Unlike previous major Drupal versions, these aren’t just bug fixes and security upgrades. Game changing modules like <a href="https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module">JSON API</a>, <a href="https://www.drupal.org/docs/8/core/modules/media">Media</a>, and <a href="https://www.drupal.org/docs/8/core/modules/layout-builder">Layout Builder</a> were all added to Drupal 8 in minor version releases — and more are in the works.</p> <p>What does this mean for end users? A greater commitment to standardized features that meet primary needs (like media and layout management, for example) and a bigger pool of developers making sure those features are updated, stable, and compatible.</p> <hr /> <p>I just finished one of my first Drupal 8/9 upgrades yesterday for a small searchable database of computer science tips &amp; tricks run by a college out of Claremont, California. Admittedly it was a pretty simple site, but the upgrade took me just two hours. Wow.</p> <p>Aten will be working on a variety of Drupal 8 to Drupal 9 upgrades in the coming months, but the landscape is almost unrecognizable compared to our Drupal 7 to Drupal 8 efforts. For us, for the rest of the Drupal world, and for our clients, that is real good news.</p> <!-- google doc id: 1-BjDI6YKjsXvdvwR8mJdvd_cnUB6Tx7uvR_np9AFOxo --></div> <a href="/about/joel-steidl" hreflang="en">Joel Steidl</a> Thu, 11 Mar 2021 18:41:57 +0000 Joel Steidl 10231 at https://atendesigngroup.com https://atendesigngroup.com/articles/drupal-7-drupal-8-9-and-beyond-your-last-major-upgrade#comments Site building with Drupal Layout Builder https://atendesigngroup.com/webinar/site-building-drupal-layout-builder <span>Site building with Drupal Layout Builder</span> <article data-history-node-id="10178" role="article" about="/about/james-nettik" class="js--block-link profile profile--compact" data-href="/about/james-nettik" > <div class="profile__image"> <figure> <picture> <source srcset="/sites/default/files/james-nettik.png 1x" media="(min-width: 1860px)" type="image/png"/> <source srcset="/sites/default/files/james-nettik.png 1x" media="(min-width: 1540px)" type="image/png"/> <source srcset="/sites/default/files/styles/responsive_large/public/james-nettik.png?itok=6tIJjejL 1x" media="(min-width: 1265px)" type="image/png"/> <source srcset="/sites/default/files/styles/responsive_medium/public/james-nettik.png?itok=lySRzyZJ 1x" media="(min-width: 1024px)" type="image/png"/> <source srcset="/sites/default/files/styles/responsive_medium/public/james-nettik.png?itok=lySRzyZJ 1x" media="(min-width: 768px)" type="image/png"/> <source srcset="/sites/default/files/styles/responsive_medium/public/james-nettik.png?itok=lySRzyZJ 1x" media="(min-width: 600px)" type="image/png"/> <source srcset="/sites/default/files/styles/responsive_small/public/james-nettik.png?itok=V7XKtki5 1x" media="(min-width: 500px)" type="image/png"/> <source srcset="/sites/default/files/styles/responsive_small/public/james-nettik.png?itok=V7XKtki5 1x" media="(min-width: 0)" type="image/png"/> <img src="/sites/default/files/james-nettik.png" alt="" typeof="foaf:Image" /> </picture> </figure> </div> <div class="profile__content clearfix"> <h3 class="profile__title"> <a href="/about/james-nettik" class="profile__title-link">James Nettik</a> </h3> <div class="profile__job-title">Senior Developer Manager</div> </div> </article> <article data-history-node-id="10227" role="article" about="/about/jess-snyder" class="js--block-link profile profile--compact" data-href="/about/jess-snyder" > <div class="profile__image"> <figure> <picture> <source srcset="/sites/default/files/2021-03/jess-snyder.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2021-03/jess-snyder.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2021-03/jess-snyder.jpg?itok=TVUCE0II 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-03/jess-snyder.jpg?itok=akSjrcah 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-03/jess-snyder.jpg?itok=akSjrcah 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2021-03/jess-snyder.jpg?itok=akSjrcah 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2021-03/jess-snyder.jpg?itok=xpg3MQh0 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2021-03/jess-snyder.jpg?itok=xpg3MQh0 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2021-03/jess-snyder.jpg" alt="Jess Snyder" typeof="foaf:Image" /> </picture> </figure> </div> <div class="profile__content clearfix"> <h3 class="profile__title"> <a href="/about/jess-snyder" class="profile__title-link">Jess Snyder</a> </h3> <div class="profile__job-title">Senior Manager, Web Systems at WETA</div> </div> </article> <span><a title="View user profile." href="/user/justin-toupin" lang="" about="/user/justin-toupin" typeof="schema:Person" property="schema:name" datatype="">Justin Toupin</a></span> <span>Wed, 03/10/2021 - 15:57</span> <div class="field field--name-field-zoom-webinar-agenda field--type-string-long field--label-hidden field__item">Join Senior Front-end Developer James Nettik of Aten Design Group and Senior Manager of Web Systems Jess Snyder of WETA for an in-depth look at Layout Builder in Drupal core.<br /> <br /> In this one-hour session we&#039;ll cover:<br /> <br /> - When Layout Builder is the right fit for your project.<br /> - How to use Layout Builder to create default layouts for content types.<br /> - When, why, and how to create page-specific overrides for your content.<br /> <br /> Who is this for:<br /> <br /> - Site builders working with Drupal.<br /> - Teams considering a move to Drupal 8 or 9.<br /> - Content authors looking for more control over their website content, without having to write code.</div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Join Senior Front-end Developer James Nettik of Aten Design Group and Senior Manager of Web Systems Jess Snyder of <a href="https://weta.org">WETA</a> for an in-depth look at Layout Builder in Drupal core.</p> <h2>In this one-hour session we'll cover:</h2> <ul> <li>When Layout Builder is the right fit for your project.</li> <li>How to use Layout Builder to create default layouts for content types.</li> <li>When, why, and how to create page-specific overrides for your content.</li> </ul> <h2>Who is this for:</h2> <ul> <li>Site builders working with Drupal.</li> <li>Teams considering a move to Drupal 8 or 9.</li> <li>Content authors looking for more control over their website content, without having to write code.</li> </ul></div> <div class="field field--name-field-date field--type-daterange field--label-above"> <div class="field__label">Date</div> <div class="field__item"><time datetime="2021-03-24T18:00:00Z">Wed, 03/24/2021 - 12:00</time> - <time datetime="2021-03-24T19:00:00Z">Wed, 03/24/2021 - 13:00</time> </div> </div> <div class="field field--name-field-zoom-webinar-join-url field--type-string field--label-hidden field__item">https://atendesigngroup.zoom.us/j/97081500402</div> <a href="/articles/authoring-experience" class="tag" >Authoring Experience</a> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> Wed, 10 Mar 2021 22:57:57 +0000 Justin Toupin 10228 at https://atendesigngroup.com Expressive Authoring with Layout Paragraphs https://atendesigngroup.com/articles/expressive-authoring-layout-paragraphs <span>Expressive Authoring with Layout Paragraphs</span> <figure> <picture> <source srcset="/sites/default/files/2020-11/layout-paragraphs.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2020-11/layout-paragraphs.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2020-11/layout-paragraphs.jpg?itok=hjIdtBJs 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-11/layout-paragraphs.jpg?itok=Oi4UHv9j 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-11/layout-paragraphs.jpg?itok=Oi4UHv9j 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-11/layout-paragraphs.jpg?itok=Oi4UHv9j 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-11/layout-paragraphs.jpg?itok=8pCgbeNb 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-11/layout-paragraphs.jpg?itok=8pCgbeNb 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2020-11/layout-paragraphs.jpg" alt="Layout Paragraphs Module" typeof="foaf:Image" /> </picture> </figure> <span><a title="View user profile." href="/user/justin-toupin" lang="" about="/user/justin-toupin" typeof="schema:Person" property="schema:name" datatype="">Justin Toupin</a></span> <span>Wed, 11/18/2020 - 11:30</span> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <a href="/blog/category/user-experience" class="tag" >User Experience</a> <a href="/articles/authoring-experience" class="tag" >Authoring Experience</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><h2>The Authoring Experience Problem</h2> <p>Authoring experience is a huge concern for web teams everywhere. As it should be. The ability for digital publishers to keep up with the rapidly accelerating demands of their users, and the pace of their competitors, largely depends on providing easy-to-use, expressive tools for their teams to create compelling content.</p> <p>In practice, this means that publishers need the ability to quickly produce rich digital content from a range of possible components: text, images, videos, social media assets, and so on. Authors should be able to mix various elements quickly and effortlessly, with simple controls for managing content flow and layout. Under the hood, content should be structured and predictable. We’ve written about this before: <a href="https://atendesigngroup.com/articles/flexible-authoring-structured-content">organizations cannot sacrifice structure for flexibility</a>. They need both.</p> <p>And yet authoring experience has been a major shortcoming of Drupal, often articulated by marketing and editorial leaders as, “Drupal is too complicated for my organization.”</p> <p>Other platforms from across the entire spectrum of digital publishing systems – from Adobe Experience Manager to Wordpress, Squarespace to WiX – provide rich, intuitive tools for easily creating all kinds of digital content. What Drupal offers in terms of flexibility – powerful APIs, easily customizable structured content, and a huge range of content management features – has come at the expense of the authoring experience.</p> <h2>Layout Paragraphs</h2> <p>A while ago I wrote about <a href="https://atendesigngroup.com/articles/drupal-8-paragraphs-layout-discovery">Entity Reference with Layout (or ERL)</a>, a Drupal 8 module that combines <a href="https://www.drupal.org/project/paragraphs">Paragraphs</a> with the <a href="https://www.drupal.org/docs/drupal-apis/layout-api">Layout API</a> for a more flexible, expressive authoring experience in Drupal. ERL had one concerning drawback: you had to use a special field type for referencing paragraphs. That means ERL wouldn’t “just work” with existing paragraph fields.</p> <p><a href="https://www.drupal.org/project/layout_paragraphs">Layout Paragraphs</a>, the successor to ERL, fixes that problem. The Layout Paragraphs module combines Drupal Paragraphs with the Layout API and works seamlessly with existing paragraph reference fields.</p> <p><div data-embed-button="media_browser" data-entity-embed-display="view_mode:media.embedded" data-entity-type="media" data-entity-uuid="d8ad4929-d00f-4892-8ca0-da70a5fef626" data-langcode="en" class="embedded-entity"><figure> <div class="field field--name-field-media-video-file field--type-file field--label-visually_hidden"> <div class="field__label visually-hidden">Video file</div> <div class="field__item"><video controls="controls" width="640" height="480"> <source src="/sites/default/files/2020-11/Layout-Paragraphs.mp4" type="video/mp4"></source> </video> </div> </div> </figure> </div> </p> <p>The Layout Paragraphs module makes it dead simple for authors to build rich pages from a library of available components. It offers drag-and-drop controls for managing content flow and layout, and works seamlessly with existing paragraph reference fields.</p> <p><b>Layout Paragraphs features include: </b></p> <ul> <li>Easily configure which content components, or paragraph types, are available to your authors wherever Layout Paragraphs is used.</li> <li>A highly visual, drag-and-drop interface makes it simple to manage content flow and layout.</li> <li>Site admins can easily configure Layout Paragraphs to support nested layouts up to 10 levels deep.</li> <li>A “disabled bin” makes it easy to temporarily remove content elements without deleting them.</li> <li>Layout Paragraphs works seamlessly with existing paragraph reference fields.</li> <li>Authors can easily switch between different layouts without losing nested content.</li> <li>Layout Paragraphs is fully customizable and works with Layout Plugins, Paragraph Behaviors, and other Drupal APIs.</li> </ul> <h2>What About Layout Builder?</h2> <p>While there are strong similarities between Layout Paragraphs and Layout Builder, Layout Paragraphs solves a fundamentally different problem than Layout Builder.</p> <p><i>Layout Builder</i>, in Drupal core, is a powerful system for managing layouts across an entire website. With Layout Builder, site administrators and content managers can place content from virtually anywhere (including custom blocks) within specific regions of a layout. Layout Builder is extremely powerful, but doesn’t directly solve the problem I mentioned above: “Drupal is too complicated for my organization.”</p> <p><i>Layout Paragraphs</i> adds a new interface for effortlessly managing content using Drupal Paragraphs. It is simple, fast, and expressive. Layout Paragraphs is a field widget, and works the same way as other Drupal fields. The Layout Paragraphs module makes it simple for publishers to create and manage rich content from a library of available components: text, images, videos, etc. Layout Paragraphs is completely focused on the authoring experience.</p> <h2>Try It Out</h2> <p>If you want to see Layout Paragraphs in action, simply download the module and give it a try. Setup is fast and easy. From the Layout Paragraphs module page:</p> <ol> <li>Make sure the <a href="https://www.drupal.org/project/paragraphs">Paragraphs module </a>is installed.</li> <li>Download/Require (composer require drupal/layout_paragraphs) and install Layout Paragraphs.</li> <li>Create a new paragraph type (admin &gt; structure &gt; paragraph types) to use for layout sections. Your new paragraph type can have whatever fields you wish, although no fields are required for the module to work.</li> <li>Enable the “Layout Paragraphs” paragraph behavior for your layout section paragraph type, and select one or more layouts you wish to make available.</li> <li>Make sure your new layout section paragraph type is selected under “Reference Type” on the content type’s reference field edit screen by clicking “edit” for the respective field on the “Manage fields” tab.</li> <li>Choose “Layout Paragraphs” as the field widget type for the desired paragraph reference field under “Manage form display”.</li> <li>Choose “Layout Paragraphs” as the field formatter for the desired paragraph reference field under “Manage display”.</li> <li>That’s it. Start creating (or editing) content to see the module in action.</li> </ol> <p>If you’re using Layout Paragraphs in your projects, we’d love to hear about it. Drop a note in the comments section below, or get involved in the <a href="https://www.drupal.org/project/issues/layout_paragraphs">issue queue</a>.</p> <!-- google doc id: 1QOz7bbiW9Jd7QCC8kLuJ3YzRiELKMRO6uFJ1Ts3s68M --></div> <div class="c-article-list"> <h3 class="c-article-list__title">Read This Next</h3> <div class="item-list"> <ul> <li><a href="/articles/drupal-8-paragraphs-layout-discovery" hreflang="und">Drupal 8 Paragraphs + Layout Discovery</a></li> <li><a href="/articles/flexible-authoring-structured-content" hreflang="und">Flexible Authoring with Structured Content </a></li> </ul> </div> </div> <a href="/about/justin-toupin" hreflang="en">Justin Toupin</a> Wed, 18 Nov 2020 18:30:00 +0000 Justin Toupin 10197 at https://atendesigngroup.com https://atendesigngroup.com/articles/expressive-authoring-layout-paragraphs#comments Absolute menu links in Drupal 8 https://atendesigngroup.com/articles/absolute-menu-links-drupal-8 <span>Absolute menu links in Drupal 8</span> <span><a title="View user profile." href="/user/joel-steidl" lang="" about="/user/joel-steidl" typeof="schema:Person" property="schema:name" datatype="">Joel Steidl</a></span> <span>Thu, 11/12/2020 - 12:15</span> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <a href="/blog/category/development" class="tag" >Code</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>Creating absolute menu links in Drupal 8 is pretty simple, but it took a little thought to land on the best solution for my use case. I ran into the requirement while working with a client to deploy their site navigation to a REACT app sitting on a different domain. The menu links we pulled in from their primary website needed to point back to their domain correctly, which of course meant they needed to be absolute.</p> <p>A quick search turned up a couple of solutions, but none that quite suited my requirements. Here’s what I came up with — it’s fairly concise, leaves the menu link attributes intact, and doesn’t involve the theme layer.</p> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/** * Implements hook_preprocess_menu(). * */</span> <span style="color: #000000; font-weight: bold;">function</span> MYTHEME_preprocess_menu<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$variables</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// Limit to specific menus for performance.</span> <span style="color: #000088;">$menus</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'main'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'footer'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$variables</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'menu_name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <a href="http://www.php.net/in_array"><span style="color: #990000;">in_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$variables</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'menu_name'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$menus</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> MYTHEME_set_menu_items_to_absolute<span style="color: #009900;">&#40;</span><span style="color: #000088;">$variables</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'items'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * Recursively make menu items link with absolute. * */</span> <span style="color: #000000; font-weight: bold;">function</span> MYTHEME_set_menu_items_to_absolute<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$items</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$items</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'url'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isExternal</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'url'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$url</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'absolute'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #666666; font-style: italic;">// Recursively loop of sub-menu items.</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'below'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> MYTHEME_set_menu_items_to_absolute<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'below'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span></pre></div></pre> <p>Generating absolute menu links this way means&nbsp;I can pull main navigation onto various apps without any headache and without sacrificing any Drupal theme layer functionality.</p> <p><a href="https://gist.github.com/joelsteidl/26d9330a1c7994c59c5ebd2f7d5bb49f">You can download the gist here.</a> Make sure you specify which menus you'd like to act on, by machine name, in the first line of the&nbsp;<em>MYTHEME_preprocess_menu()</em> function. The code goes in <em>mytheme.theme</em>&nbsp;— don't forget to replace <em>MYTHEME</em> with your theme name throughout.</p> <p>Do you have a simpler way? Feel free to share in the comments.</p> <!-- google doc id: 1l7kKEKkKpRjXfwipoX7Z06o9uLVJ6LRm-SmxuENInaE --></div> <a href="/about/joel-steidl" hreflang="en">Joel Steidl</a> Thu, 12 Nov 2020 19:15:00 +0000 Joel Steidl 10169 at https://atendesigngroup.com https://atendesigngroup.com/articles/absolute-menu-links-drupal-8#comments Add to Calendar buttons with AddEvent for Drupal 8 https://atendesigngroup.com/articles/add-calendar-buttons-addevent-drupal-8 <span>Add to Calendar buttons with AddEvent for Drupal 8</span> <span><a title="View user profile." href="/user/travis-tomka" lang="" about="/user/travis-tomka" typeof="schema:Person" property="schema:name" datatype="">Travis Tomka</a></span> <span>Tue, 10/20/2020 - 16:28</span> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>The <a href="https://www.drupal.org/project/addevent">AddEvent module for Drupal 8</a> lets you place easy-to-use <i>Add to Calendar</i> buttons on your website that integrate with Apple, Google, Yahoo, Outlook, and Office 365 calendar apps among others. The module also lets your users subscribe to entire calendars managed by AddEvent, adding all of your scheduled events to their calendars and keeping their calendars updated if your event details change.</p> <p>The module is powered by <a href="https://www.addevent.com/">AddEvent</a> and you’ll need an AddEvent account for it to work properly. Free accounts include one calendar, restricted event-adds, and limited functionality; paid accounts include multiple calendars, higher subscriber limits, and a wide variety of other features. You’ll be able to build <i>Add to Calendar </i>proof-of-concept functionality with the AddEvent free version in just 15-20 minutes — but a professional tier account is necessary for any commercial level use.</p> <h3>First things first: Create an AddEvent account</h3> <p>Head over to AddEvent.com and register for an account. AddEvent is a paid service that offers a variety of features and high volume usage for licensed customers — but they also provide a free <i>Hobby</i> account that will get you started. After creating and verifying your account with the free <i>Hobby</i> plan, navigate to the Account screen by clicking on the user menu in the upper right corner of the screen, then clicking Account. From there, click <i>Domains</i> in the left-hand navigation, then follow instructions to add your domain.</p> <figure role="group" class="align-center"> <div alt="AddEvent Module: domain whitelisting" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="fa936765-8351-4bfe-9562-e08d6cc6258a" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_licensed_domains.png" alt="AddEvent Module: domain whitelisting" title="AddEvent Module: domain whitelist" typeof="foaf:Image" /> </div> <figcaption>The domain where you will be using an Add to Calendar button needs to be whitelisted with AddEvent.</figcaption> </figure> <p>The <i>Hobby </i>plan only allows the use of one domain — but you’re able (at the time of writing this, anyway) to add a local development environment so that you can test without deploying to a publicly accessible website. When you’re ready to make the switch, you can simply remove your development domain and add in your live domain.</p> <h3>Install the Drupal 8 AddEvent module</h3> <p>Once you’ve registered for the service you’ll need to install the AddEvent module in your Drupal 8 website. You can <a href="https://www.drupal.org/docs/extending-drupal/installing-modules">install a Drupal 8 module</a> in a variety of ways, but the easiest is probably using your terminal, starting from your project’s root directory. First require the module using composer:</p> <p><span class="geshifilter"><code class="php geshifilter-php">composer <span style="color: #b1b100;">require</span> drupal<span style="color: #339933;">/</span>addevent</code></span></p> <p>Then enable the module using drush:</p> <p><span class="geshifilter"><code class="php geshifilter-php">drush en addevent</code></span></p> <p>Now you’re all set to start using the AddEvent module. You can immediately create single-use <i>Add to Calendar</i> buttons using custom blocks, or combine custom blocks with a custom <i>Event</i> node type and the <a href="https://www.drupal.org/project/token">Token</a> module to automatically produce <i>Add to Calendar</i> buttons for all of your events.</p> <h3>Add to Calendar: Static event buttons</h3> <p>Creating a static <i>Add to Calendar</i> button for a single event is super simple. Before we configure a block with our <i>Add to Calendar</i> link, though, we’ll need to fetch our <i>Client ID</i> from AddEvent. To do that, simply navigate to the <i>Account</i> page at <a href="https://www.addevent.com/">AddEvent.com</a> using the menu in the upper right corner of the screen. You should see a <i>Client ID</i> and <i>API Token</i> — just keep this window open or paste the <i>Client ID</i> in a safe place.</p> <figure role="group" class="align-center"> <div alt="AddEvent Module: Client ID" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="be6d5d54-b3e9-4986-8b63-cd93c8588430" data-langcode="en" title="AddEvent Module: Client ID" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_client_id_0.png" alt="AddEvent Module: Client ID" title="AddEvent Module: Client ID" typeof="foaf:Image" /> </div> <figcaption>You'll need the Client ID to render your Add to Calendar buttons without the AddEvent branding.</figcaption> </figure> <p>Now on your Drupal site navigate to <i>Structure</i> &gt; <i>Block layout</i> (/admin/structure/block) and click on <i>Place block</i> in the region you would like to place your <i>Add to Calendar</i> button. In my case, I’ll demonstrate adding the button to the <i>Content</i> region of a basic page that lives at the URL <em>/my-basic-page</em>.</p> <p>From the <i>Place a block</i> dialogue that follows, click <i>Place block</i> next to the <i>Add to Calendar</i> item. Fill out the following fields as indicated to get your first example working:</p> <ul> <li><b>Title:</b> Add to Calendar</li> <li><b>Display title:</b> <i>not checked </i></li> <li><b>Button text:</b> Add to Calendar</li> <li><b>Title:</b> My example event!</li> <li><b>Description:</b> My example event description!</li> <li><b>Start:</b> 10/31/2020 8:00 AM (the format is important, the date isn’t)</li> <li><b>End:</b> 10/31/2020 9:15 AM</li> <li><b>Client:</b> [Client ID from above]</li> </ul> <p>Under the <i>Customization</i> portion of the form, paste your <i>Client ID</i> in the <i>License</i> field. This will remove the AddEvent branding from your button dialogue.</p> <p>Finally, in the <i>Visibility</i> section of your block setup, choose <i>Pages</i> and write in the URL of the page you’d like the block on — in my case I’ll use /my-basic-page. Click <i>Save block</i> and navigate to the page you configured your block to appear on.</p> <figure role="group" class="align-center"> <div alt="AddEvent module, an Add to Calendar button." data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="fcfc3ea2-8cc2-44d0-8c26-17ccea486baa" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_placed_block.png" alt="AddEvent module, an Add to Calendar button." title="AddEvent Module: Placed block" typeof="foaf:Image" /> </div> <figcaption>A basic Add to Calendar button will present options for adding to Google, Yahoo, Apple, Office 365, Outlook calendars and more.</figcaption> </figure> <p>That’s it! Click the button and choose a calendar type to add the event to your calendar — it’s that easy. Next we’ll look at dynamically adding buttons to a custom <i>Event</i> node page.</p> <h3>Add to Calendar: Dynamic event buttons</h3> <p>You can create dynamic event buttons by using the Token module with a custom <i>Event</i> content type. Any node type with a properly configured date field will work. Make sure the <a href="https://www.drupal.org/project/token">Token</a> module is installed before proceeding — use whatever <a href="https://www.drupal.org/docs/extending-drupal/installing-modules">Drupal module installation method</a> works best for you. For this example, we’ll create a super simple <i>Event</i> node type. In my example below, I’ve added two custom fields of the <i>Date</i> type: <i>field_event_date_start</i> and <i>field_event_date_end</i>.</p> <figure role="group" class="align-center"> <div alt="AddEvent module: Event content type" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="234afeaa-1ccd-4f96-9785-3e091987323c" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_event_ct.png" alt="AddEvent module: Event content type" title="AddEvent module: Event content type" typeof="foaf:Image" /> </div> <figcaption>A custom <em>Event</em> node type with date fields for start date and end date, for use with dynamically created Add to Calendar buttons.</figcaption> </figure> <p>Once your <i>Event</i> content type is set up, you just need to add a new Date format that will work well with the AddEvent module. To do that, navigate to <i>Configuration</i> &gt; <i>Date and time formats</i> (/admin/config/regional/date-time) and click the <i>Add format</i> button. You can see below that I’m calling my format <i>AddEvent</i> and using the format string <i>m/d/y g:i A</i> which will translate to something like 10/30/20 4:45 PM — exactly what we need for our <i>Add to Calendar</i> button.</p> <figure role="group" class="align-center"> <div alt="AddEvent module: date format" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="280c81f9-371b-45ea-bb30-8738811ae120" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_date_format.png" alt="AddEvent module: date format" title="AddEvent module: Date format" typeof="foaf:Image" /> </div> <figcaption>Define a custom AddEvent compatible date format to get your <em>Event</em> content type working with Add to Calendar buttons.</figcaption> </figure> <p>Now we’ll place a new <i>Add to Calendar</i> block just like in the previous section, only we’ll use tokens for the Event title, description, and the start and end dates. When you open the <i>Configure block</i> interface for your new <i>Add to Calendar</i> block, click the <i>Browse available tokens</i> link in the description area of the <i>Event Information</i> section. The tokens you’re looking for will be in the <i>Node</i> group. Notice that the token options for <i>field_event_date_start</i> and <i>field_event_date_end</i> indicate our custom AddEvent format — tokens will be available for all of your custom date formats. Check out my example below.</p> <figure role="group" class="align-center"> <div alt="AddEvent module: tokens" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="cb205452-018c-48c0-97dd-392b7f162840" data-langcode="en" title="AddEvent module: tokens" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_dynamic.png" alt="AddEvent module: tokens" title="AddEvent module: tokens" typeof="foaf:Image" /> </div> <figcaption>The Token module lets block configuration be dynamic, allowing your Add to Calendar buttons to pull data from <em>Event</em> pages.</figcaption> </figure> <p>Everything else will be the same as it was in the first example in the section above, with the exception of the <i>Visibility</i> settings. For this block, we’ll restrict visibility by <i>Content Type</i>, ensuring that the block only appears on our custom <i>Event</i> node type pages.</p> <figure role="group" class="align-center"> <div alt="AddEvent module: Block visibility" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="ff9eb16f-df35-4025-8c7a-67ec988d9a23" data-langcode="en" title="AddEvent module: Block visibility" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_dynamic_visibility.png" alt="AddEvent module: Block visibility" title="AddEvent module: Block visibility" typeof="foaf:Image" /> </div> <figcaption>Set block visibility to the <em>Event</em> content type to automatically create an Add to Calendar button on <em>Event</em> pages.</figcaption> </figure> <p>Once you’ve clicked <i>Save block</i> you’re all set. Now your <i>Add to Calendar</i> button will appear on every <i>Event</i> page in the region you specified, and it will inherit all of the event details from the specific event page.</p> <h3>Subscribe to an AddEvent calendar</h3> <p>Paid AddEvent accounts can manage multiple calendars of events on the AddEvent dashboard, and they have access to robust features like RSVP, custom fielded calendar events, subscriber reports, analytics, and more. While the <i>Hobby</i> account can demonstrate how <i>Subscribe to Calendar</i> works, the feature isn’t much use with the free-version restrictions in place.</p> <p>Setting up a <i>Subscribe to Calendar</i> button is super simple. Before setting up the block on your Drupal site, you’ll need the <i>Unique Key</i> for your AddEvent calendar. From your Dashboard on AddEvent.com, click the menu options icon next to your calendar of choice (<i>Hobby</i> accounts only have one calendar) and click <i>Calendar Page</i>. Now copy the <i>Unique Key</i> for use on the block configuration below</p> <figure role="group" class="align-center"> <div alt="AddEvent: Calendar Unique Key" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="e69cc6db-e33d-410f-8939-8834ce5f7f76" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_unique_key_0.png" alt="AddEvent: Calendar Unique Key" title="AddEvent: Calendar Unique Key" typeof="foaf:Image" /> </div> <figcaption>The Unique Key of your calendar used with the <em>Subscribe to Calendar</em> block type subscribes your users to entire AddEvent calendars.</figcaption> </figure> <p>On your Drupal site, navigate to <i>Structure</i> &gt; <i>Block layout</i> (/admin/structure/block) and click <i>Place block</i> in the region of your choice. Choose the <i>Subscribe to Calendar</i> block type, then paste your <i>Unique Key</i> from above in the <i>Data-ID</i> field. You may want to place your <i>Client ID</i> in the <i>License</i> field like in previous configurations, to remove the AddEvent branding from the interface.</p> <p>You can set up the Visibility settings however you wish, for my example I’ll stick with the /my-basic-page URL like before.</p> <figure role="group" class="align-center"> <div alt="AddEvent module: Subscribe to calendar" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="d70401ee-404b-4f1a-a288-b86ea802c356" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-10/addevent_aten_subscribe_cal.png" alt="AddEvent module: Subscribe to calendar" title="AddEvent module: Subscribe to calendar" typeof="foaf:Image" /> </div> <figcaption>Subscribe to Calendar buttons add all of the events in an AddEvent calendar to your users calendar, and updates them regularly.</figcaption> </figure> <p>You’re all done! Now your users can subscribe to the calendar(s) you maintain on your AddEvent account. As you add and edit events on your AddEvent calendars, your subscribers’ calendars will be automatically updated. Very cool!</p> <p><strong>NOTE:</strong> Different calendar services synchronize at different speeds and some are very slow. Google Calendars, for example, can take up to 24 hours to synchronize changes from calendar subscriptions.</p> <p>If you have suggestions, comments, or issues related to the AddEvent module, please let me know on the <a href="https://www.drupal.org/project/addevent">AddEvent module page</a>! And feel free to leave questions or general comments below.</p> <!-- google doc id: 1Pp0XyjrTAkFB2WnEg3yQaj68cUqizMDkDfmvdKIRq18 --></div> <a href="/about/travis-tomka" hreflang="en">Travis Tomka</a> Tue, 20 Oct 2020 22:28:20 +0000 Travis Tomka 10159 at https://atendesigngroup.com https://atendesigngroup.com/articles/add-calendar-buttons-addevent-drupal-8#comments BADCamp 2020 https://atendesigngroup.com/articles/badcamp-2020 <span>BADCamp 2020</span> <figure> <picture> <source srcset="/sites/default/files/2020-09/BADCamp_Aten_2020.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2020-09/BADCamp_Aten_2020.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2020-09/BADCamp_Aten_2020.jpg?itok=_m5eh5Vl 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-09/BADCamp_Aten_2020.jpg?itok=H4TzFbCG 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-09/BADCamp_Aten_2020.jpg?itok=H4TzFbCG 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-09/BADCamp_Aten_2020.jpg?itok=H4TzFbCG 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-09/BADCamp_Aten_2020.jpg?itok=ACEMWHdz 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-09/BADCamp_Aten_2020.jpg?itok=ACEMWHdz 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2020-09/BADCamp_Aten_2020.jpg" alt="" typeof="foaf:Image" /> </picture> </figure> <span><span lang="" about="/user/kenna-andreas" typeof="schema:Person" property="schema:name" datatype="">Mckenna Andreas</span></span> <span>Tue, 09/22/2020 - 12:00</span> <a href="/blog/category/events" class="tag" >Events</a> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p><a href="https://2020.badcamp.org/">Bay Area Drupal Camp</a> has gone — wait for it — 100% virtual! BADCamp is a community run celebration of open-source software with a keen focus on learning and inclusivity. Every year this event brings Drupal users, developers, marketers, and content specialists together from all over the country for high value talks, summits and trainings.</p> <p>While you’ll have to forego the trip to beautiful Berkeley, California this year, the good news is that registration is free and the 2020 session lineup is as packed as ever. Mark your calendar for this <b>October 14th - 17th</b>, and get ready to join Aten, the Bay Area Community, and your colleagues and peers from across the country in three major session tracks: Drupal for Beginners, Advanced Drupal, and Marketing &amp; Communications.</p> <p>Aten is excited to sponsor this year’s Higher Education Summit, and for our team to contribute a few sessions of their own, detailed below. <a href="https://2020.badcamp.org/registration">Register for BADCamp 2020 today!</a></p> <hr /> <h3>Friday, October 16th</h3> <h4>Managing People: The Art &amp; The Science, 1 PM PST</h4> <p>Project Managers are tasked with organizing client schedules, timelines, meetings, internal resources and much, much more. Every one of a PM’s tasks overlap in a central — and often complex — practice: <i>managing people</i>. Join Janice Camacho, Project Manager, as she explores the art of meeting each individual where they’re most comfortable, and the science of why they’re comfortable there. In this session you’ll learn how to get out of your own way and build the healthy, confident project teams that support strong, long-term client relationships.</p> <h4>True Life: I’m an introvert in an extrovert’s world, 2 PM PST</h4> <p>Do you shy away from speaking up in a crowded room? Do you prefer to maintain a carefully guarded bubble of personal space? Does the prospect of addressing an audience make you perspire and/or shake? Introverts exist in the world of Digital Project Management, too. Gasp! And — perhaps contrary to intuition — they bring a unique set of strengths and abilities to the table, much like their extraverted counterparts. Join Kacie Miner, Digital Project Manager, as she shares her experience of being an introvert in the DPM space. In this session you’ll learn:</p> <ul> <li>Strengths, abilities, and positive attributes that introverts bring to the table</li> <li>Ways to adapt your personality to the job at hand without changing who you are</li> <li>Strategies that will set you up for success instead of causing you to overthink</li> <li>Tips and tools to know where you lie on the extrovert scale, and knowing how to recover</li> <li>How to develop your own toolkit for being fully prepared when put on the spot<b> </b></li> </ul> <h4>Layout Building in Drupal, 3 PM PST</h4> <p>The Layout Discovery API has dramatically changed the way Drupal 8 websites are designed, built and maintained. Solutions like Layout Builder, Entity Reference with Layout, and Layout Paragraphs have added a new dimension of content presentation on top of traditional content management. With these tools content editors have more control over their online presence than ever before — but this newfound flexibility isn’t without its own challenges. Join James Nettik, Front-end Developer, as he covers the essentials of layout building in Drupal 8. This session will cover:</p> <ul> <li>An overview of the tools available today and their pros and cons</li> <li>How to begin working with the new Layout Discovery API</li> <li>Tips to keep the authoring experience as intuitive as possible</li> <li>Solutions to common questions and pitfalls while designing and building<b> </b></li> </ul> <hr /> <p>Don’t miss your opportunity to learn the latest in Drupal, network with fellow professionals, and attend in-depth technical and management training. <a href="https://2020.badcamp.org/registration">Register for BADCamp 2020 today.</a> We’ll see you there!</p> <!-- google doc id: 1GZA0Ue8XnNSCprdhwWwNBCj3VZWeWUhoHD6FJer-1us --></div> Tue, 22 Sep 2020 18:00:00 +0000 Mckenna Andreas 10147 at https://atendesigngroup.com https://atendesigngroup.com/articles/badcamp-2020#comments Add SVG icons in Drupal menus https://atendesigngroup.com/articles/add-svg-icons-drupal-menus <span>Add SVG icons in Drupal menus</span> <figure> <picture> <source srcset="/sites/default/files/2020-08/drupal_svg_icons_menus.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2020-08/drupal_svg_icons_menus.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2020-08/drupal_svg_icons_menus.jpg?itok=1YHrMCwh 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupal_svg_icons_menus.jpg?itok=piBPnEcZ 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupal_svg_icons_menus.jpg?itok=piBPnEcZ 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupal_svg_icons_menus.jpg?itok=piBPnEcZ 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-08/drupal_svg_icons_menus.jpg?itok=3a3hIYGG 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-08/drupal_svg_icons_menus.jpg?itok=3a3hIYGG 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2020-08/drupal_svg_icons_menus.jpg" alt="" typeof="foaf:Image" /> </picture> </figure> <span><a title="View user profile." href="/user/james-nettik" lang="" about="/user/james-nettik" typeof="schema:Person" property="schema:name" datatype="">jnettik</a></span> <span>Wed, 08/26/2020 - 07:57</span> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <a href="/articles/drupal-planet" class="tag" >Drupal Planet</a> <a href="/blog/category/development" class="tag" >Code</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>Adding SVG icons or button styles into Drupal menus can be difficult — especially if you’re trying to avoid hardcoded, fragile solutions. With the <a href="https://www.drupal.org/project/menu_link_attributes">Menu Link Attributes</a> module you can easily add custom HTML5 data attributes to individual menu links, then use a preprocessor to inject your SVG icons and button styles based on those attributes. This solution takes just a couple of minutes and should work on Drupal 8 / Drupal 9 installations.</p> <h3>Menu Link Attributes</h3> <p>Add the <a href="https://www.drupal.org/project/menu_link_attributes">Menu Link Attributes</a> module to your project via <i>composer require drupal/menu_link_attributes</i>, then enable the module with <i>drush en menu_link_attributes</i> or through the GUI on the <i>Extend</i> page. Once the module is enabled navigate to <i>Structure</i> &gt; <i>Menus</i> and click the <i>Available attributes</i> tab. Here you’ll add YAML configuration that will describe which attribute options you’d like added to individual menu links.</p> <figure role="group" class="align-center"> <div alt="Menu link attributes config" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="02a2ab45-f85f-4787-93bf-e8bb23d0f3bc" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/svg_icons_drupal_menus_config.png" alt="Menu link attributes config" title="SVG menu icons: Config" typeof="foaf:Image" /> </div> <figcaption>The menu link attributes configurations can be found at <em>Structure</em> &gt; <em>Menus</em> &gt; <em>Available attributes</em> (tab).</figcaption> </figure> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">attributes<span style="color: #339933;">:</span> data<span style="color: #339933;">-</span>icon<span style="color: #339933;">:</span> label<span style="color: #339933;">:</span> Icon description<span style="color: #339933;">:</span> <span style="color: #0000ff;">'Replace the text of the menu link with an icon.'</span> options<span style="color: #339933;">:</span> facebook<span style="color: #339933;">:</span> Facebook instagram<span style="color: #339933;">:</span> Instagram twitter<span style="color: #339933;">:</span> Twitter</pre></div></pre> <p>Paste the above YAML into the configuration textarea and click <i>Save</i> to create a new <i>Icon</i> option for menu links using the custom <i>data-icon</i> attribute. With this option you can add attributes to your link like <em>data-icon=”facebook”</em> — or whatever you define in your config YAML. In our example we’ve defined <i>facebook</i>, <i>instagram</i> and <i>twitter</i>.</p> <figure role="group" class="align-center"> <div alt="Menu link attributes settings" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="07cc0e77-d7fe-40b2-b41a-caeb071bf6ae" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/svg_icons_drupal_menus_attributes.png" alt="Menu link attributes settings" title="SVG menu icons: Attributes" typeof="foaf:Image" /> </div> <figcaption>Menu link <em>Attributes</em> settings are now available on the edit screen for individual menu links using the configurations set above.</figcaption> </figure> <p>Next you’ll want to assign these data attributes to your Drupal menu items using the GUI. For this example I’ve created three new menu items in the Main navigation (machine name <em>main</em>) menu: Facebook, Instagram, and Twitter.</p> <figure role="group" class="align-center"> <div alt="Sandbox theme homepage" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="c0d05600-f342-467f-ada5-8da67ab16535" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/svg_icons_drupal_menus_home.png" alt="Sandbox theme homepage" title="SVG menu icons: Home" typeof="foaf:Image" /> </div> <figcaption>A custom <em>Sandbox</em> theme, using Bartik as a base theme, on a fresh Drupal 8.2 install.</figcaption> </figure> <h3>Create an SVG Sprite</h3> <p>This solution assumes you’re using a sprite of SVG icons and have included them somewhere in your templates. There are many ways to do this in Drupal, and covering them here would be outside the scope of this post. For simplicity, I’ve added the following sprite at the bottom of my <i>page.html.twig</i> file — you can follow suit to get this example working in your project. Notice that the value of the <i>data-icon</i> attribute in the menu links match the IDs of the <i>symbol</i> elements in the sprite.</p> <pre><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">&lt;div style="display:none"&gt; <span style="color: #000000; font-weight: bold;">&lt;?</span>xml version<span style="color: #339933;">=</span><span style="color: #0000ff;">"1.0"</span> encoding<span style="color: #339933;">=</span><span style="color: #0000ff;">"UTF-8"</span><span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg"&gt;&lt;symbol id="facebook" viewBox="0 0 24 24"&gt;&lt;path d="M17.844 1.161v3.536h-2.103c-1.647 0-1.955.79-1.955 1.929v2.531h3.924l-.522 3.964h-3.402v10.165H9.688V13.121H6.273V9.157h3.415v-2.92C9.688 2.849 11.764 1 14.791 1c1.446 0 2.692.107 3.054.161h-.001z"/&gt;&lt;/symbol&gt;&lt;symbol id="instagram" viewBox="0 0 24 24"&gt;&lt;path d="M20.922 0A3.094 3.094 0 0 1 24 3.078v17.844A3.094 3.094 0 0 1 20.922 24H3.078A3.094 3.094 0 0 1 0 20.922V3.078A3.094 3.094 0 0 1 3.078 0h17.844zM4.875 10.156H2.672v10.125c0 .532.422.953.953.953h16.703a.947.947 0 0 0 .953-.953V10.156h-2.11c.204.64.313 1.344.313 2.047 0 4-3.343 7.235-7.468 7.235-4.11 0-7.454-3.235-7.454-7.235 0-.703.11-1.406.313-2.047zm7.14-2.875c-2.656 0-4.812 2.094-4.812 4.672s2.156 4.672 4.813 4.672c2.671 0 4.828-2.094 4.828-4.672s-2.157-4.672-4.828-4.672zm8.188-4.61h-2.719a1.08 1.08 0 0 0-1.078 1.079v2.578a1.08 1.08 0 0 0 1.078 1.078h2.72a1.08 1.08 0 0 0 1.077-1.078V3.75a1.08 1.08 0 0 0-1.078-1.078z"/&gt;&lt;/symbol&gt;&lt;symbol id="twitter" viewBox="0 0 24 24"&gt;&lt;path d="M22.696 5.464a9.294 9.294 0 0 1-2.17 2.237c. 0 5.719-4.353 12.308-12.308 12.308-2.451 0-4.728-.71-6.643-1.942.348.04.683.054 1.045.054a8.667 8.667 0 0 0 5.371-1.848 4.334 4.334 0 0 1-4.045-3c.268.04.536.067.817.067.388 0 .777-.054 1.138-.147a4.327 4.327 0 0 1-3.469-4.246v-.054a4.367 4.367 0 0 0 1.955.549 4.325 4.325 0 0 1-1.929-3.603c0-.804.214-1.54.589-2.183a12.297 12.297 0 0 0 8.92 4.527 4.875 4.875 0 0 1-.107-.991 4.324 4.324 0 0 1 4.326-4.326c1.246 0 2.371.522 3.161 1.366a8.523 8.523 0 0 0 2.746-1.045 4.313 4.313 0 0 1-1.902 2.384 8.673 8.673 0 0 0 2.491-.67l.001.001z"/&gt;&lt;/symbol&gt;&lt;/svg&gt; &lt;/div&gt;</pre></div></pre> <figure role="group" class="align-center"> <div alt="SVG markup in page.html.twig" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="9fd39774-f381-4e4f-a11a-65d49b3fe24a" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/svg_icons_drupal_menus_page.png" alt="SVG markup in page.html.twig" title="SVG menu icons: Page.html.twig" typeof="foaf:Image" /> </div> <figcaption>In my custom <em>Sandbox</em> theme, I've copied <em>page.html.twig</em> from the base theme and pasted the SVG code from above as the last line.</figcaption> </figure> <h3>Inject your SVG markup with a preprocessor</h3> <p>In your <em>mytheme.theme</em> file (or <em>sandbox.theme</em> in my case), define the following hook to inject SVG markup in any menu item that has a <i>data-icon</i> attribute. As mentioned above, you’ll need to paste the SVG markup provided at the bottom of your <em>page.html.twig</em> file in order to see any icons actually populate.</p> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/** * @file * Functions to support theming in the Sandbox theme. */</span> <span style="color: #000000; font-weight: bold;">use</span> Drupal\Component\Render\FormattableMarkup<span style="color: #339933;">;</span>   <span style="color: #009933; font-style: italic;">/** * Implements theme_preprocess_menu(). */</span> <span style="color: #000000; font-weight: bold;">function</span> sandbox_preprocess_menu<span style="color: #009900;">(</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$variables</span><span style="color: #339933;">,</span> <span style="color: #000088;">$hook</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">(</span><span style="color: #000088;">$variables</span><span style="color: #009900;">[</span><span style="color: #0000ff;">'items'</span><span style="color: #009900;">]</span> <span style="color: #b1b100;">as</span> <span style="color: #339933;">&amp;</span><span style="color: #000088;">$item</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> <span style="color: #000088;">$attributes</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$item</span><span style="color: #009900;">[</span><span style="color: #0000ff;">'url'</span><span style="color: #009900;">]</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">(</span><span style="color: #0000ff;">'attributes'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">(</span><span style="color: #000088;">$attributes</span><span style="color: #009900;">[</span><span style="color: #0000ff;">'data-icon'</span><span style="color: #009900;">]</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> <span style="color: #000088;">$title</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FormattableMarkup<span style="color: #009900;">(</span><span style="color: #0000ff;">' &lt;span class="visually-hidden"&gt;@title&lt;/span&gt; &lt;svg class="icon icon--@icon" viewbox="0 0 24 24"&gt; &lt;use xlink:href="#@icon"&gt;&lt;/use&gt; &lt;/svg&gt; '</span><span style="color: #339933;">,</span> <span style="color: #009900;">[</span> <span style="color: #0000ff;">'@title'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$item</span><span style="color: #009900;">[</span><span style="color: #0000ff;">'title'</span><span style="color: #009900;">]</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'@icon'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$attributes</span><span style="color: #009900;">[</span><span style="color: #0000ff;">'data-icon'</span><span style="color: #009900;">]</span><span style="color: #339933;">,</span> <span style="color: #009900;">]</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #000088;">$item</span><span style="color: #009900;">[</span><span style="color: #0000ff;">'title'</span><span style="color: #009900;">]</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$title</span><span style="color: #339933;">;</span> <span style="color: #009900;">}</span> <span style="color: #009900;">}</span> <span style="color: #009900;">}</span></pre></div></pre> <p>In this example using Sandbox, my custom sub-theme of Bartik, I added an <em>svg { max-width: 25px; }</em> CSS declaration to my theme's base styles so my menu icons aren’t the size of the whole viewport.</p> <figure role="group" class="align-center"> <div alt="Example homepage with SVG icons in Drupal menu links." data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="086bfefe-fad2-4ea2-a2c7-0232e55de4ae" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/svg_icons_drupal_menu_complete.png" alt="Example homepage with SVG icons in Drupal menu links." title="SVG menu icons: Complete" typeof="foaf:Image" /> </div> <figcaption>SVG Icons in their proper place as Drupal menu items! I added a line of CSS (above) in my Sandbox theme to set the icon sizes.</figcaption> </figure> <p>Voila! Now you’ve got SVG icons in your Drupal menu links, and you can easily alter the <i>data-icon</i> link attributes with a point-and-click interface. Check back soon for a separate post on creating SVG sprites for your Drupal templates.</p></div> <a href="/about/james-nettik" hreflang="en">James Nettik</a> Wed, 26 Aug 2020 13:57:33 +0000 jnettik 10140 at https://atendesigngroup.com https://atendesigngroup.com/articles/add-svg-icons-drupal-menus#comments Drupal 8 content migrations from CSV or spreadsheet https://atendesigngroup.com/articles/drupal-8-content-migrations-csv-spreadsheet <span>Drupal 8 content migrations from CSV or spreadsheet</span> <figure> <picture> <source srcset="/sites/default/files/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg?itok=IVc6tWU1 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg?itok=v__Davu2 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg?itok=v__Davu2 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg?itok=v__Davu2 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg?itok=QGvlcAmd 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg?itok=QGvlcAmd 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2020-08/drupal_8_data_migration_csv_spreadsheet.jpg" alt="Decorative image" typeof="foaf:Image" /> </picture> </figure> <span><a title="View user profile." href="/user/joel-steidl" lang="" about="/user/joel-steidl" typeof="schema:Person" property="schema:name" datatype="">Joel Steidl</a></span> <span>Mon, 08/17/2020 - 06:32</span> <a href="/blog/category/drupal-8" class="tag" >Drupal 8</a> <a href="/articles/drupal-planet" class="tag" >Drupal Planet</a> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <a href="/blog/category/development" class="tag" >Code</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>Content migration into a Drupal website using spreadsheet or CSV data can be surprisingly effective — especially (counterintuitively?) with large and complex datasets. I’ve written about <a href="https://atendesigngroup.com/articles/getting-started-drupal-8-migrations">data migration in Drupal 8</a> a <a href="https://atendesigngroup.com/articles/drupal-8-migration-multiple-paragraph-references">couple of times</a>, but new projects keep highlighting the diversity of data sources and content configurations, reminding me over and over again that data migration doesn’t really have a one-size-fits-all solution. In this post we’ll get you from zero (fresh Drupal 8 install) to a basic CSV data migration — including entity references and multiple field values — in about 15 or 20 minutes. You can <a href="https://github.com/AtenDesignGroup/aten_csv_migrate">download the accompanying Aten CSV Migrate example</a> module here, and <a href="#instructions">skip straight to the instructions</a> if you'd like.</p> <p>Drupal 8 offers a handful of powerful and extensible migration modules in core. These modules lay the foundation for a wide variety of migration methods including several flavors of CSV importers like the point-and-click <a href="/articles/entity-import-user-interface-drupal-8-migrations">Entity Importer module for Drupal 8</a> developed by my colleague Travis Tomka. GUI powered migrations are perfect for minimally to moderately complex content, but can have a hard time crossing the finish line alone for complicated datasets.</p> <h3>When GUIs overwhelm: CSV or Spreadsheet content migrations</h3> <p>Earlier this year I began working with the <a href="https://preview.neonscience.org/">National Science Foundation’s National Ecological Observatory Network</a> (NEON) to migrate robust ecological data collected from more than eighty terrestrial and aquatic field sites across the United States into a Drupal 8 website. The bulk of the data was destined for a content type with more than 75 unique fields, and the sheer volume and complexity of the data was steering me away from point-and-click interfaces.</p> <p>Luckily for me, the NEON team are old hands when it comes to spreadsheet manipulation. Their expertise and flexibility were applied to formatting a spreadsheet export of their data specifically configured for an import into Drupal. Then their spreadsheets were exported to CSV, a format simple to consume into a Drupal website with the right modules and configurations. With just a little back and forth, we were well on our way to a successful, complex data migration with minimal custom code.</p> <h3 id="instructions">The basics: Getting spreadsheet or CSV data in Drupal</h3> <p>A quick introduction to configuring a CSV import using the <a href="https://www.drupal.org/project/migrate_source_csv">Migrate Source CSV module for Drupal 8</a> is warranted. Once the basics are clear, a more complex import won’t be so overwhelming. If your data is in spreadsheet format, you’ll want to export it to CSV. The example below assumes a comma delimiter, no encapsulation characters, and no escape characters. For more complex content you’ll define these attributes in the <i>source</i> portion of your migration yaml file. The following steps culminate in a <a href="https://github.com/AtenDesignGroup/aten_csv_migrate">working example CSV data migration module</a> you can download and tinker with. Note that this first example doesn’t discuss the more complex sample below, which is also included in the download.</p> <ol> <li>Ensure that the core Migrate module is enabled</li> <li>Install and enable <a href="https://www.drupal.org/project/migrate_source_csv">Migrate Source CSV</a>, <a href="https://www.drupal.org/project/migrate_tools">Migrate Tools</a>, and <a href="https://www.drupal.org/project/migrate_plus">Migrate Plus</a></li> <li>Create a new custom module (or just <a href="https://github.com/AtenDesignGroup/aten_csv_migrate">download my working example</a>) which will include an info file, a migrate file, a source file, and an install file following the outline below</li> </ol> <p>modules/custom/aten_csv_migrate/aten_csv_migrate.info.yml</p> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">type<span style="color: #339933;">:</span> module name<span style="color: #339933;">:</span> Aten CSV Migration description<span style="color: #339933;">:</span> <span style="color: #0000ff;">'Aten CSV Migration example. Read more from &lt;a href="https://atendesigngroup.com/articles/drupal-8-content-migrations-csv-spreadsheet"&gt;this data migration from CSV or spreadsheet tutorial.&lt;/a&gt;'</span> package<span style="color: #339933;">:</span> Migration core_version_requirement<span style="color: #339933;">:</span> ^8<span style="color: #339933;">.</span>7<span style="color: #339933;">.</span>7 <span style="color: #339933;">||</span> ^<span style="color: #cc66cc;">9</span> dependencies<span style="color: #339933;">:</span> <span style="color: #339933;">-</span> drupal<span style="color: #339933;">:</span>migrate <span style="color: #339933;">-</span> migrate_source_csv <span style="color: #339933;">-</span> migrate_plus</pre></div></pre> <p>Here we simply define the module and its dependencies.</p> <p>modules/custom/aten_csv_migrate/aten_csv_migrate.install</p> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/** * Implements hook_uninstall() */</span> <span style="color: #000000; font-weight: bold;">function</span> aten_csv_migrate_uninstall<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> Drupal<span style="color: #339933;">::</span><span style="color: #004000;">configFactory</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getEditable</span><span style="color: #009900;">(</span><span style="color: #0000ff;">'migrate_plus.migration.aten_csv_migrate_node'</span><span style="color: #009900;">)</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> Drupal<span style="color: #339933;">::</span><span style="color: #004000;">configFactory</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getEditable</span><span style="color: #009900;">(</span><span style="color: #0000ff;">'migrate_plus.migration.aten_complex_csv_example'</span><span style="color: #009900;">)</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #009900;">}</span></pre></div></pre> <p>This implementation of hook_uninstall() will clean up active configuration for the example CSV data migration when the module is uninstalled.</p> <p>modules/custom/aten_csv_migrate/config/install/migrate_plus.migration.aten_csv_migrate_node.yml</p> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">id<span style="color: #339933;">:</span> aten_csv_migrate_node label<span style="color: #339933;">:</span> Aten CSV Migrate example node migration_tags<span style="color: #339933;">:</span> <span style="color: #339933;">-</span> Aten Migrate CSV source<span style="color: #339933;">:</span> plugin<span style="color: #339933;">:</span> csv path<span style="color: #339933;">:</span> modules<span style="color: #339933;">/</span>custom<span style="color: #339933;">/</span>aten_csv_migrate<span style="color: #339933;">/</span>sources<span style="color: #339933;">/</span>aten_csv_migrate_items<span style="color: #339933;">.</span>csv ids<span style="color: #339933;">:</span> <span style="color: #009900;">[</span>ID<span style="color: #009900;">]</span> process<span style="color: #339933;">:</span> title<span style="color: #339933;">:</span> Title body<span style="color: #339933;">:</span> Description field_color<span style="color: #339933;">:</span> Color field_weight<span style="color: #339933;">:</span> Weight type<span style="color: #339933;">:</span> plugin<span style="color: #339933;">:</span> default_value default_value<span style="color: #339933;">:</span> item destination<span style="color: #339933;">:</span> plugin<span style="color: #339933;">:</span> entity<span style="color: #339933;">:</span>node</pre></div></pre> <p>This is the cornerstone of the migration. Using the <i>migrate_plus.migration.my_module.yml</i> namespace lets us hook into the power of the Migrate Plus module. You can see we define our CSV file in <i>path </i>and then map our fields to columns in the CSV file under <i>process</i> including the node type <i>item</i> which we’ll need to create.</p> <p>modules/custom/aten_csv_migrate/sources/aten_csv_migrate_items.csv</p> <pre> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">ID<span style="color: #339933;">,</span>Title<span style="color: #339933;">,</span>Description<span style="color: #339933;">,</span>Color<span style="color: #339933;">,</span>Weight <span style="color: #cc66cc;">100</span><span style="color: #339933;">,</span>Ball<span style="color: #339933;">,</span>A top quality exercise ball<span style="color: #339933;">.,</span>Red<span style="color: #339933;">,</span><span style="color: #cc66cc;">4</span> <span style="color: #cc66cc;">101</span><span style="color: #339933;">,</span>Flag<span style="color: #339933;">,</span>The perfect flag <span style="color: #b1b100;">for</span> your collection<span style="color: #339933;">.,</span>Blue<span style="color: #339933;">,</span><span style="color: #cc66cc;">1</span> <span style="color: #cc66cc;">102</span><span style="color: #339933;">,</span>Paperweight<span style="color: #339933;">,</span>A weight <span style="color: #b1b100;">for</span> your important papers<span style="color: #339933;">,</span>Black<span style="color: #339933;">,</span><span style="color: #cc66cc;">2</span> <span style="color: #cc66cc;">103</span><span style="color: #339933;">,</span>Thermos<span style="color: #339933;">,</span>Liquids stay warm with this amazing product<span style="color: #339933;">.,</span>White<span style="color: #339933;">,</span><span style="color: #cc66cc;">2</span></pre></div></pre> <p>Some items that we’ll stuff into nodes!</p> <p>Now that your code is in place, make sure that you have a content type configured to receive the content import. For this example I’m sticking with core field types and a custom node type <i>item</i> that matches my CSV data. Note that the field machine names match those in the <i>process</i> definitions of my <i>migrate_plus.migration.aten_csv_migrate_node.yml</i> file.</p> <figure role="group" class="align-center"> <div alt="Content type Item" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="340e62ef-e44b-436d-987f-809c53d0ad5d" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/drupal_csv_import_content_overview.png" alt="Content type Item" title="D8 CSV Migration item content type" typeof="foaf:Image" /> </div> <figcaption>The content type "Item" contains simple core fields and will receive the CSV data.</figcaption> </figure> <p>And here are the field configurations.</p> <figure role="group" class="align-center"> <div alt="Content type Item field definitions." data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="f8a1a6b3-2568-43d0-8c7e-d99223b6f704" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/drupal_csv_import_content_fields.png" alt="Content type Item field definitions." title="D8 CSV Migration item fields" typeof="foaf:Image" /> </div> <figcaption>The "Item" content type contains the core body field, a field_color (short text) field, and a field_weight (integer) field.</figcaption> </figure> <p>Now you’re set to run your import using drush. You’ll want to clear the drupal and drush caches before attempting your import via <em>drush cr</em> and <em>drush cc drush</em> - at which point you’ll see the migrate commands are available to drush via <em>drush list</em>.</p> <p>Now we run the migration using <em>drush migrate:import aten_csv_migrate_node</em>, and we should see a success message.</p> <figure role="group" class="align-center"> <div alt="Command line drush commands" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="53cfc01b-f5e2-47bb-8f1d-320b6e6c9c0b" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/drush_csv_import_success.png" alt="Command line drush commands" title="D8 CSV Migration drush commands" typeof="foaf:Image" /> </div> <figcaption>With the module properly installed drush cr, drush cc drush, and drush migrate:import aten_csv_migrate_node should complete the example migration.</figcaption> </figure> <p>That’s it for the basic CSV data migration! You’ll now see the items defined in your CSV have populated as nodes, with all the field data mapped to the appropriate fields.</p> <figure role="group" class="align-center"> <div alt="Four nodes of the content type Item successfully imported" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="d84c1994-1634-4894-94c7-02ec33409b09" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/drupal_csv_import_items.png" alt="Four nodes of the content type Item successfully imported" title="D8 CSV Migration result content" typeof="foaf:Image" /> </div> <figcaption>The CSV content has been imported into "Item" nodes.</figcaption> </figure> <p>And if we check inside, we'll see our individual fields migrated as we'd hoped.</p> <figure role="group" class="align-center"> <div alt="CSV data imported into the fields previously defined." data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="c2160ab6-6089-4001-a454-9042d1ed2d5f" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/drupal_csv_import_item_fields.png" alt="CSV data imported into the fields previously defined." title="D8 CSV Migration result content fields" typeof="foaf:Image" /> </div> <figcaption>Our title, description, color, and weight columns have imported. Note that the ID column is simply a unique identifier, and is not imported into a node attribute.</figcaption> </figure> <p>Now that we’ve got the basics down, we can move on to exploring some real-world complexities. Here’s where manipulating the format of the data in the CSV file becomes particularly handy.</p> <h3>A deeper dive: Getting spreadsheet or CSV data in Drupal</h3> <p>Migrating CSV data into a Drupal website is perhaps the most cost effective when A) The source data is inherently complex, and B) It can be easily manipulated, reformatted and re-exported to facilitate an easier migration. In the case of NEON’s content the volume and uniqueness of data fields, their relational aspects (think tags or entity references), and their inherent complexity (like multiple values for the same field) made it a good candidate on the first account. The client team’s capacity to fiddle with formats and re-export their data to spreadsheets made it a good candidate on the second.</p> <p>For more complex field types we rely on Migrate Plus plugins which will be used to populate the data. For the complex example included in the download to run successfully, you’ll need to configure a new content type <i>complex_item</i> with the appropriate fields. My example uses the <a href="https://www.drupal.org/project/geofield">Geofield</a> and <a href="https://www.drupal.org/project/address">Address</a> modules which allows the setup of the <i>field_coordinates</i> and <i>field_address</i> fields respectively. The rest of the fields are core.</p> <figure role="group" class="align-center"> <div alt="Complex item content type field configuration" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="42d2f25c-6758-4ada-8567-3847e37ac991" data-langcode="en" class="embedded-entity"> <img src="/sites/default/files/2020-08/complex_item_field_config.png" alt="Complex item content type field configuration" title="D8 CSV Migration complex item config" typeof="foaf:Image" /> </div> <figcaption>The complex_item content type configuration implements core, Address and Geofield fields: field_address (address), body, field_coordinates (geofield), field_link (link), field_multiple_taxonomy_term (entity reference: term), field_single_entity_reference (entity reference: node), field_single_taxonomy_term (entity reference: term).</figcaption> </figure> <p>It’s fields like <i>field_multiple_taxonomy_term</i> that really shine with CSV or spreadsheet imports, in that having the client separate multiple values with a “|” in their export and then implementing the explode plugin quickly solves what could otherwise be a complex problem.</p> <figure role="group" class="align-center"> <div alt="YAML configuration for import into field_multiple_taxonomy_term" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="e845f7bf-2a2c-42e3-8fd0-1744fed4c3df" data-langcode="en" title="D8 CSV Migration multi-term config" class="embedded-entity"> <img src="/sites/default/files/2020-08/complex_item_multiple_term.png" alt="YAML configuration for import into field_multiple_taxonomy_term" title="D8 CSV Migration multi-term config" typeof="foaf:Image" /> </div> <figcaption>Code highlight is from <em>migrate_plus.migration.aten_complex_csv_example.yml</em>. All mentioned code is included in the <a href="https://github.com/AtenDesignGroup/aten_csv_migrate">Aten CSV Migrate download</a> included with this post.</figcaption> </figure> <p>Another thing to notice in <i>migrate_plus.migration.aten_complex_csv_example.yml</i> is the difference between the <i>entity_lookup</i> plugin and the <i>entity_generate</i> plugin. The <i>entity_generate</i> plugin will search by title for a matching entity, and create one if it doesn’t exist. The <i>entity_lookup</i> plugin, on the other hand, skips the field if an appropriate existing entity isn’t found.</p> <figure role="group" class="align-center"> <div alt="YAML configuration for import entity_lookup vs entity_generate" data-embed-button="media_browser" data-entity-embed-display="media_image" data-entity-type="media" data-entity-uuid="0531d9f9-1027-48c1-bf9e-a04256a8c7bb" data-langcode="en" title="D8 CSV Migration entity lookup vs generate" class="embedded-entity"> <img src="/sites/default/files/2020-08/complex_item_generate_lookup.png" alt="YAML configuration for import entity_lookup vs entity_generate" title="D8 CSV Migration entity lookup vs generate" typeof="foaf:Image" /> </div> <figcaption>Code highlight is from <em>migrate_plus.migration.aten_complex_csv_example.yml</em>. All mentioned code is included in the <a href="https://github.com/AtenDesignGroup/aten_csv_migrate">Aten CSV Migrate download</a> included with this post.</figcaption> </figure> <p>The Migrate Plus module ships with an impressive collection of plugins and example code. Once you’ve gotten your feet wet, it’s likely you can find everything you need for complex data migrations from CSV within the various Migrate Plus example submodules.</p> <p>There are as many ways to migrate data into Drupal as there are unique combinations of source data, client teams, and project requirements. Knowing more about the methods available to you is a great way to broaden your options and choose the right tools for each unique job. What are your go-to migration methods or tricks of the trade? I’d love to hear about them in the comments below.</p></div> <a href="/about/joel-steidl" hreflang="en">Joel Steidl</a> Mon, 17 Aug 2020 12:32:35 +0000 Joel Steidl 10139 at https://atendesigngroup.com https://atendesigngroup.com/articles/drupal-8-content-migrations-csv-spreadsheet#comments Drupal Camp Colorado 2020 https://atendesigngroup.com/articles/drupal-camp-colorado-2020 <span>Drupal Camp Colorado 2020</span> <figure> <picture> <source srcset="/sites/default/files/2020-08/drupalcamp_co_2020_aten.jpg 1x" media="(min-width: 1860px)" type="image/jpeg"/> <source srcset="/sites/default/files/2020-08/drupalcamp_co_2020_aten.jpg 1x" media="(min-width: 1540px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_large/public/2020-08/drupalcamp_co_2020_aten.jpg?itok=vqvcf7D3 1x" media="(min-width: 1265px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupalcamp_co_2020_aten.jpg?itok=RfYH-egW 1x" media="(min-width: 1024px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupalcamp_co_2020_aten.jpg?itok=RfYH-egW 1x" media="(min-width: 768px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_medium/public/2020-08/drupalcamp_co_2020_aten.jpg?itok=RfYH-egW 1x" media="(min-width: 600px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-08/drupalcamp_co_2020_aten.jpg?itok=wyi1ma78 1x" media="(min-width: 500px)" type="image/jpeg"/> <source srcset="/sites/default/files/styles/responsive_small/public/2020-08/drupalcamp_co_2020_aten.jpg?itok=wyi1ma78 1x" media="(min-width: 0)" type="image/jpeg"/> <img src="/sites/default/files/2020-08/drupalcamp_co_2020_aten.jpg" alt="" typeof="foaf:Image" /> </picture> </figure> <span><span lang="" about="/user/kenna-andreas" typeof="schema:Person" property="schema:name" datatype="">Mckenna Andreas</span></span> <span>Fri, 08/07/2020 - 09:05</span> <a href="/blog/category/events" class="tag" >Events</a> <a href="/blog/category/drupal-0" class="tag" >Drupal</a> <div class="field field--name-body field--type-text-with-summary field--label-hidden t--body field__item"><p>Get ready for the first ever fully virtual <a href="https://2020.drupalcampcolorado.org/">DrupalCamp Colorado</a>, this August 14-16, 2020. This year’s DCCO is packed with <a href="https://2020.drupalcampcolorado.org/schedule">more than two dozen sessions</a> covering a wide array of topics from content strategy to accessibility, data migrations, analytics, and much, much more. The event will be broadcast via <a href="https://zoom.us/">Zoom</a> &amp; <a href="https://hopin.to/">Hopin</a>, offering plenty of opportunity to connect, network, learn &amp; share from the comfort of your own home. If you haven’t already, make sure to <a href="https://2020.drupalcampcolorado.org/register">register for this free event</a>. We’re super excited for the 2020 lineup and hope to see you there — perhaps in one of the Aten team’s sessions listed below!</p> <h3>Friday August 14th, 2020</h3> <h4>Nonprofit &amp; Government Summit, 8:30 AM</h4> <p>Accessibility on the web is important to everyone, but the pressure to meet accessibility standards is perhaps most keenly felt by publicly funded or government organizations. Michaela, Front-End Developer and accessibility expert, will be presenting an introduction to accessibility for the Nonprofit &amp; Government Summit that covers fundamentals, performing audits, and a few tricks of the trade.</p> <h3>Saturday August 15th, 2020</h3> <h4>Successful Projects Start With Great RFPS, 10:15 AM</h4> <p>A user-centered approach should take the front seat when it comes to website design and development, but what about developing RFPs for your upcoming digital project? Join Joe Crespo, Director of Accounts at Aten Design Group, as he covers how to write an RFP that communicates clearly with the users at the center of proposal writing and evaluation — your potential vendors. Learn how great RFPs lead to better proposals and more successful projects.</p> <h4>Social Media and Accessibility, 11:15 AM</h4> <p>Social media allows you to establish meaningful, productive dialogue with your end users, potential clients, content consumers or other target audiences. Can your social media speak louder, to a wider audience, and with a bigger focus on inclusion? Join Michaela, Front-End Developer and accessibility expert, as she walks through creating accessible content for major social media platforms — and why it’s important to your organization.</p> <hr /> <p>Don’t miss your opportunity to connect with the Aten team, the Drupal community, and the wider sphere of your colleagues in the digital services industry — <a href="https://2020.drupalcampcolorado.org/register">register for DrupalCamp Colorado 2020</a> today!</p> <!-- google doc id: 1lgSo-UTflVI7gNx529CpK4OTtnAfD8vOA7uOT2ChLG4 --></div> Fri, 07 Aug 2020 15:05:16 +0000 Mckenna Andreas 10134 at https://atendesigngroup.com https://atendesigngroup.com/articles/drupal-camp-colorado-2020#comments