Cool News Card Design with Display Suite and Views in Drupal 7
I want to display news posts in a neat little row. A simple date in the upper left, an image of a consistent size, and the title in a dark box below. The box itself should be one entire link.
How we’ll do it
- Install Display Suite
- Create a small custom module to make our own Display Suite layout
- Make an image style
- Make a date format
- Use that layout in the news content type’s Manage Display
- Make a View Block to display four cards
- (Javascript to add keyboard navigation)
01. Install Display Suite
The Display Suite contrib Drupal module allows us to place content type fields into our own layout regions with our own custom layouts. Among other things.
02. Custom module for our own layout
Let’s create our own layout first, then put it in a module. I construct an HTML component, then use CSS to style it like a card.
I am going to have three sections:
- news_card_top
- news_card_caption
- news_card_date
Name these files like this. newscard is the machine name of my layout.
- Template (the HTML/PHP at the bottom of this section):
newscard.tpl.php
- CSS:
newscard.css
HTML/CSS
HTML: Space for the top where I’ll put the image, the caption where I’ll put the title, and the date, which we’ll position at the top.
<div class="news_card">
<div class="news_card_wrapper">
<div class="news_card_top">
<!-- Image goes here -->
</div>
<div class="news_card_caption">
<!-- Title will goes here -->
</div>
<div class="news_card_date">
<!-- Date goes here -->
</div>
</div>
</div>
CSS: The card components are wrapped in a column flex container which allows the content to stretch to the available height making the content even. The date is positioned absolutely so it rises up to the top like a happy champagne bubble.
Important! Your CSS is going to have to vary to cooperate with your theme. The main ideas of this CSS are in bold.
.news_card {
position: relative;
display: flex;
justify-content: center;
height: 100%;
border: 1px solid #ddd;
}.news_card[onclick]:hover {
cursor: pointer;
box-shadow: 0 0 4px 3px #8cb8d0;
}.news_card_wrapper {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
overflow: hidden;
}.news_card_top {
flex: 0 0 auto;
}.news_card_top img {
height: auto !important;
width: 100%;
max-width: 100%;
}.news_card_date {
position: absolute;
top: 0;
left: 0;
padding: 0.5rem;
color: #ffffff;
background: #006BA6;
}.news_card_date .date-display-single {
color: #ffffff !important;
}.news_card_date .date-display-single:before {
content: '' !important;
margin-right: 0 !important;
}.news_card_caption {
flex: 1 0 auto;
display: flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1rem;
padding: 1rem;
color: #ffffff;
background: rgba(0, 0, 0, 0.75);
}
PHP
We have to inject PHP into the HTML to bring in the content and any custom wrappers and classes. This is going to look really verbose and I’m sorry. I’ll try to make sense of it by bolding any original code.
<<?php print $layout_wrapper; print $layout_attributes; ?> class="news_card <?php print $classes;?>"> <?php if (isset($title_suffix['contextual_links'])): ?>
<?php print render($title_suffix['contextual_links']); ?>
<?php endif; ?> <div class="news_card_top_wrapper"> <?php if ($news_card_top): ?>
<<?php print $news_card_top_wrapper ?> class="news_card_top <?php print $news_card_top_classes; ?>">
<?php print $news_card_top; ?>
</<?php print $news_card_top_wrapper ?>>
<?php endif; ?> <?php if ($news_card_caption): ?>
<<?php print $news_card_caption_wrapper ?> class="news_card_caption <?php print $news_card_caption_classes; ?>">
<?php print $news_card_caption; ?>
</<?php print $news_card_caption_wrapper ?>>
<?php endif; ?> <?php if ($news_card_date): ?>
<<?php print $news_card_date_wrapper ?> class="news_card_date <?php print $news_card_date_classes; ?>">
<?php print $news_card_date ?>
</<?php print $news_card_date_wrapper ?>>
<?php endif; ?> </div></<?php print $layout_wrapper ?>>
Things to note:
- The
_wrapper
parts like the first line replace my genericdiv
element with whatever is used in the Display Suite custom wrappers. - The
_classes
pull in any custom classes applied in the DS custom classes settings. - There are if statements wrapped around each part. I only what that HTML to show if there’s something in that part.
- The
print $news_card_caption
print the actual content placed in that part.
Constructing the Module
Here is the module structure. My module’s machine name is newscard_layout
.
newscard_layout
-- layouts
---- newscard
------ newscard.css
------ newscard.tpl.php
-- newscard_layout.info
-- newscard_layout.module
newscard_layout.info: Defines the module.
name = News Card Display Suite Layout
description = News Card Display Suite Layout
package = "Display Suite"
core = 7.x
dependencies[] = ds
newscard_layout.module has a function to define the layout. Note where you’d plug in your own information in bold.
/**
* Implements hook_ds_layout_info().
*/
function newscard_layout_ds_layout_info() {// Get the path to the module.
$path = drupal_get_path('module', 'newscard_layout');$layouts = array();$layouts['newscard'] = array(
'label' => t('News Card'),
'path' => $path . '/layouts/newscard',
'regions' => array(
'news_card_top' => t('Top'),
'news_card_date' => t('Date'),
'news_card_caption' => t('Caption'),
),
'css' => TRUE,
'image' => FALSE,
);
return $layouts;
}
I place my css file in the same folder as my layout template, in the layouts folder. That’s where 'css' => TRUE
is going to look for it.
Done!
When you install and enable this module, you should see News Card layout as an option when you go to add a Display Suite layout to a Manage Display of a content type. I hope.
03. Image style
For this design
admin/config/media/image-styles
and Add Style.
04. Date Format
Default date formats don’t give me a short month/day format I want. First we create the date format, then the date type.
admin/config/regional/date-time/formats
and Add Format. PHP has codes for making date formats. I use M j
.
admin/config/regional/date-time
and ‘Add date type’. Find your date format in the dropdown.
05. Apply the layout to the content type
We have all our pieces in place: layout, image style, and date format.
admin/structure/types/manage/your_content_type/display
In order to use Display Suite in a content type, you have to select a layout on the default view mode. You can just choose a blank or one column or something generic.
Create a new View Mode and arrange fields in the new card layout.
- On the default view mode, scroll to the bottom to the ‘Custom display settings’ tab.
- Check another box for an existing view mode or make a new one with ‘Manage view modes’.
- When making a new view mode, check the ‘Node’ box. I called mine Card.
- Back on the Manage Display tab, make sure you’re on your new View Mode.
- Scroll down and choose News Card.
- Now there will be regions in the list of fields.
- Arrange and configure your fields like this:
Your fields may have different names. The important bits:
- Image in Top. Use the ‘Card’ image style you made.
- Post Date in Date. Find your new date format.
- Title in Caption. Set link ‘no’, add the
news_card_title
a style we made in our CSS file.
To make the whole card click-able
- go to the ‘Custom wrappers’ tab at the bottom
- Choose ‘link to content’ under ‘Add link’
- Add `
role="link" tabindex="0"
under Layout attributes. This improves keyboard navigability and announces the element as a link to accessibility technology. - Bonus: Scroll to the bottom for some extra javascript I added to the module so you can hit Enter/Return to open the link.
06. Pull cards into a View
Create a View Block that pulls in your content types. This isn’t a great place to go into Views, but here are the main points:
Format: Unformatted list | ‘Add views row classes’
Show: Content | Card
Pager: Display a specified number of items | 4 items
Advanced, CSS class:news-card-row
Basically, we are gong to show the ‘Card’ view mode we just set up instead of fields. The news-card-row
class references the CSS styles from above that put the Views rows into a row.
Javascript Bonus:
I have an extra javascript file in my module because I wanted to be able to tab through each card and then hit enter.
- Add a folder in the layout module and place a js file in it:
js/newscard.js
- Add the js to the
newscard_layout.info
file
name = News Card Display Suite Layout
description = News Card Display Suite Layout
package = "Display Suite"
core = 7.x
dependencies[] = ds
scripts[] = js/newscard.js
3. Here is the javascript snippet. It says when a div has an onclick
attribute (which is how Drupal made the card clickable), and when a button is pressed keydown
, ‘click’ the div if that button is the Enter/Return key.
(function ($) { $(document).ready(function() { $('div[onclick]').keydown(function(event) {
var key = event.which;
if (key == 13) {
$(this).click();
}
}) });})(jQuery);
That should do it!
I hope it’s apparent how these principles can be customized to your use-case.