Month: March 2019

4 Places to Find New Web Design Inspiration

Scroll-Linked Animations

You scroll down to a certain point, now you want to style things in a certain way. A header becomes fixed. An animation triggers. A table of contents appears. To do anything based on scroll position, JavaScript is required right now. You watch the scroll position via a DOM event and alter an element’s styling based on that position. Or, probably better if you can, use IntersectionObserver. We just blogged about all this.

Now there is a new (unofficial) spec trying to bring these possibilities to CSS. I love it when web standards get involved because it sees authors like us trying to pull off certain design effects and wants to (presumably) help make it easier and more performant. I also like how this spec lists editors from Mozilla and Google and Apple.

I wonder how they’ll handle the infinite-loop stuff here. Like you scroll to a point, it triggers some animation, which moves some element such that it changes the scroll position, which stops the animation, which moves the scroll position again… etc. I also wonder why it’s all specific to animation. “Scroll-position styling” seems like it would have the widest appeal and use level of usefulness.

Direct Link to ArticlePermalink

The post Scroll-Linked Animations appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

You probably don’t need input type=“number”

Brad Frost wrote about a recent experience with a website that used <input type="number">:

Last week I got a call from my bank regarding a wire transfer I had just scheduled. The customer support guy had me repeat everything back to him because there seemed to be a problem with the information. “Hmmmm, everything you said is right right except the last 3 digits of the account number.”

He had me resubmit the wire transfer form. When I exited the account number field, the corner of my eye noticed the account number change ever so slightly. I quickly refocused into the field and slightly moved my index finger up on my Magic Mouse. It started looking more like a slot machine than an input field!

Brad argues that we then shouldn’t be using <input type="number"> for “account numbers, social security numbers, credit card numbers, confirmation numbers” which makes a bunch of sense to me! Instead we can use the pattern attribute that Chris Ferdinandi looked at a while back in a post all about constraint validation in HTML.

It’s worth mentioning that numeric inputs can be more complex than they appear and that their appearance and behavior vary between browsers. All good things to consider along alongside Brad’s advice when evaluating user experience.

Also:

Direct Link to ArticlePermalink

The post You probably don’t need input type=“number” appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Creating a Reusable Pagination Component in Vue

The idea behind most of web applications is to fetch data from the database and present it to the user in the best possible way. When we deal with data there are cases when the best possible way of presentation means creating a list.

Depending on the amount of data and its content, we may decide to show all content at once (very rarely), or show only a specific part of a bigger data set (more likely). The main reason behind showing only part of the existing data is that we want to keep our applications as performant as possible and avoid loading or showing unnecessary data.

If we decide to show our data in “chunks” then we need a way to navigate through that collection. The two most common ways of navigating through set of data are:

The first is pagination, a technique that splits the set of data into a specific number of pages, saving users from being overwhelmed by the amount of data on one page and allowing them to view one set of results at a time. Take this very blog you’re reading, for example. The homepage lists the latest 10 posts. Viewing the next set of latest posts requires clicking a button.

The second common technique is infinite scrolling, something you’re likely familiar with if you’ve ever scrolled through a timeline on either Facebook or Twitter.

The Apple News app also uses infinite scroll to browse a list of articles.

We’re going to take a deeper look at the first type in this post. Pagination is something we encounter on a near-daily basis, yet making it is not exactly trivial. It’s a great use case for a component, so that’s exactly what we’re going to do. We will go through the process of creating a component that is in charge of displaying that list, and triggering the action that fetches additional articles when we click on a specific page to be displayed. In other words, we’re making a pagination component in Vue.js like this:

Let’s go through the steps together.

Step 1: Create the ArticlesList component in Vue

Let’s start by creating a component that will show a list of articles (but without pagination just yet). We’ll call it ArticlesList. In the component template, we’ll iterate through the set of articles and pass a single article item to each ArticleItem component.

// ArticlesList.vue <template>   <div>     <ArticleItem       v-for="article in articles"       :key="article.publishedAt"       :article="article"     />   </div> </template>

In the script section of the component, we set initial data:

  • articles: This is an empty array filled with data fetched from the API on mounted hook.
  • currentPage: This is used to manipulate the pagination.
  • pageCount : This is the total number of pages, calculated on mounted hook based on the API response.
  • visibleItemsPerPageCount: This is how many articles we want to see on a single page.

