Development News

Lullabot: Styling the WYSIWYG Editor in Drupal 8

Main Drupal Feed - Wed, 11/08/2017 - 16:42

Drupal 8 ships with a built-in WYSIWG editor called CKEditor. It’s great to have it included in core, but I had some questions about how to control the styling. In particular, I wanted the styling in the editor to look like my front-end theme, even though I use an administration theme for the node form. I spent many hours trying to find the answer, but it turned out to be simple if a little confusing.

In my example, I have a front-end theme called “Custom Theme” that extends the Bootstrap theme. I use core’s “Seven” theme as an administration theme, and I checked the box to use the administration theme for my node forms. 

My front end theme adds custom fonts to Bootstrap and uses a larger than normal font, so it’s distinctively different than the standard styling that comes with the WYSIWYG editor. 

Front End Styling undefined WYSIWYG Styling

Out of the box, the styling in the editor looks very different than my front-end theme. The font family and line height are wrong, and the font size is too small.

undefined

It turns out there are two ways to alter the styling in the WYSIWYG editor, adding some information to the default theme’s info.yml file, or implementing HOOK_ckeditor_css_alter() in either a module or in the theme. The kicker is that the info changes go in the FRONT END theme, even though I’m using an admin theme on the node form.

I added the following information to my default theme info file, custom_theme.info.yml. The font-family.css and style.css files are the front-end theme CSS files that I want to pass into the WYSIWYG editor. Even if I select the option to use the front-end theme for the node form, the CSS from that theme will not make it into the WYSIWYG editor without making this change, so this is necessary whether or not you use an admin theme on the node form!  

name: "Custom Theme" description: A subtheme of Bootstrap theme for Drupal 8. type: theme core: 8.x base theme: bootstrap ckeditor_stylesheets: - https://fonts.googleapis.com/css?family=Open+Sans - css/font-family.css - css/style.css libraries: ... WYSIWYG Styling

After this change, the font styles in the WYSIWYG editor match the text in the primary theme.

undefined

When CKEditor builds the editor iframe, it checks to see which theme is the default theme, then looks to see if that theme has values in the info.yml file for ckeditor_stylesheets. If it finds anything, it adds those CSS files to the iframe. Relative CSS file URLs are assumed to be files in the front-end theme’s directory, or you can use absolute URLs to other files.

The contributed Bootstrap module does not implement ckeditor_stylesheets, so I had to create a sub-theme to take advantage of this. I always create a sub-theme anyway, to add in the little tweaks I want to make. In this case, my sub-theme also uses a Google font instead of the default font, and I can also pass that font into the WYSIWYG editor.

TaDa!

That was easy to do, but it took me quite a while to understand how it worked. So I decided to post it here in case anyone else is as confused as I was.

More Information

To debug this further and understand how to impact the styling inside the WYSIWYG editor, you can refer to the relevant code from two files in core, ckeditor.module:  

/** * Retrieves the default theme's CKEditor stylesheets. * * Themes may specify iframe-specific CSS files for use with CKEditor by * including a "ckeditor_stylesheets" key in their .info.yml file. * * @code * ckeditor_stylesheets: * - css/ckeditor-iframe.css * @endcode */ function _ckeditor_theme_css($theme = NULL) { $css = []; if (!isset($theme)) { $theme = \Drupal::config('system.theme')->get('default'); } if (isset($theme) && $theme_path = drupal_get_path('theme', $theme)) { $info = system_get_info('theme', $theme); if (isset($info['ckeditor_stylesheets'])) { $css = $info['ckeditor_stylesheets']; foreach ($css as $key => $url) { if (UrlHelper::isExternal($url)) { $css[$key] = $url; } else { $css[$key] = $theme_path . '/' . $url; } } } if (isset($info['base theme'])) { $css = array_merge(_ckeditor_theme_css($info['base theme']), $css); } } return $css; }

and Plugin/Editor/CKEditor.php:  