At this stage, we fetch only first page of the article list. This will give us a list two articles:

// ArticlesList.vue import ArticleItem from "./ArticleItem" import axios from "axios" export default {   name: "ArticlesList",   static: {     visibleItemsPerPageCount: 2   },   data() {     return {       articles: [],       currentPage: 1,       pageCount: 0     }   },   components: {      ArticleItem,    },   async mounted() {     try {       const { data } = await axios.get(         `?country=us&page=1&pageSize=$ {           this.$ options.static.visibleItemsPerPageCount         }&category=business&apiKey=065703927c66462286554ada16a686a1`       )       this.articles = data.articles       this.pageCount = Math.ceil(         data.totalResults / this.$ options.static.visibleItemsPerPageCount       )     } catch (error) {       throw error     }   } }

Step 2: Create pageChangeHandle method

Now we need to create a method that will load the next page, the previous page or a selected page.

In the pageChangeHandle method, before loading new articles, we change the currentPage value depending on a property passed to the method and fetch the data respective to a specific page from the API. Upon receiving new data, we replace the existing articles array with the fresh data containing a new page of articles.

// ArticlesList.vue ... export default { ...   methods: {     async pageChangeHandle(value) {       switch (value) {         case 'next':           this.currentPage += 1           break         case 'previous':           this.currentPage -= 1           break         default:           this.currentPage = value       }       const { data } = await axios.get(         `?country=us&page=$ {this.currentPage}&pageSize=$ {           this.$ options.static.visibleItemsPerPageCount         }&category=business&apiKey=065703927c66462286554ada16a686a1`       )       this.articles = data.articles     }   } }

Step 3: Create a component to fire page changes

We have the pageChangeHandle method, but we do not fire it anywhere. We need to create a component that will be responsible for that.

This component should do the following things:

  1. Allow the user to go to the next/previous page.
  2. Allow the user to go to a specific page within a range from currently selected page.
  3. Change the range of page numbers based on the current page.

If we were to sketch that out, it would look something like this:

Let’s proceed!

Requirement 1: Allow the user to go to the next or previous page

Our BasePagination will contain two buttons responsible for going to the next and previous page.

// BasePagination.vue <template>   <div class="base-pagination">     <BaseButton       :disabled="isPreviousButtonDisabled"       @click.native="previousPage"     >       ←     </BaseButton>     <BaseButton       :disabled="isNextButtonDisabled"       @click.native="nextPage"     >       →     </BaseButton>   </div> </template>

The component will accept currentPage and pageCount properties from the parent component and emit proper actions back to the parent when the next or previous button is clicked. It will also be responsible for disabling buttons when we are on the first or last page to prevent moving out of the existing collection.

// BasePagination.vue import BaseButton from "./BaseButton.vue"; export default {   components: {     BaseButton   },   props: {     currentPage: {       type: Number,       required: true     },     pageCount: {       type: Number,       required: true     }   },   computed: {     isPreviousButtonDisabled() {       return this.currentPage === 1     },     isNextButtonDisabled() {       return this.currentPage === this.pageCount     }   },   methods: {     nextPage() {       this.$ emit('nextPage')     },     previousPage() {       this.$ emit('previousPage')     }   }

We will render that component just below our ArticleItems in ArticlesList component.

// ArticlesList.vue <template>   <div>     <ArticleItem       v-for="article in articles"       :key="article.publishedAt"       :article="article"     />     <BasePagination       :current-page="currentPage"       :page-count="pageCount"       class="articles-list__pagination"       @nextPage="pageChangeHandle('next')"       @previousPage="pageChangeHandle('previous')"     />   </div> </template>

That was the easy part. Now we need to create a list of page numbers, each allowing us to select a specific page. The number of pages should be customizable and we also need to make sure not to show any pages that may lead us beyond the collection range.

Requirement 2: Allow the user to go to a specific page within a range

Let’s start by creating a component that will be used as a single page number. I called it BasePaginationTrigger. It will do two things: show the page number passed from the BasePagination component and emit an event when the user clicks on a specific number.

// BasePaginationTrigger.vue <template>   <span class="base-pagination-trigger" @click="onClick">     {{ pageNumber }}   </span> </template> <script> export default {   props: {     pageNumber: {       type: Number,       required: true     }   },   methods: {     onClick() {       this.$ emit("loadPage", this.pageNumber)     }   } } </script>

This component will then be rendered in the BasePagination component between the next and previous buttons.

// BasePagination.vue <template>   <div class="base-pagination">     <BaseButton />     ...     <BasePaginationTrigger       class="base-pagination__description"       :pageNumber="currentPage"       @loadPage="onLoadPage"     />     ...     <BaseButton />   </div> </template>

In the script section, we need to add one more method (onLoadPage) that will be fired when the loadPage event is emitted from the trigger component. This method will receive a page number that was clicked and emit the event up to the ArticlesList component.

// BasePagination.vue export default {   ...     methods: {     ...     onLoadPage(value) {       this.$ emit("loadPage", value)     }   } }

Then, in the ArticlesList, we will listen for that event and trigger the pageChangeHandle method that will fetch the data for our new page.

// ArticlesList <template>   ...     <BasePagination       :current-page="currentPage"       :page-count="pageCount"       class="articles-list__pagination"       @nextPage="pageChangeHandle('next')"       @previousPage="pageChangeHandle('previous')"       @loadPage="pageChangeHandle"     />   ... </template>

Requirement 3: Change the range of page numbers based on the current page

OK, now we have a single trigger that shows us the current page and allows us to fetch the same page again. Pretty useless, don’t you think? Let’s make some use of that newly created trigger component. We need a list of pages that will allow us to jump from one page to another without needing to go through the pages in between.

We also need to make sure to display the pages in a nice manner. We always want to display the first page (on the far left) and the last page (on the far right) on the pagination list and then the remaining pages between them.

We have three possible scenarios:

  1. The selected page number is smaller than half of the list width (e.g. 1 – 2 – 3 – 4 – 18)
  2. The selected page number is bigger than half of the list width counting from the end of the list (e.g. 1 – 15 – 16 – 17 – 18)
  3. All other cases (e.g. 1 – 4 – 5 – 6 – 18)

To handle these cases, we will create a computed property that will return an array of numbers that should be shown between the next and previous buttons. To make the component more reusable we will accept a property visiblePagesCount that will specify how many pages should be visible in the pagination component.

Before going to the cases one by one we create few variables:

  • visiblePagesThreshold:- Tells us how many pages from the centre (selected page should be shown)
  • paginationTriggersArray: Array that will be filled with page numbers
  • visiblePagesCount: Creates an array with the required length
// BasePagination.vue export default {   props: {     visiblePagesCount: {       type: Number,       default: 5     }   }   ...   computed: {     ...       paginationTriggers() {         const currentPage = this.currentPage         const pageCount = this.pageCount         const visiblePagesCount = this.visiblePagesCount         const visiblePagesThreshold = (visiblePagesCount - 1) / 2         const pagintationTriggersArray = Array(this.visiblePagesCount - 1).fill(0)       }     ...     }   ... }

Now let’s go through each scenario.

Scenario 1: The selected page number is smaller than half of the list width

We set the first element to always be equal to 1. Then we iterate through the list, adding an index to each element. At the end, we add the last value and set it to be equal to the last page number — we want to be able to go straight to the last page if we need to.

if (currentPage <= visiblePagesThreshold + 1) {   pagintationTriggersArray[0] = 1   const pagintationTriggers = pagintationTriggersArray.map(     (paginationTrigger, index) => {       return pagintationTriggersArray[0] + index     }   )   pagintationTriggers.push(pageCount)   return pagintationTriggers }
Scenario 2: The selected page number is bigger than half of the list width counting from the end of the list

Similar to the previous scenario, we start with the last page and iterate through the list, this time subtracting the index from each element. Then we reverse the array to get the proper order and push 1 into the first place in our array.

if (currentPage >= pageCount - visiblePagesThreshold + 1) {   const pagintationTriggers = pagintationTriggersArray.map(     (paginationTrigger, index) => {       return pageCount - index     }   )   pagintationTriggers.reverse().unshift(1)   return pagintationTriggers }
Scenario 3: All other cases