/** * Builds the "contentsCss" configuration part of the CKEditor JS settings. * * @see getJSSettings() * * @param \Drupal\editor\Entity\Editor $editor * A configured text editor object. * @return array * An array containing the "contentsCss" configuration. */ public function buildContentsCssJSSetting(Editor $editor) { $css = [ drupal_get_path('module', 'ckeditor') . '/css/ckeditor-iframe.css', drupal_get_path('module', 'system') . '/css/components/align.module.css', ]; $this->moduleHandler->alter('ckeditor_css', $css, $editor); // Get a list of all enabled plugins' iframe instance CSS files. $plugins_css = array_reduce($this->ckeditorPluginManager->getCssFiles($editor), function($result, $item) { return array_merge($result, array_values($item)); }, []); $css = array_merge($css, $plugins_css); $css = array_merge($css, _ckeditor_theme_css()); $css = array_map('file_create_url', $css); $css = array_map('file_url_transform_relative', $css); return array_values($css); }

Valuebound: Enabling custom web font in Drupal website

Main Drupal Feed - Wed, 11/08/2017 - 12:21

This blog will walk you through one the contributed module in Drupal community that has been a heave of sigh for me whenever I was in trouble for web building activity. A couple of weeks back, I have been assigned a task where the requirement was to enable ‘Benton-sans Regular’ font throughout the site. Initially, I thought it would be an easy task and can be done easily. But I was wrong.

No issues! If you facing similar difficulties. Here, I am going to discuss how you can enable ‘Benton-sans Regular’ font seamlessly using Drupal font-your-face module.

HeroPress: From the Outskirts to an Insider

Wordpress Planet - Wed, 11/08/2017 - 12:00

WordPress wasn’t the first blogging platform I tried. My very first blog was set up using Blogspot (now Blogger). I didn’t even know I wanted a blog to tell you the truth. But let me take a step back.

I am a techie. A very “untechie” techie, but a techie nonetheless. I actually went to university with a plan to study mathematics and become an actuarial scientist (math and money made for a perfect career, I thought). After one year of university-level mathematics, I decided that I was done with the subject and I stuck with the computer science courses I had also taken. It turned out I had a knack for programming and was often found in the computer lab, debugging my friends’ assignments.

Following my graduation, I worked for several years as a programmer before deciding that I had no interest in coding for the rest of my life. I moved on and up, studying management and information systems, which led me into more managerial positions. On my way there, I decided that I needed to have a personal website. I bought a domain (not my real name though) and starting looking into building my website.

My very first job out of university had been with a web development company as web administrator, where I had picked up quite a bit of HTML, so I figured it would be easy to just build my own website. While researching the latest and best, it struck me that being able to easily add content would be cool, as I had seen early content management systems used back in that job (Tango, anyone?).

Blogging Begins

Suddenly my search results were showing me something called blogging. This was 2005, and blogs were still pretty new. I was excited by the concept, that I could have an easy way to put my thoughts out into cyberspace. I signed up for Blogspot and dove in. For all of 2 days. I wanted to change the design and the layout of my new blog, but I couldn’t. I was stuck in the box that Blogspot provided. A little more searching and I found WordPress.

WordPress meant I could install it myself on my own hosting and play around to my heart’s content. It was a techie’s dream. In April 2005, WordPress was at version 1.5 and I was in heaven. I spent days and nights tweaking and customizing my brand new website and blog. I was a WordPresser.

I was an avid blogger, sharing posts everyday — longer thought-pieces and short asides (who remembers that concept?). The blogging community in Jamaica was small but we were an enthusiastic bunch. Many of my friends were still using other platforms, but I was a diehard WordPress lover. They took comfort in the ease of use of their hosted platforms, while I reveled in being able to completely mess my site up myself (and fix it!).

I played with themes, and experimented with plugins. Two years later, I was helping other people set up and customize their WordPress blogs, and doing migrations from Blogspot.

I was a WordPress freelancer. I didn’t even know this was a thing people did.

It took me several years before I officially created my freelance consultancy, L’Attitude Studios and actually looked to bring in clients.

Despite the fact that WordPress is the most popular blogging platform in Jamaica, and is used by many web developers to built CMS-based websites, there is not much of a WordPress community. And despite my reading all about WordCamps and community meetups, I didn’t really think of myself as part of an actual community. WordCamps started back in 2006 and there have been hundreds since, but I only went to my first WordCamp in 2016, in Miami.

Finding a Place

The organizers of WordCamp Miami made me feel so welcome. They were excited to have me come from Jamaica “just” to attend their event. For the first time, I understood that I have a place in the community, not just as a user. I signed up with the WordPress Community team as an organizer of the WordPress Kingston meetups. Full of enthusiasm I came home, ran a survey to find out how people were using WordPress and declared I was starting local meetups. The sound of crickets followed as the interest was low.

I started a new job and didn’t have time to focus on WordPress, so the meetups fell by the wayside. But I still wanted to contribute. So In 2017, I made the leap to speaking. I decided that there were things I could offer the WordPress community based on my own experiences. WordCamp Ottawa became the first WordCamp I spoke at.

Again, the WordCamp organizers (one of which I had met at WordCamp Miami) were thrilled to have me travel from Jamaica to participate. Funnily, I had to point out to several people that it took less time to get from Jamaica to Ottawa than it did for those traveling from San Francisco.

Everyone I met at WordCamp Ottawa made me feel like a part of the WordPress family, like I belonged.

I still hadn’t got my local meetups going, but I had started making connections in the WordPress space locally. And there seemed to be more interest. I proposed a series of workshops to the organizer of Caribbean Bloggers’ Week. It wouldn’t quite be a WordCamp, which we wouldn’t get permission for, but we could try to do an educational community event to spur interest and raise awareness. WP in the City was born! Sadly, it had to be postponed, but it will still take shape for 2018.

WordCamp US

Now bitten by the bug, I set my speaking sights even higher and made a submission to WordCamp US. A month later, I was notified that one of my two proposals was accepted. I was to be a WordCamp US speaker! Now an even bigger part of the WordPress community would be open to me. I set about making plans for Nashville in December.

By the time you read this, I will be able to announce that I was selected as the recipient of the Kim Parsell Memorial Scholarship. When they notified me, I didn’t even remember I had applied. Kim Parsell was an active member of the WordPress community until her passing in 2015. She was nicknamed “WPMom” because of the care she took in making sure any member of the WordPress community she met felt welcomed and valued.

Kim was already gone before I actively started taking part in the wider WordPress community. But the community I encountered definitely made me feel welcomed and valued, and now I want to help others feel that way. Going to WordCamp US is going to be an amazing opportunity, in part because of the size and breadth of the community I will get to interact with.

Bringing it Home

Jamaica is a small country, an island in the middle of the Caribbean sea. Most people know about our biggest stars (like Bob Marley and Usain Bolt), our culture (reggae music and jerk cooking) or our beaches. The people who go usually remember the people. Our community is what makes us a powerhouse. And I want to tap into that for WordPress.

I want to bring Jamaica into the WordPress community, and bring the WordPress community to Jamaica. I want to get more Jamaicans to WordCamps and actively participating in the WordPress community in other ways (through contributing and meetups).

I want to bring more WordPressers to Jamaica to share and exchange knowledge, not just enjoy the beach.

When I started out, WordPress was just a tool to get me to my goal. For a long time, I didn’t think much about the people behind WordPress, much less considering getting involved myself. Despite my own technical background, I am a newbie where it comes to WordPress development, having remained a tinkerer for much of the last decade. But WordPress is so much more than just code.

Through WordPress, I have been able to express myself through blogging and poetry. I have been able to help others achieve their own success. I have found people willing to share their knowledge for others (like me) to learn. I have found people willing to hear about my WordPress experiences. I have built a network of contacts always willing to help out.

Reading through the other essays on HeroPress, it is also clear that WordPress has changed lives. It has given people a voice. It has brought people together.

WordPress is community. WordPress is my community.

The post From the Outskirts to an Insider appeared first on HeroPress.

Flocon de toile | Freelance Drupal: Change the position of the meta data panel on the node form with Drupal 8

Main Drupal Feed - Wed, 11/08/2017 - 10:00
Content metadata (menu settings, publishing options, url path settings, and so on) are by default displayed on the node form in a side panel. This has the advantage of giving immediate visibility on these options while writing its content. But there are use cases where the lateral position of these informations is detrimental to the general ergonomics, because reducing the space available for the content form. This can be the case, for example, if you use the Field Group module to structure and group the information you need to enter. No need here for a Drupal expert. Let's find out how we can make the position of these metadata customizable according to the needs and general ergonomics of the Drupal 8 project.

Agiledrop.com Blog: AGILEDROP: Top Drupal blogs from October

Main Drupal Feed - Wed, 11/08/2017 - 08:56
The October is over, so it's time we present you top Drupal blogs written in October by other authors.  Let's start with How to maintain Drush commands for Drush 8 and 9 and Drupal console with the same code base by Fabian Bircher from Nuvole. He shows us that the solution is actually really simple, it is all about separating the command discovery from the command logic. Check it out! Our second choice is Decoupled Drupal Hard Problems: Image Styles by Mateu Aguiló Bosch from Lullabot. He shows us the problems when back-end doesn't know anything about the front-end design. He presents a… READ MORE

WPTavern: How to Whitelist Comments in WordPress

Wordpress Planet - Wed, 11/08/2017 - 02:50

Out-of-the-box, WordPress provides the ability to blacklist comments or configure a set of options to send comments to moderation. If all comments are moderated, there are no options to whitelist comments.

Searching the plugin directory for comment whitelisting provides few, if any, solutions. However, a cursory search of Google led me to the Comment Whitelist plugin by Alejandro Carravedo.

Comment Whitelist Box

Comment Whitelist adds a ‘Put in Whitelist’ quick moderation link to comments that makes adding email addresses to the list an easy task. One thing to keep in mind is that the whitelist uses email addresses and it’s possible comments from people impersonating whitelisted users may get published.

Despite not being updated in more than nine years, the plugin works as advertised. You’ll need to download the zip file and manually install it as you won’t be able to find it by searching the plugin directory from the WordPress backend.

Savas Labs: The cost of investing in Drupal 7 - why it's time for Drupal 8

Main Drupal Feed - Wed, 11/08/2017 - 00:00

In the second of a two-part series, we investigate Drupal 8's present value and help highlight sometimes hidden costs of developing on an older platform. Continue reading…

Morpht: Announcing Enforce Profile Field for Drupal 8

Main Drupal Feed - Tue, 11/07/2017 - 23:42


The Enforce Profile Field is a new module which allows editors to enforce the completion of one or more fields in order to access content on a site. It is now available for Drupal 8.

Sometimes you need to collect a variety of profile data for different users. The data may be needed for regulatory compliance or marketing reasons. In some cases you need a single field and in others it may be several. You may also wish to collect the information when a user access certain parts of the site.

The Enforce Profile Field module comes to the rescue in cases such as these, forcing users to complete their profile before being able to move onto the page they want to see. This may sound harsh, however, collecting data as you need it is a more subtle way of collecting data than enforcing it all at registration time.

The implementation consists mainly from a new Field Type called "Enforce profile" and hook_entity_view_alter().

The module works as follows
  1. Site builder defines a “form display” for the user type bundle and specify fields associated with it to collect data.
    1. The fields should not be required, as this allows the user to skip them on registration and profile editing.
    2. In addition the Form Mode Manager module can be used to display the “form display” as a "tab" on a user profile page.
  2. The site builder places an Enforce profile field onto an entity type bundle, such as a node article or page.
  3. The Enforce profile field requires some settings:
    1. A "User's form mode" to be utilized for additional field information extraction (created in the first step).
    2. An "Enforced view modes" that require some profile data to be filled in before being able to access them. You should usually select the "Full content" view mode and rather not include view modes like "Teaser" or "Search".
  4. The editor creates content, an article or page, and can then select which fields need to be enforced.
    1. The editor is provided with multi-select of "User's form mode" fields.
    2. Selecting nothing is equal to no access change, no profile data enforcement.
  5. A new user navigates to the content and is redirected to the profile tab and is informed that they need to complete the fields.
  6. Fields are completed, form submitted and the user redirected back to the content.
    1. In case the user doesn't provide all enforced fields, the profile tab is displayed again with the message what fields need to be filled in.
Why to use the Enforce Profile Field to collect an additional profile data?
  • You may need customer's information to generate a coupon or access token.
  • You may just want to know better with whom you share information.
  • Your users know exactly what content requires their additional profile data input rather than satisfying a wide range of requirements during registration. It just makes it easier for them.
  • The new profile data can be synced to a CRM or other system if required to.

Let us know what you think.
 

WPTavern: Gutenberg Contributors Explore Alternative to Using iframes for Meta Boxes

Wordpress Planet - Tue, 11/07/2017 - 22:58

The discussion surrounding the use of iframes for meta boxes in Gutenberg became more heated over the weekend, as concerned developers implored the team to consider the detriments of the current approach. Responses from Gutenberg’s leadership initially deflected concerns, presenting the iframe implementation as an experiment that “works ‘for now'” but isn’t what the team would ship.

Instead of getting a response to the specific concerns about performance and accessibility of the iframes approach, Kevin Hoffman was urged to think about the future of meta boxes and “the cases (if any) that would not be converted to blocks.” When the developer community is repeatedly asked to test and offer feedback but is met with deflection on issues that are critical to sites using WordPress as a CMS, the GitHub discussions begin to get more heated.

“People are worried, and getting frustrated and it seems to me that they have every right to do so because the perception is that the team working on Gutenberg has little understanding of how meta boxes are being used, little concern for what the impact will be, and is going to move forward with their vision no matter what,” Jimmy Smutek, lead developer at the office of external affairs at Johns Hopkins, said in response to a Gutenberg collaborators’ admission to having been dismissive of feedback.

After several rounds of developers joining the thread to debunk the notion that iframes for meta boxes “work for now,” Gutenberg lead developer Matias Ventura joined the discussion yesterday and confirmed that the experiment is likely to be dropped fairly soon.

“I’m glad the conversation refocused in the end to the topic’s issue: is the current approach to meta-boxes in an iframe viable? With the answer being no,” Ventura said. “The iframes are an implementation detail I think we can drop relatively easy. So let’s focus on that.”

He also addressed the popular opinion that WordPress should make iterative enhancements to the editor itself (and not the full page) before proceeding with overhauling meta boxes.

“What some people have called as the pragmatic approach is not concomitant with the design direction this project has had from the start — heading towards full site customization — and what has dictated our decisions so far,” Ventura said. “Nothing here has to be a final solution, we are exploring what is possible within the design premises and putting it out there for testing.”

Ventura said that not making changes to the other aspects of the edit screen would certainly be the simplest path for Gutenberg to take but that it “would not be fair to the goals of the project and the long term users of WordPress.”

WordPress developer Gary Jones contended that pursuing a more iterative approach would not change the goals of the project but would make it possible for more sites to come along during the process.

“Going one step at a time does not, in any way, compromise the goals of the project,” Jones said. “You can still head to full-size customization if that’s the goal, but by doing it in a stepped way, you’ll bring the rest of the developer community along with you.” Jones cited the Customizer as an example of a feature within WordPress with a concept that is being realized over time with many iterations.

Ventura responded with clarification on the Gutenberg team’s approach to iterating on the project, a paradigm shift that supports block-based content creation from the outset.

“We have proposed a staged approach, from Matt’s original new focuses post, it just considers the steps differently,” Ventura said. “There are generally three stages for the Gutenberg project: from the post editor, to page templates, to site building. What is primordial is that the paradigm is one where the content is a single area, with the block as the primary concept, and where the outcome can be visually represented with clarity and without excessive abstractions.”

Ventura also assured those following along on the discussion that the project will not be dropping support for meta boxes but needs more time to experiment with different interface options.

“WordPress always moves with the user, and we take the burden of figuring out development paths to ease transitions for our existing code,” he said. “As a project, we have said before that we were not dropping support for meta-boxes from WordPress, but also that we had to explore what interface decisions we would have to make within the new paradigm, including the possibility of loading the classic editor when we detect meta-boxes we cannot handle or that directly conflict with an editor that seeks to more clearly delineate what is content and what is meta-data.”

He also said the team plans to create more mechanisms to handle incompatibilities as well as “allowing more things to be opt-in (say if you are comfortable with your meta-boxes showing in Gutenberg you could declare support for it, or vice versa.”

A new approach to rendering meta boxes without using iframes is currently underway. Riad Benguella has created a pull request that attempts to undo the iframes and implement a suggestion that Tom Nowell offered during the discussion:

Instead of loading Gutenberg on a settings page, lets load it into the main classic editors page, load metaboxes in their native environment, then hoist their container DOM node into a component via JS.

We then use a different kind of toggle to make sure the classic editor can still be used. This way:

– we avoid the iframe nonsense
– metaboxes work as they always have done as far as registration is concerned
– the existing JS works as expected, and no hacks are necessary to make things work on the PHP end

The new approach has the advantage of no problems with links, modals, duplicate stylesheets, and the other drawbacks to using iframes.

The Gutenberg Team Needs a New Communication Strategy

The discussion regarding the long-term viability of using iframes for meta boxes has highlighted a lack of a unified message or communication strategy among Gutenberg leads. Collaborators on the project have grown impatient with the community for not grasping the vision, but communication is scattered across various blogs, comments, Slack channels, and GitHub discussions.

Morten Rand-Hendriksen has opened a new issue requesting a centralized resource that can serve as a plain language outline of Gutenberg’s scope, direction, and goals.

“My observation is the community is struggling to see the wider scope of the Gutenberg project due to lack of a single authoritative plain language resource containing this information,” Rand-Hendriksen said. “This creates a high degree of speculation, miscommunication, and frustration from all parties and the project suffers as a consequence.”

Gutenberg does have a documentation hub, but so far those documents are more technical and lack a practical roadmap for how the team is aiming to accomplish its goals. The FAQ section of the current docs is the closest thing to the plain language resource that Rand-Hendriksen is requesting in his ticket. The readme.txt files for both Gutenberg’s GitHub repository and the WordPress.org plugin give the impression that the project is simply updating the current editor to be block-based, not overhauling the entire editor screen.

“Due to the fractured nature of this information it is challenging for anyone to get a clear picture of the entire project, and though Matias and Matt’s posts do a good job at explaining the grand vision of the project, they lack concrete plain language breakdowns of the essentials the community need to get a firm understanding of what this project is and where it’s headed,” Rand-Hendriksen said. “They also exist as independent satellites of information circling the project rather than core parts of the project itself.”

The community is chiming in on the GitHub issue with questions they would like to see answered in a more transparent plain language product roadmap. A document like this might help the Gutenberg team to better communicate the goals of the project and avoid sending mixed messages that cause unnecessary confusion.

Acro Media: Video: How Commerce 2.x Makes Taxes Simple

Main Drupal Feed - Tue, 11/07/2017 - 21:44

 

 

Tax regulations can be ridiculously complicated, particularly in the U.S., but Drupal has your back. With more inclusions and better integrations out of the box, Commerce 2.x represents a significant improvement from Commerce 1.x. Watch this High5 video for details!

Commerce 2.x now includes:
  • Native integration with Avalara
    That means full integration for every region that Avalara handles. Integrations with Tax Cloud and TaxJar are also in the pipeline, so U.S.-based businesses will have a few different options.
  • Built-in tax rules for Canada and the EU (and more)
    These are now included right out of the box; no add-ons or third-party service required. As long as you stay up to date with your Commerce install, you will automatically get any new rules or changes. And if you sell to other countries, you can still build the tax rules and configure them yourself.
  • The ability to prescribe when a tax applies
    Besides being able to set what products a tax applies to and in what regions, you can now select when it applies. So if a tax rule is set to come into effect on January 1st, for instance, you can set that up way in advance and not have to be up at dawn on the big day to push a button. This functionality is also key when it comes to redoing old orders that were done under a different tax scheme.
As always, if you have questions about getting your site setup on Drupal Commerce 2, let us know! We'd love to help.

Agaric Collective: Conditional fields in Paragraphs using the Javascript States API for Drupal 8

Main Drupal Feed - Tue, 11/07/2017 - 14:03

While creating content, there are pieces of information that are only relevant when other fields have a certain value. For example, if we want to allow the user to upload either an image or a video, but not both, you can have another field for the user to select which type of media they want to upload. In these scenarios, the Javascript States API for Drupal 8 can be used to conditionally hide and show the input elements for image and video conditionally.

Note: Do not confuse the Javascript States API with the storage State API.

The basics: conditional fields in node forms

Let’s see how to accomplish the conditional fields behavior in a node form before explaining the implementations for paragraphs. For this example, let’s assume a content type has a machine name of article with three fields: field_image, field_video, and field_media_type. The field_image_or_video field is of type List (text) with the following values: Image and Video.

/** * Implements hook_form_alter(). */ function nicaragua_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { if ($form_id == 'node_article_form' || $form_id == 'node_article_edit_form') { $form['field_ image']['#states'] = [ 'visible' => [ ':input[name="field_image_or_video"]' => ['value' => 'Image'], ], ]; $form['field_ video']['#states'] = [ 'visible' => [ ':input[name="field_image_or_video"]' => ['value' => 'Video'], ], ]; } }

Note that in Drupal 8, the node add and edit form have different form ids. Hence, we check for either one before applying the field states. After checking for the right forms to alter, we implement the fields’ states logic as such:

$form[DEPENDEE_FIELD_NAME]['#states'] = [ DEPENDEE_FIELD_STATE => [ DEPENDENT_FIELD_SELECTOR => ['value' => DEPENDENT_FIELD_VALUE], ], ];

DEPENDENT_FIELD_SELECTOR is a CSS selector to the HTML form element rendered in the browser. Not to be confused with a nested Drupal form structure.

Conditional fields in Drupal 8 paragraphs

Although hook_form_alter could be used in paragraphs as well, their deep nesting nature makes it super complicated. Instead, we can use hook_field_widget_form_alter to alter the paragraph widget before it is added to the form. In fact, we are going to use the widget specific hook_field_widget_WIDGET_TYPE_form_alter to affect paragraphs only.

For this example, let’s assume a content type has a machine name of campaign with an entity reference field whose machine name is field_sections. The paragraph where we want to apply the conditional logic has a machine name of embedded_image_or_video with the following fields: field_image, field_video, and field_image_or_video. The field_image_or_video field is of type List (text) with the following values: Image and Video.

/** * Implements hook_field_widget_WIDGET_TYPE_form_alter(). */ function nichq_field_widget_paragraphs_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) { /** @var \Drupal\field\Entity\FieldConfig $field_definition */ $field_definition = $context['items']->getFieldDefinition(); $paragraph_entity_reference_field_name = $field_definition->getName(); if ($paragraph_entity_reference_field_name == 'field_sections') { /** @see \Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget::formElement() */ $widget_state = \Drupal\Core\Field\WidgetBase::getWidgetState($element['#field_parents'], $paragraph_entity_reference_field_name, $form_state); /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */ $paragraph_instance = $widget_state['paragraphs'][$element['#delta']]['entity']; $paragraph_type = $paragraph_instance->bundle(); // Determine which paragraph type is being embedded. if ($paragraph_type == 'embedded_image_or_video') { $dependee_field_name = 'field_image_or_video'; $selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraph_entity_reference_field_name, $element['#delta'], $dependee_field_name); // Dependent fields. $element['subform']['field_image']['#states'] = [ 'visible' => [ $selector => ['value' => 'Image'], ], ]; $element['subform']['field_video']['#states'] = [ 'visible' => [ $selector => ['value' => 'Video'], ], ]; } } }

Paragraphs can be referenced from multiple fields. If you want to limit the conditional behavior you can check the name of the field embedding the paragraph using:

$field_definition = $context['items']->getFieldDefinition(); $paragraph_entity_reference_field_name = $field_definition->getName();

If you need more information on the field or entity where the paragraph is being embedded, the field definition (instance of FieldConfig) provides some useful methods:

$field_definition->getName(); // Returns the field_name property. Example: 'field_sections'. $field_definition->getType(); // Returns the field_type property. Example: 'entity_reference_revisions'. $field_definition->getTargetEntityTypeId(); // Returns the entity_type property. Example: 'node'. $field_definition->getTargetBundle(); // Returns the bundle property. Example: 'campaign'.

In Drupal 8 it is a common practice to use the paragraph module to replace the body field. When doing so, a single field allows many different paragraph types. In that scenario, it is possible that different paragraph types have fields with the same name. You can add a check to apply the conditional logic only when one specific paragraph type is being embedded.

$widget_state = \Drupal\Core\Field\WidgetBase::getWidgetState($element['#field_parents'], $paragraph_entity_reference_field_name, $form_state); $paragraph_instance = $widget_state['paragraphs'][$element['#delta']]['entity']; $paragraph_type = $paragraph_instance->bundle();

The last step is to add the Javascript states API logic. There are two important things to consider:

  • The paragraph widget are added under a subform key.
  • Because multiple paragraphs can be referenced from the same field, we need to consider the order (i.e. the paragraph delta). This is reflected in the DEPENDENT_FIELD_SELECTOR.
$element['subform'][DEPENDEE_FIELD_NAME]['#states'] = [ DEPENDEE_FIELD_STATE => [ DEPENDENT_FIELD_SELECTOR => ['value' => DEPENDENT_FIELD_VALUE], ], ];

When adding the widget, the form API will generate markup similar to this:

<select data-drupal-selector="edit-field-sections-0-subform-field-image-or-video" id="edit-field-sections-0-subform-field-image-or-video--vtQ4eJfmH7k" name="field_sections[0][subform][field_image_or_video]" class="form-select required" required="required" aria-required="true"> <option value="Image" selected="selected">Image</option> <option value="Video">Video> </select>

So we need a selector like select[name="field_sections[0][subform][field_image_or_video]"] which can be generated using:

$selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraph_field_name, $element['#delta'], $dependee_field_name);

By using $element['#delta'] we ensure to apply the conditional field logic to the proper instance of the paragraph. This works when a field allows multiple paragraphs, including multiple instances of the same paragraph type.

Warning: Javascript behavior does not affect user input

It is very important to note that the form elements are hidden and shown via javascript. This does not affect user input. If, for example, a user selects image and uploads one then changes the selection to video and sets one then both the image and video will be stored. Switching the selection from image to video and vice versa does not remove what the user had previous uploaded or set. Once the node is saved, if there are values for the image and the video both will be saved. One way to work around this when rendering the node is to toggle field visibility in the node Twig template. In my session "Twig Recipes: Making Drupal 8 Render the Markup You Want" there is an example on how to do this. Check out the slide deck and the video recording for reference.

What do you think of this approach to add conditional field logic to paragraphs? Let me know in the comments.

PreviousNext: Composing Docker Local Development: Networking

Main Drupal Feed - Mon, 11/06/2017 - 21:47
Share:

Its extremely important to have default values that you can rely on for local Drupal development, one of those is "localhost". In this blog post we will explore what is required to make our local development environment appear as "localhost".

by Nick Schuch / 7 November 2017

In our journey migrating to Docker for local dev we found ourselves running into issues with "discovery" of services eg. Solr/Mysql/Memcache.

In our first iteration we used linking, allowing our services to talk to each other, some downsides to this were:

  • Tricky to compose an advanced relationship, lets use PHP and PanthomJS as an example:
    • PHP needs to know where PhantomJS is running
    • PhantomJS needs to know the domain of the site that you are running locally
    • Wouldn't it be great if we could just use "localhost" for both of these configurations?
  • DNS entries only available within the containers themselves, cannot run utilities outside of the containers eg. Mysql admin tool

With this in mind, we hatched an idea.....

What if we could just use "localhost" for all interactions between all the containers.

  • If we wanted to access our local projects Apache, http://localhost (inside and outside of container)
  • If we wanted to access our local projects Mailhog, http://localhost:8025 (inside and outside of container)
  • If we wanted to access our local projects Solr, http://localhost:8983 (inside and outside of container)

All this can be achieved with Linux Network Namespaces in Docker Compose.

Network Namespaces

Linux Network Namespaces allow for us to isolate processes into their own "network stacks".

By default, the following happens when a container gets created in Docker:

  • Its own Network Namespace is created
  • A new network interface is added
  • Provided an IP on the default bridge network

However, if a container is created and told to share the same Network Namespace with an existing container, they will both be able to interface with each other on "localhost" or "127.0.0.1".

Here are working examples for both OSX and Linux.

OSX

  • Mysql and Mail share the PHP containers Network Namespace, giving us "localhost" for "container to container" communication.
  • Port mapping for host to container "localhost"
version: "3" services: php: image: previousnext/php:7.1-dev # You will notice that we are forwarding port which do not belong to PHP. # We have to declare them here because these "sidecar" services are sharing # THIS containers network stack. ports: - "80:80" - "3306:3306" - "8025:8025" volumes: - .:/data:cached db: image: mariadb network_mode: service:php mail: image: mailhog/mailhog network_mode: service:php

Linux

All containers share the Network Namespace of the users' host, nothing else is required.

version: "3" services: php: image: previousnext/php:7.1-dev # This makes the container run on the same network stack as your # workstation. Meaning that you can interact on "localhost". network_mode: host volumes: - .:/data db: image: mariadb network_mode: host mail: image: mailhog/mailhog network_mode: host Trade offs

To facilitate this approach we had to make some trade offs:

  • We only run 1 project at a time. Only a single process can bind to port 80, 8983 etc.
  • Split out the Docker Compose files into 2 separate files, making it simple for each OS can have its own approach.
Bash aliases

Since we split out our Docker Compose file to be "per OS" we wanted to make it simple for developers to use these files.

After a couple of internal developers meetings, we came up with some bash aliases that developers only have to setup once.

# If you are on a Mac. alias dc='docker-compose -f docker-compose.osx.yml' # If you are running Linux. alias dc='docker-compose -f docker-compose.linux.yml'

A developer can then run all the usual Docker Compose commands with the shorthand dc command eg.

dc up -d

This also keeps the command docker-compose available if a developer is using an external project.

Simple configuration

The following solution has also provided us with a consistent configuration fallback for local development.

We leverage this in multiple places in our settings.php, here is 1 example:

$databases['default']['default']['host'] = getenv("DB_HOST") ?: '127.0.0.1';
  • Dev / Stg / Prod environments set the DB_HOST environment variable
  • Local is always the fallback (127.0.0.1)
Conclusion

While the solution may have required a deeper knowledge of the Linux Kernel, it has yielded us a much simpler solution for developers.

How have you managed Docker local dev networking? Let me know in the comments below.

Tagged Docker, Drupal Development

Posted by Nick Schuch
Sys Ops Lead

Dated 7 November 2017

Add new comment

Akismet: Version 4.0.1 of the Akismet WordPress Plugin Is Now Available

Wordpress Planet - Mon, 11/06/2017 - 20:29

Version 4.0.1 of the Akismet plugin for WordPress is now available.

4.0.1 contains a few helpful changes:

  • We fixed a bug that could prevent some sites from connecting Akismet using an existing Jetpack connection.
  • We added some code to ensure that any pending Akismet-related events are unscheduled if (heaven forbid) the plugin is deactivated.
  • Some of the Akismet JavaScript is now run asynchronously in order to increase the speed with which your pages will appear to load.

Pretty good, right?  To upgrade, visit the Updates page of your WordPress dashboard and follow the instructions. If you need to download the plugin zip file directly, links to all versions are available in the WordPress plugins directory.


Hook 42: Hook 42 at New England Drupal Camp

Main Drupal Feed - Mon, 11/06/2017 - 20:21

We're super excited to attend New England Drupal Camp this year!

Aimee is honored to have been invited to be the keynote speaker this year. She'll be discussing inclusion and diversity in the community. In addition to Aimee's keynote, we are partnering up with our longtime friends at Lingotek to put together a hands-on multilingual workshop that covers Drupal 8 and an integration to Lingotek's Translation Management System.

Just in case that wasn't enough, we're also presenting a couple of sessions. One comparing the madness of the multilingual modules on Drupal 7 to the new and improved Drupal 8 multilingual approach. We will be presenting another session covering how ANYONE and EVERYONE can help contribute back to the Drupal project even if they aren't the most advance technical person

WPTavern: WordCamp Europe 2018 Early Bird Tickets Now on Sale

Wordpress Planet - Mon, 11/06/2017 - 19:54

WordCamp Europe 2018 has begun early bird ticket sales for its sixth edition in Belgrade, Serbia, June 14-16. Attendees who purchase a ticket before December 31, 2017, will receive a limited-edition swag item.

WordCamp Europe has sold out in many previous years and organizers of the 2017 event in Paris anticipated that it would be the largest event in WordPress history. They expected to host more than 3,000 attendees but the actual number on the ground was 1,900 – 5% fewer than the 2,000 who attended in Vienna the previous year. WCEU 2017 posted a 24% no-show rate, which was more than double that of previous years.

Putting tickets on sale too early was one of the factors that contributed to the Paris event’s high no-show rate, in addition to higher local sales, an expensive location, and attendees’ problems obtaining visas. This year ticket sales are starting a little later and batches will be staged out into 2018.

The WCEU organizing team for Belgrade includes 54 people leading 10 teams to manage sponsors, PR, volunteers, design, and on-site responsibilities. The event has also added a new Attendee Services team that will assist with things like ticket invoices, visa letters, and other services on the ground.

A batch of 1,000 early bird tickets were released today and more than 10% have already been purchased on the first day of sales. Tickets are €40.00 and include two days of presentations, lunch, coffee and snacks, a t-shirt, and a ticket to the After Party. The ticket also gives the attendee access to Contributor Day, which will take place the day before the conference and requires a separate sign up. Tickets are non-refundable but can easily be resold or gifted in the event that the purchaser cannot attend.

Wim Leers: Rendering & caching: a journey through the layers

Main Drupal Feed - Mon, 11/06/2017 - 18:11

The Drupal render pipeline and its caching capabilities have been the subject of quite a few talks of mine and of multiple writings. But all of those were very technical, very precise.

Over the past year and a half I’d heard multiple times there was a need for a more pragmatic talk, where only high-level principles are explained, and it is demonstrated how to step through the various layers with a debugger. So I set out to do just that.

I figured it made sense to spend 10–15 minutes explaining (using a hand-drawn diagram that I spent a lot of time tweaking) and spend the rest of the time stepping through things live. Yes, this was frightening. Yes, there were last-minute problems (my IDE suddenly didn’t allow font size scaling …), but it seems overall people were very satisfied :)

Have you seen and heard of Render API (with its render caching, lazy builders and render pipeline), Cache API (and its cache tags & contexts), Dynamic Page Cache, Page Cache and BigPipe? Have you cursed them, wondered about them, been confused by them?

I will show you three typical use cases:

  1. An uncacheable block
  2. A personalized block
  3. A cacheable block that you can see if you have a certain permission and that should update whenever some entity is updated

… and for each, will take you on the journey through the various layers: from rendering to render caching, on to Dynamic Page Cache and eventually Page Cache … or BigPipe.

Coming out of this session, you should have a concrete understanding of how these various layers cooperate, how you as a Drupal developer can use them to your advantage, and how you can test that it’s behaving correctly.

I’m a maintainer of Dynamic Page Cache and BigPipe, and an effective co-maintainer of Render API, Cache API and Page Cache.

Preview:

Slides: Slides with transcriptVideo: YouTubeConference: Drupalcon ViennaLocation: Vienna, AustriaDate: Sep 28 2017 - 14:15Duration: 60 minutesExtra information: 

See https://events.drupal.org/vienna2017/sessions/rendering-caching-journey-through-layers.

Attendees: 200

Evalutations: 4.6/5

Thanks for the explanation. Your sketches about the rendering process and how dynamic cache, page cache and big pipe work together ; are awesome. It is very clear no for me.


Best session for me on DC. Good examples, loved the live demo, these live demo’s are much more helpful to me as a developer then static slides. General comments, not related to the speaker. The venue was to small for this talk and should have been on a larger stage. Also the location next to the exhibition stands made it a bit noisy when sitting in the back.


Great presentation! I really liked the hand-drawn figure and live demo, they made it really easy to understand and follow. The speaking was calm but engaging. It was great that you were so flexible on the audience feedback.

ThinkShout: My First BADCamp

Main Drupal Feed - Mon, 11/06/2017 - 12:30

We’re fresh off of BADCamp (Bay Area Drupal Camp), and we’re eager to share our experience with you! If you’ve ever thought about going to one of the local Drupal Camps in your area, or attending BADCamp yourself, we hope our takeaways persuade you to seek this out as a professional development opportunity.

BADCamp is essentially three days of intense workshops and sessions for Drupal users to hone their skills, meet other open source contributors, and make valuable connections in the community. Amongst the ThinkShout team, two had never attended BADCamp before. We were eager to hear their perspective on the conference and their key takeaways.

Sessions they attended ranged from learning about component-based theming tools, object oriented php, module development, debugging JavaScript; to Drupal 9 and backward compatibility and the importance of upgrading to D8 now.

Let’s hear from Mario and Lui–I mean Amy and Jules, on what their first BADCamp experience was like!

Amy and Jules on Halloween. Costumes are not required at BADCamp.

What did you learn at BADCamp?

Amy: Component-based theming is a hot topic these days for those building sites due to a number of reasons. Here are a couple of them:

  • It encourages a DRY (Don’t Repeat Yourself) and more organized theming code base.
  • It decouples site building in such a way that backend and frontend developers can work on the site at the same time, rather than the backend code needing to be built first before the frontend developer can do their work.
  • It provides clients with an interactive experience of their site (including responsiveness) before the database and backend elements are hooked up to it. This allows the client more time to provide feedback in case they want to change behaviors before they’re completely built.

I also attended a session called: React, GraphQL, and Drupal. This talk was largely about an opportunity to create multiple suites using the same API. The team used “headless Drupal” (to serve as the API), React.js to build the sites, and GraphQL to explore data coming from the API in a much more direct and clear way. It seemed like a great solution for a tricky problem, in addition to giving this team the opportunity to learn and use cutting edge technologies - so much fun!

Jules: I learned a lot about the Drupal Community. This was my first BADCamp, and also my first Drupal conference. I was excited about how generous the community is with knowledge and tools, working together so we can succeed together.

I learned about some of the changes to Drupal releases from @Webchick’s talk (Drupal 9 and Backward Compatibility: Why Now is the Time to Upgrade to Drupal 8). If I keep up with the incremental point releases (ie: 8.x), upgrading to 9 should be pretty painless, which is a relief. Knowing the incremental releases will be coming out with a regular six month-ish cadence will make planning easier. I’m also excited about the new features in the works; including Layouts, Work Spaces, a better out of the box experience on first install, a better UI admin experience (possibly with React?).

What would you tell someone who is planing to attend BADCamp next year?

Amy: Definitely invest in attending the full-day sessions if they interest you. The information I took away from my Pattern Lab day was priceless, and I came back to ThinkShout excited and empowered to figure out a way to make component based theming part of our usual practice.

Jules: The full day sessions were a great way to dive into deeper concepts. It’s hard to fully cover a subject in a shorter session. It also helps to show up with an open mind. It’s impossible to know everything about Drupal, and there are so many tools available. It was valuable just meeting people and talking to them about their workflows, challenges, and favorite new tools.

Do you consider BADCamp to be better for networking, professional development, or both?

Amy: My big focus was on professional development. There were so many good training days and sessions happening that those filled my schedule almost entirely. Of course, attending sessions (and being a session speaker!) is a great way to network with like-minded people too.

Jules: My goal was to immerse myself in the Drupal community. Since I’m new to Drupal, the sessions were really valuable for me. Returning with more experience, that might not be the case. It was valuable to see new ideas being presented, challenged, discussed, and explored with mutual respect and support. We’re all in this together. Some talks were stronger than others, but every speaker had a nugget of gold I could take with me. It was encouraging to meet peers and to see all of the great work people are doing out in the world. It also served as a reminder that great strides can come from many small steps (or pushes)!

Make time to learn

It can be difficult to take time away from project work and dedicate yourself to two or three days of conferencing. But when you disconnect and dive into several days of leaning, it makes your contributions back at the office invaluable. As Jules commented to me after her first day of sessions, “it was like php church!”

Getting out of your usual environment and talking to other people opens your mind up to other ways of problem solving, and helps you arrive at solutions you otherwise wouldn’t get through sitting in your cubicle. We hope you’re inspired to go to a local Drupal Meetup or Camp – or even better, meet us at DrupalCon or NTC’s Drupal Day!

Agiledrop.com Blog: AGILEDROP: Why rejecting projects due to resourcing challenges is avoidable

Main Drupal Feed - Mon, 11/06/2017 - 10:49
Even though I have been with AGILEDROP for little over than three months now, I already found myself in a situation when two of our potential clients were on the verge of declining their clients. The reasons for that were different, I'll go into more detail later. The agencies we approached differed in size, one being bigger (more than 50 people) the other smaller (less than 10 people). And the challenges they faced were also different. As you will see we could help both of them, but in the end, only one of the agencies trusted us that we are capable of delivering.  From a simple… READ MORE

OSTraining: How to Highlight the Differences Detween Two Images with Zurb Twenty Twenty Module

Main Drupal Feed - Mon, 11/06/2017 - 08:41

Zurb TwentyTwenty module is mostly intended to highlight the difference between two images on a Drupal site. You certainly saw those advertising images for skin products, for example. 

They would present half of the face before applying the product and half of the face after applying it. Besides such comparisons, you can use this module for other purposes as well. In this tutorial, you will learn how Zurb TwentyTwenty module works.

Appnovation Technologies: My First Book - Drupal 8 Module Development (Or Where I Have Been Lately)

Main Drupal Feed - Mon, 11/06/2017 - 08:00
My First Book - Drupal 8 Module Development (Or Where I Have Been Lately) If you’ve been wondering where I’ve been and why I haven’t been writing any articles lately, I am here to put your mind at ease: I've been working heavily on my first book about Drupal, called Drupal 8 Module Development. And I am happy to announce that it has finally been published and is available for purch...

Pages