We know what number should be in the center of our list: the current page. We also know how long the list should be. This allows us to get the first number in our array. Then we populate the list by adding an index to each element. At the end, we push 1 into the first place in our array and replace the last number with our last page number.

pagintationTriggersArray[0] = currentPage - visiblePagesThreshold + 1 const pagintationTriggers = pagintationTriggersArray.map(   (paginationTrigger, index) => {     return pagintationTriggersArray[0] + index   } ) pagintationTriggers.unshift(1); pagintationTriggers[pagintationTriggers.length - 1] = pageCount return pagintationTriggers

That covers all of our scenarios! We only have one more step to go.

Step 5: Render the list of numbers in BasePagination component

Now that we know exactly what number we want to show in our pagination, we need to render a trigger component for each one of them.

We do that using a v-for directive. Let’s also add a conditional class that will handle selecting our current page.

// BasePagination.vue <template>   ...   <BasePaginationTrigger     v-for="paginationTrigger in paginationTriggers"     :class="{       'base-pagination__description--current':         paginationTrigger === currentPage     }"     :key="paginationTrigger"     :pageNumber="paginationTrigger"     class="base-pagination__description"     @loadPage="onLoadPage"   />   ... </template>

And we are done! We just built a nice and reusable pagination component in Vue.

When to avoid this pattern

Although this component is pretty sweet, it’s not a silver bullet for all use cases involving pagination.

For example, it’s probably a good idea to avoid this pattern for content that streams constantly and has a relatively flat structure, like each item is at the same level of hierarchy and has a similar chance of being interesting to the user. In other words, something less like an article with multiple pages and something more like main navigation.

Another example would be browsing news rather than looking for a specific news article. We do not need to know where exactly the news is and how much we scrolled to get to a specific article.

That’s a wrap!

Hopefully this is a pattern you will be able to find useful in a project, whether it’s for a simple blog, a complex e-commerce site, or something in between. Pagination can be a pain, but having a modular pattern that not only can be re-used, but considers a slew of scenarios, can make it much easier to handle.

The post Creating a Reusable Pagination Component in Vue appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Web Design Sins to Avoid – Turning Bad Websites into Successful Websites

[Top]

Powers of Two

Refactoring is one of those words that evokes fear in the eyes of many folks, from developers to product owners and everyone in between. It may as well be a four-letter word in many ways. It’s also something that we talk about quite a bit around here because, like books on the topic, where to start with one, and the impact of letting technical debt pile up.

Ben Rady has thoughts on refactoring as well, but in the context of pair programming:

We pair for about 6 hours a day, every day. Everything that’s on the critical path is worked on in a pair. Always. Our goal is always to get the thing we’re working on to production as fast as we responsibly can, and the best way I’ve found to that is with a pair.

Ben then dives into the process of working alongside others and how to ship software with that approach, a lot of which I think relates to front-end development best practices, too. But I also love how punk rock this team is, as they appear not to develop software with a backlog or a ton of meetings for managing their projects:

No formal backlog. We have three states for new features. Now, next, and probably never. Whatever we’re working on now is the most valuable thing we can think of. Whatever’s next is the next most valuable thing. When we pull new work, we ask “What’s next?” and discuss. If someone comes to us with an idea, we ask “Is this more valuable that what we were planning to do next?” If not, it’s usually forgotten, because by the time we finish that there’s something else that’s newer and better. But if it comes up again, maybe it’ll make the cut.

I wonder how much time a year they save without having to argue about stories and points and whether this one tiny feature is more important than this other one. Anyway, I find all of this stuff thoroughly inspiring.

Direct Link to ArticlePermalink

The post Powers of Two appeared first on CSS-Tricks.

CSS-Tricks

[Top]

CSS Houdini Could Change the Way We Write and Manage CSS

CSS Houdini may be the most exciting development in CSS. Houdini is comprised of a number of separate APIs, each shipping to browsers separately, and some that have already shipped (here’s the browser support). The Paint API is one of them. I’m very excited about it and recently started to think about how I can use it in my work.

One way I’ve been able to do that is to use it as a way to avoid reinventing the wheel. We’ll go over that in this post while comparing it with methods we currently use in JavaScript and CSS. (I won’t dig into how to write CSS Houdini because there are great articles like this, this and this.)

Houdini brings modularity and configurations to CSS

The way CSS Houdini works brings two advantages: modularity and configurability. Both are common ways to make our lives as developers easier. We see these concepts often in the JavaScript world, but less-so with CSS world… until now.

Here’s a table the workflows we have for some use cases, comparing traditional CSS with using Houdini. I also added JavaScript for further comparison. You can see CSS Houdini allows us to use CSS more productively, similar to how the JavaScript world had evolved into components.

Traditional CSS CSS Houdini JavaScript
When we need a commonly used snippets Write it from scratch or copy-paste from somewhere. Import a worklet for it. Import a JS library.
Customize the snippet for the use case Manually tweak the value in CSS. Edit custom properties that the worklet exposes. Edit configs that the library provides.
Sharing code Share code for the raw styles, with comments on how to tweak each piece. Share the worklet (in the future, to a package management service) and document custom properties. Share the library to a package management service (like npm) and document how to use and configure it.

Modularity

With Houdini, you can import a worklet and start to use it with one line of code.

<script>   CSS.paintWorklet.addModule('my-useful-paint-worklet.js'); </script>

This means there’s no need to implement commonly used styles every time. You can have a collection of your own worklets which can be used on any of your projects, or even shared with each other.

If you’re looking for modularity for HTML and JavaScript in additional to styles, then web components is the solution.

It’s very similar to what we already have in the JavaScript world. Most people won’t re-implement commonly used functions, like throttling or deep-copying objects. We simply import libraries, like Lodash.

I can imagine we could have CSS Houdini package management services if the popularity of CSS Houdini takes off, and anyone could import worklets for interesting waterfall layouts, background patterns, complex animation, etc.

Configurability

Houdini works well with CSS variables, which largely empowers itself. With CSS variables, a Houdini worklet can be configured by the user.

.my-element {   background-image: paint(triangle);   --direction: top;   --size: 20px; }

In the snippet, --direction and --size are CSS variables, and they’re used in the triangle worklet (defined by the author of the triangle worklet). The user can change the property to update how it displays, even dynamically updating CSS variables in JavaScript.

If we compare it to what we already have in JavaScript again, JavaScript libraries usually have options that can be passed along. For example, we can pass values for speed, direction, size and so on to a carousel library to make it perform the way we want. Offering these APIs at the element level in CSS is very useful.

A Houdini workflow makes my development process much more efficient

Let’s see a complete example of how this whole thing can work together to make development easier. We’ll use a tooltip design pattern as an example. I find myself using this pattern often in different websites, yet somehow re-implement for each new project.

Let’s briefly walk through my old experience:

  1. OK, I need a tooltip.
  2. It’s a box, with a triangle on one side. I’ll use a pseudo-element to draw the triangle.
  3. I can use the transparent border trick to draw the triangle.
  4. At this time, I most likely dig up my past projects to copy the code. Let me think… this one needs to point up, which side is transparent?
  5. Oh, the design requires a border for the tooltip. I have to use another pseudo-element and fake a border for the pointing triangle.
  6. What? They decide to change the direction of the triangle?! OK, OK. I will tweak all the values of both triangles…

It’s not rocket science. The whole process may only take five minutes. But let’s see how it can be better with Houdini.

I built a simple worklet to draw a tooltip, with many options to change its looks. You can download it on GitHub.

Here’s my new process, thanks to Houdini:

  1. OK, I need a tooltip.
  2. I’ll import this tooltip worklet and use it.
  3. Now I’ll modify it using custom properties.
<div class="tooltip-1">This is a tip</div> <script>CSS.paintWorklet.addModule('my-tooltip-worklet.js')</script> <style> .tooltip-1 {   background-image: paint(tooltip);   padding: calc(var(--triangle-size) * 1px + .5em) 1em 1em;   --round-radius: 0;   --background-color: #4d7990;   --triangle-size: 20;   --position: 20;   --direction: top;   --border-color: #333;   --border-width: 2;   color: #fff; } </style>

Here’s a demo! Go ahead and play around with variables!

CSS Houdini opens a door to modularized, configurable styles sharing. I look forward to seeing developers using and sharing CSS Houdini worklets. I’m trying to add more useful examples of Houdini usage. Ping me if you have ideas, or want to contribute to this repo.

The post CSS Houdini Could Change the Way We Write and Manage CSS appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

A Gutenburg-Powered Newsletter

I like Gutenberg, the new WordPress editor. I’m not oblivious to all the conversation around accessibility, UX, and readiness, but I know how hard it is to ship software and I’m glad WordPress got it out the door. Now it can evolve for the better.

I see a lot of benefit to block-based editors. Some of my favorite editors that I use every day, Notion and Dropbox Paper, are block-based in their own ways and I find it effective. In the CMS context, even moreso. Add the fact that these aren’t just souped-up text blocks, but can be anything! Every block is it’s own little configurable world, outputting anything it needs to.

I’m using Gutenberg on a number of sites, including my personal site and my rambling email site, where the content is pretty basic. On a decade+ old website like CSS-Tricks though, we need to baby step it. One of our first steps was moving our newsletter authoring into a Gutenberg setup. Here’s how we’re doing that.

Gutenberg Ramp

Gutenberg Ramp is a plugin with the purpose of turning Gutenberg on for some areas and not for others. In our case, I wanted to turn on Gutenberg just for newsletters, which is a Custom Post Type on our site. With the plugin installed and activated, I can do this now in our functions.php:

if (function_exists('gutenberg_ramp_load_gutenberg')) {   gutenberg_ramp_load_gutenberg(['post_types' => [ 'newsletters' ]]); }

Which works great:

Classic editor for posts, Gutenberg for the Newsletters Custom Post Type

We already have 100+ newsletters in there, so I was hoping to only flip on Gutenberg over a certain date or ID, but I haven’t quite gotten there yet. I did open an issue.

What we were doing before: pasting in HTML email gibberish

We ultimately send out the email from MailChimp. So when we first started hand-crafting our email newsletter, we made a template in MailChimp and did our authoring right in MailChimp:

The MailChimp Editor

Nothing terrible about that, I just much prefer when we keep the clean, authored content in our own database. Even the old way, we ultimately did get it into our database, but we did it in a rather janky way. After sending out the email, we’d take the HTML output from MailChimp and copy-paste dump it into our Newsletter Custom Post Type.

That’s good in a way: we have the content! But the content is so junked up we can basically never do anything with it other than display it in an <iframe> as the content is 100% bundled up in HTML email gibberish.

Now we can author cleanly in Gutenberg

I’d argue that the writing experience here is similar (MailChimp is kind of a block editor too), but nicer than doing it directly in MailChimp. It’s so fast to make headers, lists, blockquotes, separators, drag and drop images… blocks that are the staple of our newsletter.

Displaying the newsletter

I like having a permanent URL for each edition of the newsletter. I like that the delivery mechanism is email primarily, but ultimately these are written words that I’d like to be a part of the site. That means if people don’t like email, they can still read it. There is SEO value. I can link to them as needed. It just feels right for a site like ours that is a publication.

Now that we’re authoring right on the site, I can output <?php the_content() ?> in a WordPress loop just like any other post or page and get clean output.

But… we have that “old” vs. “new” problem in that old newsletters are HTML dumps, and new newsletters are Gutenberg. Fortunately this wasn’t too big of a problem, as I know exactly when the switch happened, so I can display them in different ways according to the ID. In my `single-newsletters.php`:

<?php if (get_the_ID() > 283082) { ?>    <main class="single-newsletter on-light">     <article class="article-content">       <h1>CSS-Tricks Newsletter #<?php the_title(); ?></h1>       <?php the_content() ?>     </article>   </main>    <?php } else { // Classic Mailchimp HTML dump ?>    <div class="newsletter-iframe-wrap">     <iframe class="newsletter-iframe" srcdoc="<?php echo htmlspecialchars(get_the_content()); ?>"></iframe>   </div>  <?php } ?>

At the moment, the primary way we display the newsletters is in a little faux phone UI on the newsletters page, and it handles both just fine:

Old and new newsletters display equally well, it’s just the old newsletters need to be iframed and I don’t have as much design control.

So how do they actually get sent out?

Since we aren’t creating the newsletters inside MailChimp anymore, did we have to find another way to send them out? Nope! MailChimp can send out a newsletter based on an RSS feed.

And WordPress is great at coughing up RSS feeds for Custom Post Yypes. You can do…

/feed/?post_type=your-custom-post-type

But… for us, I wanted to make sure that any of those old HTML dump emails never ended up in this RSS feed, so that the new MailChimp RSS feed would never see them an accidentally send them. So I ended up making a special Page Template that outputs a custom RSS feed. I figured that would give us ultimate control over it if we ever need it for even more things.

<?php /* Template Name: RSS Newsletterss */  the_post(); $ id = get_post_meta($ post->ID, 'parent_page_feed_id', true);  $ args = array(   'showposts' => 5,   'post_type'  => 'newsletters',   'post_status' => 'publish',   'date_query' => array(      array(       'after'     => 'February 19th, 2019'     )   ) );  $ posts = query_posts($ args);  header('Content-Type: '.feed_content_type('rss-http').'; charset='.get_option('blog_charset'), true); echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>  <rss version="2.0"   xmlns:content="http://purl.org/rss/1.0/modules/content/"   xmlns:wfw="http://wellformedweb.org/CommentAPI/"   xmlns:dc="http://purl.org/dc/elements/1.1/"   xmlns:atom="http://www.w3.org/2005/Atom"   xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"   <?php do_action('rss2_ns'); ?>>  <channel>   <title>CSS-Tricks Newsletters RSS Feed</title>   <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />   <link><?php bloginfo_rss('url') ?></link>   <description><?php bloginfo_rss("description") ?></description>   <lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>   <language><?php echo get_option('rss_language'); ?></language>   <sy:updatePeriod><?php echo apply_filters( 'rss_update_period', 'hourly' ); ?></sy:updatePeriod>   <sy:updateFrequency><?php echo apply_filters( 'rss_update_frequency', '1' ); ?></sy:updateFrequency>    <?php do_action('rss2_head'); ?>    <?php while( have_posts()) : the_post(); ?>      <item>       <title><?php the_title_rss(); ?></title>       <link><?php the_permalink_rss(); ?></link>       <comments><?php comments_link(); ?></comments>       <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_post_time('Y-m-d H:i:s', true), false); ?></pubDate>       <dc:creator><?php the_author(); ?></dc:creator>   <?php the_category_rss(); ?>       <guid isPermaLink="false"><?php the_guid(); ?></guid>        <description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>        <content:encoded><![CDATA[<?php the_content(); ?>]]></content:encoded>        <wfw:commentRss><?php echo get_post_comments_feed_link(); ?></wfw:commentRss>       <slash:comments><?php echo get_comments_number(); ?></slash:comments>        <?php rss_enclosure(); ?>       <?php do_action('rss2_item'); ?>      </item>    <?php endwhile; ?>  </channel>  </rss>

Styling…

With a MailChimp RSS campaign, you still have control over the outside template like any other campaign:

But then content from the feed just kinda gets dumped in there. Fortunately, their preview tool does go grab content for you so you can actually see what it will look like:

And then you can style that by injecting a <style> block into the editor area yourself.

That gives us all the design control we need over the email, and it’s nicely independent of how we might choose to style it on the site itself.

The post A Gutenburg-Powered Newsletter appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

Jetpack Gutenberg Blocks

I remember when Gutenberg was released into core, because I was at WordCamp US that day. A number of months have gone by now, so I imagine more and more of us on WordPress sites have dipped our toes into it. I just wrote about our first foray here on CSS-Tricks and using Gutenberg to power our newsletter.

Jetpack, of course, was ahead of the game. Jetpack adds a bunch of special, powerful blocks to Gutenberg that it’s easy to see how useful they can be.

Here they are, as of this writing:

Maps! Subscriptions! GIFs! There are so many good ones. Here’s a look at a few more:

The form widget, I hear, is the most popular.

You get a pretty powerful form builder right within your editor:

Instant Markdown Processing

Jetpack has always enabled Markdown support for WordPress, so it’s nice that there is a Markdown widget!

PayPal Selling Blocks

There is even basic eCommerce blocks, which I just love as you can imagine how empowering that could be for some folks.

You can read more about Jetpack-specific Gutenberg blocks in their releases that went out for 6.8 and 6.9. Here at CSS-Tricks, we use a bunch of Jetpack features.

The post Jetpack Gutenberg Blocks appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

5 Watch design trends we’re seeing in 2019

[Top]