Gutenberg 9.0 Brings Major Improvements to Navigation Screen and Query Block

If you haven’t played around with Gutenberg’s experiments lately, the Navigation block is getting some exciting updates. Version 9.0 was released today with drag-and-drop support added to the list view of navigation items.

Contributors have been working through several different prototypes aimed at unifying the controls and simplifying the menu building process. The Navigation screen included in version 9.0 has been redesigned to improve the “Create Menu” flow and includes the following changes:

  • New Header and Toolbar components.
  • Manage Locations has been rewritten and is now a popover.
  • Add New form has been rewritten and now appears inline in the toolbar.
  • Automatically Add Pages checkbox and Delete menu button has been rewritten and now appears in the block inspector.

The screen is starting to take shape but is still very much a work in progress. If you want to test it, you can enable it under Gutenberg > Experiments.

The Query block was another main focus fr the 9.0 release. It is taking a giant leap forward with new features like search, filtering by author, support for order/order by (date + title), and tags. This block should be tested locally and is still behind the __experimentalEnableFullSiteEditing flag since it requires full site editing blocks to display queried content.

Other notable UI enhancements include a new drag handle added to block toolbar for drag-and-drop capability. (It is not visible on the top toolbar). Blocks can be dragged to other areas of a post as an alternative to using the up/down arrows.

This release also removes the Facebook and Instagram blocks from the inserter, as Facebook will be dropping unauthenticated oEmbed support on October 24. WordPress core is also set to remove Facebook and Instagram as an oEmbed provider in an upcoming release.

For a full list of all the enhancements, bug fixes, experiments, and documentation updates, check out the 9.0 release post on WordPress.org.

Weaved Webs

There is a bit of an irony with Jamstack.

The concept is simple: you put pre-rendered, static files on web hosting (a CDN) designed to do that well. That’s it. If you need to do more, anything you do from there is done with client-side JavaScript, which is likely talking to serverless functions because that’s the spiritual partner to Jamstack on the back end. I heard Guillermo Rauch say at Smashing Conf the other day that it isn’t exactly a “stack” in that it’s almost entirely non-prescriptive in what you do. While I like the word Jamstack, that also feels fair.

The irony is that while the concept is simple, that simplicity can be the cause of complexity.

Netlify, the company largely behind Jamstack, knows this. They know that without a back-end server with back-end languages, something like a basic contact form gets complicated. Instead of being in no-brainer solved-problem territory, we have to figure out another way to process that form. So, they solve that problem for you (among others, like auth and serverless functions). But there are tons of other companies that want to be that cog in your machine.

That’s just one potential complication. What do you use for a CMS or other data storage? What is your build process like? How do you see previews of content changes? How do you do auth? What if you need some fancy calendar widget? What if you want to sell something? Anything a website can do, Jamstack has an answer for — it’s just that combining all those answers can feel disjointed and potentially confusing.

Dave recently played with Eleventy + Tailwind + Netlify CMS (which is Jamstack-y) and said it felt like cattle herding:

So my little mashup, which was supposed to be just 3 technologies ended up exposing me to ~20 different technologies and had me digging into nth-level dependency source code after midnight. If there’s an allegory for what I don’t like about modern-day web development, this is it. You want to use three tools, but you have to know how to use twenty tools instead. If modules and components are like LEGO, then this is dumping out the entire bin on the floor just to find one tiny piece you need.

“The tangled webs we weave,” indeed.

In a conversation between Richard MacManus and Matt Mullenweg¹, Richard quotes Matt:

You can patch together a dozen services, each with its own account and billing, for hundreds of dollars a month, to get a similar result you’d have for a few dollars a month using WordPress on shared hosting,” he said. “And it would be more fragile, because the chain is only as strong as its weakest link. You are chaining together different toolsets, logins, billing, hosting… any part of it going down can break the entire flow.

If I was considering Jamstack for a particular project, and the grand total really was twelve services, I probably would reconsider, particularly if I could reach for a tool like WordPress and bring it down to one. There are plenty of other fair criticisms of Jamstack, particularly since it is early-days. The story of “CMS with Preview” isn’t particularly great, for example, which is a feature you don’t even think about with WordPress because, duh, obviously it has that.

And Jamstack can do some things that are very ahead of the game that I cherish. Git-based deployment? All websites should have that. Previews of my pull requests? Hot damn. Sub -100-millisecond first requests? Yes please. Not having to diddle with cache? Sweet. Catch up, other stacks.

I’m saying there are baby bear choices to be made here. You get there by doing what you’re probably already doing anyway: putting your adult pants on, thinking about what your project needs, and choosing the best option.

I have production WordPress sites. Like this one! It’s great!

I have production Jamstack sites. Like this one! It’s not a complicated web of services. It’s a static site generator with content in the GitHub repo deployed with Netlify. While CSS-Tricks can do about 100 things that this site can’t, it has a few tricks up its sleeve that CSS-Tricks can’t do, like accept pull requests on content.

I feel like I’ve chosen pretty well in all my cases.

  1. While Matt is clearly incentivized to defend the WordPress approach, it feels to me the opinions here are genuine; in part because Automattic invests in alternative stack approaches, and that WordPress and Jamstack are not mutually exclusive. I enjoyed responses to this, like Ohad Eder-Pressman’s open letter, which is also full of incentivized-but-genuine thoughts.


The post Weaved Webs appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

19 Trippy & Glitchy CSS Distortion Effects

Sometimes a cool glitchy, distorted effect is the perfect addition to your web design. Maybe you’re creating a tech site, a developer’s portfolio, or something completely experimental. Distortion effects are an unconventional but interesting way to grab visitors’ attention with a unique animation. We’ve collected some glitchy CSS effects for you to use today. They’re free to copy or study as a learning tool, and they range from text and image glitch effects to hover distortions to trippy background animations. Whatever you’re looking for, one of these effects has the inspiration you need.

Your Web Designer Toolbox

Unlimited Downloads: 500,000+ Web Templates, Icon Sets, Themes & Design Assets
Starting at only $16.50/month!


Pure CSS Glitch Effect

See the Pen Pure CSS Glitch Effect by Felix Rilling (@FelixRilling) on CodePen.dark

CodePen Challenge: Color Pop

See the Pen CodePen Challenge: Color Pop by Johan Lagerqvist (@lgrqvst) on CodePen.dark

Trippy CSS Effect

See the Pen Trippy CSS effect by kryo (@kryo2k) on CodePen.dark

Glitch Photo Filters CSS

See the Pen Glitch Photo Filters CSS by Sergey (@canti23) on CodePen.dark

Perspective Split Text Menu Hover

See the Pen Perspective Split Text Menu Hover by James Bosworth (@bosworthco) on CodePen.dark

Clean CSS Glitch

See the Pen Clean CSS Glitch by Piotr Galor (@pgalor) on CodePen.dark

Creepy Squiggly Text Effect with SVG

glitchy CSS effects - Example of Creepy Squiggly Text Effect with SVG

Text Shuffle & Distort

See the Pen Text shuffle & distort fx by Blaz Kemperle (@blazicke) on CodePen.dark

Glitch CSS

See the Pen Glitch CSS by Iliuta Stoica (@iliutastoica) on CodePen.dark

Infinite SVG Triangle Fusion

See the Pen Infinite SVG Triangle Fusion by Rob DiMarzo (@robdimarzo) on CodePen.dark

Glitch Effect in CSS

See the Pen Glitch effect in CSS by Thomas Aufresne (@origine) on CodePen.dark

Buttons with Trippy Background Animation on Hover

glitchy CSS effects - Example of Buttons with Trippy Background Animation on Hover

Trippy – CSS only

See the Pen Trippy – CSS only by Emmanuel Lainas (@RedGlove) on CodePen.dark

Laser Text Animation

Example of Laser Text Animation

Glitch Text

See the Pen Glitch Text by Chase (@chasebank) on CodePen.dark

Oddly Satisfying CSS Only Triangle Animation

See the Pen Oddly satisfying CSS Only triangle animation by eight (@eight) on CodePen.dark

Paint on Heat Distortion

See the Pen Paint on Heat Distortion by Matt Popovich (@mattpopovich) on CodePen.dark

Trippy Squares – Left to Right Wave

See the Pen Trippy Squares – Left to Right Wave! by Praveen Puglia (@praveenpuglia) on CodePen.dark

Glitch Clock

See the Pen Glitch Clock by Konstantin (@fearOfCode) on CodePen.dark

Glitchy and Psychedelic CSS Effects

There’s something simply awesome about an unusual distortion effect. Using them correctly can help you make an awesome website that people will love to explore. Too much distortion can be an eyestrain, but a cool trippy background animation or some glitchy text can pull the whole design together.

You also should be careful with implementing too many CSS effects onto your website. Too many animations can lead to a slowdown. If you find your website loading slowly, this guide can help you cut down on bloat and let you keep your awesome new effects.

Next time you’re making a dark website, a site with tech or programming focus, or a page you want to be unconventional and unique, try out one of these free glitchy CSS effects. You’ll love the character it can bring to a design.

How to Create High-performance, Scalable Content Websites Using MACH Technologies

Websites are easy to build these days. There is an abundance of tools available that let you create websites in minutes. However, building websites that are fast, scalable, and flexible that deliver superior performance is a lot more complex than creating a simple website. This is especially true when developing content-heavy websites, such as a news site, knowledge-base platform, online magazine, communities, and so on.

get selection into POST

New to this forum and to programming in PHP, so apologies if I miss some detail.

I have found some code which does almost everything I need, but I can't figure out how to get the 'selected item' from the results on an secondary page (reading in post) ..

this properly retrieves a list of names from a sql table and populates a select list, and two input boxes

<div id="ifNew" style="display:none" >
            <form name = "form2" action="../Form/modified.php" method = "post" enctype = "multipart/form-data">     
            <div class = "form_data1">    

                     <?php

                     $stmt = sqlsrv_query( $conn,$tsql );
                     if( $stmt === false) {    die( print_r( sqlsrv_errors(), true) );}
                            echo "<select id=''nm'' name=''Name''>";
                                while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) 
                                    {       echo "<option value='" . $row['Name']. "'>" . $row['Name'] . "</option>"; 
                                    }
                                    echo "</select>"; 


                    sqlsrv_free_stmt($stmt);?>  

                     <input type = "text" name = "group" value = "" size = "30" required/><label> :Group</label> <br>
                     <input type = "text" name = "btype" value = "" size = "30" required/><label> :Type</label><br>
                     <input type = "submit" />
            </form>
                </div>              
            </div>  
        </div>

        What I am struggling with is how to retrieve the selected item from the name list and populate a variable

        modified.php
        <?php
$group = $_POST['group'];
$btype = $_POST['btype'];
$name = $_POST['name'];
?>

while the first two are popuated (group and btype), the name is not, and i receive an error
Notice: Undefined index: name in C:\inetpub\wwwroot\testWeb\Form\modified.php on line 4

please help

#284: Settings Redesign (Part 2)

Show Description

Klare, Dee, and Marie chat about the process behind redesigning the settings pages inside CodePen – how decisions were made, adding helper text to various locations, and designing React components to reuse.

Time Jumps

  • 01:24 What was the process behind the design?
  • 09:55 Context switching
  • 17:13 Adding helper text
  • 19:24 Sponsor: imgix
  • 20:50 Designing React components

Sponsor: imgix 19:24

imgix is the API for fast, responsive, beautifully optimized images.

Your images create complex challenges with web performance, user experience, conversion rates, SEO, and responsive design. Our APIs solve them.

Visit imgix.com/codepen and signup to receive a $300 account credit.

Show Links

CodePen Links

The post #284: Settings Redesign (Part 2) appeared first on CodePen Blog.

Menu to Inner Page Animation with Image Grid Background

Today I have a little layout for you. The idea is to show a menu with a nice background grid of images and when choosing to explore a project, an animation happens where the images of the background grid fly away and an inner page shows.

This kind of layout is interesting for a photography portfolio or some other project presentation.

I hope you like this little layout and find it useful!

The post Menu to Inner Page Animation with Image Grid Background appeared first on Codrops.

Lessons Learned from Sixty Days of Re-Animating Zombies with Hand-Coded CSS

Caution: Terrible sense of humor ahead. We’ll talk about practical stuff, but the examples pretty much all involve zombies and silly jokes. You have been warned.

I’ll be linking to individual Pens as I discuss the lessons I learned, but if you’d like to get a sense of the entire project, check out 60 days of Animation on Undead Institute. I started this project to end on August 1st, 2020, coinciding with the publication of a book I wrote featuring CSS animation, humor, and zombies — because, obviously, zombies will destroy the world if you don’t brandish your web skills and stop the apocalypse. Nothing puts the hurt on the horde like a HTML element on the move!

I had a few rules for myself throughout the project. 

  1. I would hand-code all CSS. (I’m a masochist.)
  2. The user would initiate all of the animation. (I hate coming upon an animation that’s already halfway through.) 
  3. I would use JavaScript as little as possible and never for animation. (I only ended up using JavaScript once, and that was to start audio with the final animation. I have nothing against JavaScript, it’s just not what I wanted to do here.)

Lesson 1: Eighty days is a long time.

Uh, doesn’t the title say “sixty” days? Yes, but my original goal was to do eighty days and as day one approached with less than twenty animations prepared and a three day average for each production, I freaked out and switched to sixty days. That gave me both twenty more days till the beginning date and twenty fewer pieces to do.

Lesson 1A: Sixty days is still a long time.

That’s a lot of animation to do with a limited amount of time, ideas, and even more limited artistic skills. And while I thought of dropping to thirty days, I’m glad I didn’t. Sixty days stretched me and forced me to go deeper into how CSS animation — and by extension, CSS itself — works. I’m also proudest of many of the later pieces I did as my skills increased, and I had to be more innovative and think harder about how to make things interesting. Once you’ve used all the easy options, the actual work and best results begin. (And yes, it ended up being sixty-two days because I started on June 1 and wanted to do a final animation on August 1. Starting June 3 just felt icky and wrong.)

So, the real Lesson 1: stretch yourself.

Lesson 2: Interactive animations are hard, and even harder to make responsive. 

If you want something to fly across the screen and connect with another element or appear to start another element’s move, you must use either all standard, inflexible units or all flexible units. 

Three variables determine when and where an animated element will be during any animation: duration, velocity, and distance. The duration of the animation is set in the animation property and cannot be changed in relation to screen size. The animation timing function determines the velocity; screen size can’t change that either. Thus, if the distance varies with the screen size, the timing will be off everywhere except a specific screen width and height. 

Look at Tank!. Run the animation at wide and narrow screen sizes. While I got the timing close, if you compare the two, you’ll see that the tank is in a different place relative to the zombies when the last zombies fall.

Showing the same brown take, side by side, where the tank on the left is further along than the tank on the right.

To avoid these timing issues, you can use fixed units and a large number, like 2000 or 5000 pixels or more, so that the animation will cover the width (or height) of the screen for all but the largest monitors.  

Lesson 3: If you want a responsive animation, put everything in (one of the) viewport units. 

Going halfsies on unit proportions (e.g. setting width and height in pixels, but location and movement with viewport units) will lead to unpredictable results. Don’t use both vw and vh either but one or the other; whichever will be the dominant orientation. Mixing vh and vw units will make your animation go “wonky” which I believe is the technical term. 

Take Superbly Zomborrific, for instance. It mixes pixel, vw, and vh units. The premise is that the Super Zombie is flying upward as the “camera” follows. Super Zombie smashes into a ledge and falls as the camera continues, but you wouldn’t understand that if your screen was sufficiently tall.

Two animation frames, side by side where the left shows the flying green zombie hitting a building ceiling and the right shows the zombie leaving the frame after impact.

That also means that if you need something to come in from the top — like I did in Nobody Here But Us Humans —you must set the vw height high enough to ensure that the ninja zombie isn’t visible at most aspect ratios.

Lesson 3A: Use pixel units for movements within an SVG element. 

All that said, transforming elements within an SVG element should not use viewport units. SVG tags are their own proportional universe. The SVG “pixel” will stay proportional within the SVG element to all the other SVG element children while viewport units will not. So transform with pixel units within an SVG element, but use viewport units everywhere else.

Lesson 4: SVGs scale horribly at runtime.

For animations, like Oops…, I made the SVG image of the zombie scale up to five times his size, but that makes the edges fuzzy. [Shakes fist at “scalable” vector graphics.]

/* Original code resulting in fuzzy edges */
.zombie {
  transform: scale(1);
  width: 15vw;
}

.toggle-checkbox:checked ~ .zombie {
  animation: 5s ease-in-out 0s reverseshrinkydink forwards;
}

@keyframes reverseshrinkydink {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(5);
  }
}

I learned to set their dimensions to the final dimensions that would be in effect at the end of the animation, then use a scale transform to shrink them down to the size for the start of the animation. 

/* Revised code */
.zombie {
  transform: scale(0.2);
  width: 75vw;
}

.toggle-checkbox:checked ~ .zombie {
  animation: 5s ease-in-out 0s reverseshrinkydink forwards;
}

@keyframes reverseshrinkydink {
  0% {
    transform: scale(0.2);
  }
  100% {
    transform: scale(1);
  }
}

In short, the revised code moves from a scaled-down version of the image up to the full width and height. The browser always renders at 1, making the edges crisp and clean at a scale of 1. So instead of scaling from 1 to 5, I scaled from 0.2 to 1.

The same animation frame of a scientist holding a coffee mug standing to the left of a growing zombie where the frame on the left shows the zombie with blurry edges and the frame on the right is clear.

Lesson 5: The axis Isn’t a universal truth. 

An element’s axes stay in sync with the element, not the page. A 90-degree rotation before a translateX will change the direction of the translateX from horizontal to vertical. In Nobody Here But Us Humans… 2, I flipped the zombies using a 180-degree rotation. But positive Y values move the ninjas towards the top, and negative ones move them towards the bottom (the opposite of normal). Beware of how a rotation may affect transforms further down the line.

Showing the main character facing us in the foreground with 7 ninja characters hanging upside down from the ceiling against a light pink background.

Lesson 6. Separate complex animations into concentric elements to make easier adjustments.

When creating a complex animation that moves in multiple directions, adding wrapper divs, or rather parent elements, and animating each one individually will cut down on conflicting transforms, and prevent you from becoming a weepy mess.

For instance, in Space Cadet, I had three different transforms going on. The first is the zomb-o-naut’s moving in an up and down motion. The second is a movement across the screen. The third is a rotation. Rather than trying to do everything in a single transform, I added two wrapping elements and did one animation on each element (I also saved my hair… at least some of it.) This helped avoid the axis issues discussed in the last lesson because I performed the rotation on the innermost element, leaving its parent’s and grandparent’s axes in place.

Lesson 7: SVG and CSS transforms are the same. 

Some paths and groups and other SVG elements will already have transforms defined on them. It could be from an optimization algorithm, or perhaps it’s just how the illustration software generates the code. If a path, group, or whatever element in an SVG already has an SVG transform on it, removing that transform will reset the element, often to a bizarre location or size compared to the rest of the drawing. 

Since SVG and CSS transforms are the same, any CSS transform you do replaces the SVG transform, meaning your CSS transform will start from that bizarre location or size rather than the location or size that is set in the the SVG.

You can copy the transform from the SVG element to your CSS and set it as the starting position in CSS (updating it to the CSS syntax first, of course). You can then modify it in your CSS animation.

For instance, in Uhhh, Yeah…, my tribute to Office Space, Undead Lumbergh’s right upper arm (the #arm2 element) had a transform on it in the original SVG code.

<path id="arm2" fill="#91c1a3" fill-rule="nonzero" d="M0 171h9v9H0z" transform="translate(0 -343) scale(4 3.55)"/>
A side by side comparison of a zombie dressed in a blue button-up shirt and black suspenders while holding a coffee cup. On the left, the arm holding the coffee mugs the the correct position but the right shows the arm detached from the body.

Moving that transform to CSS like this:

<path id="arm2" fill="#91c1a3" fill-rule="nonzero" d="M0 171h9v9H0z"/>
#arm2 {
  transform: translate(0, -343px) scale(4, 3.55);
}

…I could then create an animation that doesn’t accidentally reset the location and scale:

.toggle-checkbox:checked ~ .z #arm2 { 
  animation: 6s ease-in-out 0.15s arm2move forwards;
}

@keyframes arm2move {
  0%, 100% {
    transform: translate(0, -343px) scale(4, 3.55);
  }
  40%, 60% {
    transform: translate(0, -403px) scale(4, 3.55);
  }
  50% {
    transform: translate(0, -408px) scale(4, 3.55);
  }
} 

This process is harder when the tool generating the SVG code attempts to “simplify” the transform into a matrix. While you can recreate the matrix transform by copying it into the CSS, it is a difficult task to do. You’re a better developer than me — which might be true anyway — if you can take a matrix transform and manipulate it to scale, rotate, or translate in the exact way you want.

Alternatively, you can recreate the matrix transform using translation, rotation, and scaling, but if the path is complex, the likelihood that you can recreate it in a timely manner without finding yourself in a straight jacket is low. 

The last and probably easiest option is to wrap the element in a group (<g>) tag. Add a class or ID to it for easy CSS access and transform the group itself, thus separating out the transforms as discussed in the last lesson. 

Lesson 8: Keep your sanity by using transform-origin when transforming part of an SVG

The CSS transform-origin property moves the point around which the transform happens. If you’re trying to rotate an arm — like I did in Clubbin’ It —  your animation will look more natural if you rotate the arm from the center of the shoulder, but that path’s natural transform origin is in the upper-left. Use transform-origin to fix this for smoother, more natural feel… you know that really natural pixel art look…

Four sequential frames of an animation showing a caveman character facing left, holding a large wooden club, and raising it up from the bottom to behind his head.

Transforming the origin can also be useful when scaling, like I did in Mustachioed Oops, or when rotating mouth movements, such as the dinosaur’s jaw in Super Tasty. If you don’t change the origin, the transforms will use an origin point at the upper left corner of the SVG element. 

Lesson 9: Sprite animations can be responsive

I ended up doing a lot of sprite animations for this project (i.e., where you use multiple, incremental frames and switch between them fast enough that the characters seem to move). I created the images in one wide file, added them as a background image to an element the size of a single frame, used background-size to set the background image to the width of the image, and hid the overflow. Then I used background-position and the animation timing function, step(), to walk through the images; for example: Post-Apocalyptic Celebrations.

Before the project, I always used inflexible images. I’d scale things down a little so that there would be at least a little responsive give, but I didn’t think you could make it a fully flexible width. However, if you use SVG as the background image you can then use viewport units to scale the element along with the changing screen size. The only problem is the background position. However, if you use viewport units for that, it will stay in sync. Check that out in Finally, Alone with my Sandwich…

Lesson 9A: Use viewport units to set the background size of an image when creating responsive sprite animation

As I’ve learned throughout this project, using a single type of unit  is almost always the way to go. Initially, I’d set my sprite’s background size using percentages. The math was easy (100% * (number of steps + 1)) and it worked fine in most cases. In longer animations, however, the exact frame tracking could be off and parts of the wrong sprite frame might display. The problem grows as more frames are added to the sprite. 

I’m not sure the exact reason this causes an issue, but I believe it’s because of rounding errors that compound over the length of the sprite sheet (the amount of the shift increases with the number of frames). 

For my final animation, It Ain’t Over Till the Zombie Sings, I had a dinosaur open his mouth to reveal a zombie Viking singing (while lasers fired in the background plus there was dancing, accordions playing and zombies fired from cannons, of course). Yeah, I know how to throw a party… a nerd party.

The dinosaur and viking was one of the longest sprite animations I did for the project. But when I used percentages to set the background size, the tracking would be off at certain sizes in Safari. By the end of the animation, part of the dinosaur’s nose from a different frame would appear to the right and a similar part of the nose would be missing on the left.

A large green dinosaur behind a crowd of people, all facing and looking forward.
The dinosaur on the left is missing part of his left cheek and growing a new one next to his right cheek.

This was super frustrating to diagnose because it seemed to work fine in Chrome and I’d think I fixed it in Safari only to look at a slightly different screen size and see the frame off again. However, if I used consistent units — i.e. vw for background-size, frame width, and background-position — everything worked fine. Again, it comes down to working with consistent units!

Lesson 10: Invite people into the project.

A crowd of 32 pixel-art characters from the previous demos facing the screen.

While I learned tons of things during this process, I beat my head against the wall for most of it (often until the wall broke or my head did… I can’t tell). While that’s one way to do it, even if you’re hard-headed, you’ll still end up with a headache. Invite others into your project, be it for advice, to point out an obvious blind spot you missed, provide feedback, help with the project, or simply to encourage you to keep going when the scope is stupidly and arbitrarily large. 

So let me put this lesson into practice. What are your thoughts? How will you stop the zombie hordes with CSS animation? What stupidly and arbitrarily large project will you take on to stretch yourself?


The post Lessons Learned from Sixty Days of Re-Animating Zombies with Hand-Coded CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Inclusive Design 24

Totally free.

No sign-up. No registration. All sessions are streamed live and publicly on the Inclusive Design 24 YouTube channel – see the entire playlist for the event.

Quite the lineup.

I’ve got a couple of other accessibility links burning a hole in my pocket as well:

Direct Link to ArticlePermalink


The post Inclusive Design 24 appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Editing HTML Like A Boss In VS Code

Here’s a seven minute video from Caleb Porzio that focuses on some of Emmet‘s HTML editing features. You might think of Emmet as that thing that expands abbreviations like table.stats>tr*3>td*3 into glorious, expanded, and perfect HTML. But Emmet has other HTML editing trickery up its sleeve. My favorite is “wrap with abbreviation” (which happens to be Cmd/Ctrl + Shift + A on CodePen), but there are more, like expanding your selection inward and outward and tag changing.

If you haven’t seen it, the Emmet 2 preview on CodePen is pretty neeeeat. It shows you what you’re about to expand into before you do it:

Direct Link to ArticlePermalink


The post Editing HTML Like A Boss In VS Code appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

10 Open Source Fonts That Are Actually Amazing | Free Fonts 2020

free fonts 2020 manrope

There’s nothing like creating an amazing design that your client loves, while also saving some money in the process.

You don’t have to compromise on the quality of the fonts you choose, just because you’re not paying the big bucks for them.

Better yet, why pay for fonts at all when there are some really great ones out there that are ready for you to use for free?

10 Free Fonts That’ll Change Your Life

I’m going to introduce you to your new best friends, aka 10 open source fonts that’ll spice up all your designs in 2020.

You ready to do this? Cause I am.

Let’s jump right into it.

1. Manrope

We’re going to start today’s list of 10 free fonts with Manrope.

I’ve mentions this font before, but that’s only because it’s my all time favorite.

It’s modern, it’s sleek, it’s everything you want in a free font.

It’s versatility is what really hits home for me and that’s why I recommend that you start incorporating it into all your new designs.

2. Inter

You might’ve seen Inter take a step into the scene as of recent, and I truly believe it’s here to stay.

Inter has become a staple font for many, so don’t be the exception! Add this font to your collection and start adding it to your design projects right away.

3. Public Sans

I can’t lie, I love a good sans serif font.

But what’s special about this font is that it was developed for the US government and is all over their websites and is a huge part of their design.

It looks very similar to another open-source font that you may know of, Libre Franklin.

4. Alice

It’s time to step away from the sans serif, and into the serifs.

When I saw the type-face Alice, I knew it was going to have a new and special spot in my font collection.

Alice is a very unique serif font, which seems kinda old-fashioned, but at the same time, pretty modern.

You can find this font on Google-fonts!

5. Urbanist

Another one of my all time favorite free fonts is Urbanist.

This geometric sans serif is most definitely a modern font that can be used in a variety of different projects.

From logos, to headlines, this font is perfect to add to your colelction of fonts.

What are you waiting for? Go and download it now!

6. Evolventa

Were you surprised when you saw another modern sans serif?

Me either.

Evolventa is a Cyrillic extension of the open-source URW Gothic L font family.

7. Object Sans

If this font isn’t eye-catching, I don’t know what is.

If you’re looking for the perfect combination of Swiss neo-grotesks and geometric fonts, then Object Sans is the one for you.

This font is perfect to replace any of those pricey fonts, because it looks just as good as the rest of them.

8. Lunchtype

I love a good back-story to any font that I use, and Lunchtype has one of the best.

The designer who created this font created it during a lunch break on 100-day project.

We love a good lunch-break, and I can’t deny that that’s when some of my best ideas come to me.

Food is life, and so is an amazing font.

9. Work Sans

What’s cuter than a good font and a hedgehog?

I’ll answer that for you.

nothing.

Absolutely nothing.

10. Monoid

And finally, we’ve come to our last free font, which is Monoid.

Monoid is another great font that we know you’ll love and be using on the daily, if you code.

“The clever thing about Monoid is that it has font-awesome built into it, which they call Monoisome. This means when writing code, you can pop a few icons in there easily. Monoid looks just as great when you’re after highly readable website body text.”

Let us know in the comments which font was your favorite of this list and which ones you’ll be incoporating into your daily design life.

Until next time,

Stay creative folks!

Read More at 10 Open Source Fonts That Are Actually Amazing | Free Fonts 2020

Advanced GraphQL Usage In Gatsby Websites

Before the release of GraphQL in 2015, Representational State Transfer (REST) was the main way to interface with an API. The introduction of GraphQL was therefore a major change in software development.

As a modern static site generator, Gatsby leverages GraphQL to provide a concise methodology for bringing in and manipulating data into the framework. In this article, we will take a closer look at GraphQL and how we can integrate it into a Gatsby website by building and implementing advanced data sourcing and transformation in Gatsby. The result is a publisher’s blog that could be used by any publishing firm to share content of their authors.

What Is GraphQL?

Going by the _QL_ in its name, GraphQL is a query language combined with a set of tools created to provide flexibility and efficiency in the way we pull data from a source. With GraphQL, a client/consumer can request exactly the data it requires. The server/provider responds with a JSON response signature matching the requirements specified in the query. It allows us to express our data needs declaratively.

Why Use GraphQL?

As a static site generator, Gatsby stores static files, which makes querying data close to impossible. There are often page components that have to be dynamic like the single blog post page, so the need to pull data from a source and transform it to the needed format would arise, just like having blog posts stored in markdown files. Some plugins provide data from various sources, which leaves you with querying and transforming the required data from a source.

According to a list on gatsby.org, GraphQL is useful in Gatsby to:

  • Eliminate boilerplate
  • Push frontend complexities into queries
  • Provide a perfect solution for the always complex data of a modern-day application
  • Finally, to remove code bloat, thereby improving performance.

GraphQL Concepts

Gatsby maintains the same ideas of GraphQL as widely used; some of these concepts are:

Schema Definition Language

GraphQL SDL is a type system incorporated into GraphQL, and you can use it to create new types for your data.

We can declare a type for a country, and its attributes could include a name, continent, population, gdp and number of states.

As an example below, we have created a new type with the name of Aleem. It has hobbies which is an array of strings and are not required, but country, marital status, and posts are needed due to the ! they include, also posts references another type, Post.

type Authors {
  name: String!,
  hobbies: [String]
  country: String!
  married: Boolean!
  posts: [Post!]
}

type Post {
  title: String!
  body: String!
}

type Query {
  author: Author
}

schema {
  query: Query
}

Queries

We can use Queries to pull data from a GraphQL source.

Considering a data set like the below

{
  data: {
    author: [
      {
        hobbies: ["travelling", "reading"],
        married: false,
        country: "Nigeria",
        name: "Aleem Isiaka",
        posts: [
          {
            title: "Learn more about how to improve your Gatsby website",
          },
          {
            title: "The ultimate guide to GatsbyJS",
          },
          {
            title: "How to start a blog with only GatsbyJS",
          },
        ],
      },
    ],
  },
};

We can have a query that to fetch the country and posts from the data:

query {
  authors {
    country,
    posts {
      title
    }
  }
}

The response that we will get should contain JSON data of blog posts with just the title and nothing more:

[
  { country: “Nigeria”, posts: [{...}, {...}, {...}] },
  { country: “Tunisia”, posts: [] },
  { title: “Ghana”, posts: []},
]

We can also use arguments as conditions for a query:

query {
  authors (country: “Nigeria”) {
    country,
    posts {
      title
    }
  }
}

Which should return

[
  { country: “Nigeria”, posts: [{...}, {...}, {...}] }
]

Nested fields can also be queried, like the posts with the Post type, you can ask for just the titles:

query {
  authors(country: ‘Nigeria’) {
    country,
    posts {
      title
    }
  }
}

And it should return any Author type matching Nigeria returning the country and posts array containing objects with just the title field.

Gatsby with GraphQL

To avoid the overhead of having a server/service that serves data that GraphQL can transform, Gatsby executes GraphQL queries at build time. Data is provided to the components during the build process, making them readily available inside the browser without a server.

Still, Gatsby can run as a server that can be queried by other GraphQL clients, like GraphiQL, in a browser.

Gatsby Ways Of Interacting With GraphQL

There are two places where Gatsby can interact with GraphQL, through a gatsby-node.js API file, and through page components.

gatsby-node.js

The createPage API can be configured as a function which will receive a graphql helper as part of the items in the first argument passed to the function.

// gatsby-node.js source: https://www.gatsbyjs.org/docs/node-apis/#createPages
exports.createPages = async ({ graphql, actions }) => {
  const result = await graphql(query loadPagesQuery ($limit: Int!) {
      allMarkdownRemark(limit: $limit) {
        edges {
          node {
            frontmatter {
              slug
            }
          }
        }
      }
    })
}

In the above code, we have used the GraphQL helper to fetch markdown files from Gatsby’s data layer. And we can inject this to create a page and modify existing data inside the Gatsby data layer.

Page Components

Page components inside of /pages directory or templates rendered by the createPage API action can import graphql from the gatsby module and export a pageQuery. In turn, Gatsby would inject a new prop data into the props of the page component containing the resolved data.

import React from "react";
import { graphql } from "gatsby";

const Page = props => {
  return 
{JSON.stringify(props.data)}
; }; export const pageQuery = graphql` query { ... } `; export default Page;
In Other Components

Other components can import graphql and StaticQuery components from the gatsby module, render the &lt;StaticQuery/> passing query props that implement the Graphql helper and render to get the returned data.

import React from "react";
import { StaticQuery, graphql } from "gatsby";

const Brand = props => {
  return (
    <div>
      <h1>{data.site.siteMetadata.title}</h1>
    </div>
  );
};

const Navbar = props => {
  return (
    <StaticQuery
      query={graphql`
        query {
          site {
            siteMetadata {
              title
            }
          }
        }
      `}
      render={data => <Brand data={data} {...props} />}
    />
  );
};

export default Navbar;

Building A Modern And Advanced Gatsby Publishing Blog

In this section we will walk through a process of creating a blog that supports tagging, categorization, pagination and grouping articles by authors. We will use plugins of Gatsby’s ecosystem to bring in some features and use logics in GraphQL queries to make a publisher’s blog that is ready for multiple author publications.

The final version of the blog we will build can be found here, also the code is hosted on Github.

Initializing The Project

Like any Gatsby website, we initialize from a starter, here we will be using the advanced starter but modified to cater for our use case.

First clone this Github repo, change the working branch to the dev-init, and then run npm run develop from the project’s folder to start the development server making the site available at http://localhost:8000.

git clone git@github.com:limistah/modern-gatsby-starter.git 
cd modern-gatsby-starter
git checkout dev-init
npm install
npm run develop

Visiting http://localhost:8000 will show the default homepage for this branch.

Creating Blog Posts Content

Some post content included in the project repository could be accessed at the dev-blog-content branch. The organization of the content directory looks like this /content/YYYY_MM/DD.md, which group posts by the created month of a year.

The blog post content has title, date, author, category, tags as its frontmatter, which we will use to distinguish a post and do some further processing on, while the rest of the content is the body of the post.

title: "Bold Mage"
date: "2020-07-12"
author: "Tunde Isiaka"
category: "tech"
tags:
  - programming
  - stuff
  - Ice cream
  - other
---

# Donut I love macaroon chocolate bar

Oat cake marshmallow lollipop fruitcake I love jelly-o. Gummi bears cake wafer chocolate bar pie. Marshmallow pastry powder chocolate cake candy chupa chups. Jelly beans powder soufflé biscuit pie macaroon chocolate cake. Marzipan lemon drops chupa chups sweet cookie sesame snaps jelly halvah.

Displaying Post Content

Before we can render our Markdown posts in HTML, we have to do some processing. First, loading the files into the Gatsby storage, parsing the MD to HTML, linking image dependencies, and likes. To ease this, we will use a host of plugins by the Gatsby ecosystem.

We can use these plugins by updating the gatsby-config.js at the root of the project to look like this:

module.exports = {
  siteMetadata: {},
  plugins: [
    {
      resolve: "gatsby-source-filesystem",
      options: {
        name: "assets",
        path: `${__dirname}/static/`,
      },
    },
    {
      resolve: "gatsby-source-filesystem",
      options: {
        name: "posts",
        path: `${__dirname}/content/`,
      },
    },
    {
      resolve: "gatsby-transformer-remark",
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-relative-images`,
          },
          {
            resolve: "gatsby-remark-images",
            options: {
              maxWidth: 690,
            },
          },
          {
            resolve: "gatsby-remark-responsive-iframe",
          },
          "gatsby-remark-copy-linked-files",
          "gatsby-remark-autolink-headers",
          "gatsby-remark-prismjs",
        ],
      },
    },
  ],
};

We have instructed gatsby to include the plugins to assist us in carrying out some actions, notably pulling files from the /static folder for static files and /content for our blog posts. Also, we have included a remark transformer plugin to transform all files ending with .md or .markdown into a node with all the fields of remark for rendering markdown as HTML.

Lastly, we included plugins in operating on the nodes generated by gatsby-transformer-remark.

Implementing The gatsby-config.js API File

Moving forward, inside of gatsby-node.js in the project root, we can export a function named createPage and have the content of the function to use the graphQL helper to pull nodes from the content layer of GatsbyJS.

The first update to this page would include ensuring that we have a slug set on the MarkDown remark nodes. We will listen to the onCreateNode API and get the node created to determine if it is a type of MarkdownRemark before we update the node to include a slug and date accordingly.

const path = require("path");
const _ = require("lodash");
const moment = require("moment");

const config = require("./config");

// Called each time a new node is created
exports.onCreateNode = ({ node, actions, getNode }) => {
  // A Gatsby API action to add a new field to a node
  const { createNodeField } = actions;
  // The field that would be included
  let slug;
  // The currently created node is a MarkdownRemark type
  if (node.internal.type === "MarkdownRemark") {
    // Recall, we are using gatsby-source-filesystem?
    // This pulls the parent(File) node,
    // instead of the current MarkdownRemark node
    const fileNode = getNode(node.parent);
    const parsedFilePath = path.parse(fileNode.relativePath);
    if (
      Object.prototype.hasOwnProperty.call(node, "frontmatter") &&
      Object.prototype.hasOwnProperty.call(node.frontmatter, "title")
    ) {
      // The node is a valid remark type and has a title,
      // Use the title as the slug for the node.
      slug = /${_.kebabCase(node.frontmatter.title)};
    } else if (parsedFilePath.name !== "index" && parsedFilePath.dir !== "") {
      // File is in a directory and the name is not index
      // e.g content/2020_02/learner/post.md
      slug = /${parsedFilePath.dir}/${parsedFilePath.name}/;
    } else if (parsedFilePath.dir === "") {
      // File is not in a subdirectory
      slug = /${parsedFilePath.name}/;
    } else {
      // File is in a subdirectory, and name of the file is index
      // e.g content/2020_02/learner/index.md
      slug = /${parsedFilePath.dir}/;
    }

    if (Object.prototype.hasOwnProperty.call(node, "frontmatter")) {
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "slug"))
        slug = /${_.kebabCase(node.frontmatter.slug)};
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "date")) {
        const date = moment(new Date(node.frontmatter.date), "DD/MM/YYYY");
        if (!date.isValid)
          console.warn(WARNING: Invalid date., node.frontmatter);
        // MarkdownRemark does not include date by default

        createNodeField({ node, name: "date", value: date.toISOString() });
      }
    }
    createNodeField({ node, name: "slug", value: slug });
  }
};

The Post Listing

At this point, we can implement the createPages API to query for all markdowns and create a page with the path as the slug we have created above. See it on Github.

//gatsby-node.js
// previous code

// Create Pages Programatically!
exports.createPages = async ({ graphql, actions }) => {
  // Pulls the createPage action from the Actions API
  const { createPage } = actions;

  // Template to use to render the post converted HTML
  const postPage = path.resolve("./src/templates/singlePost/index.js");

  // Get all the markdown parsed through the help of gatsby-source-filesystem and gatsby-transformer-remark
  const allMarkdownResult = await graphql({
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
            frontmatter {
              title
              tags
              category
              date
              author
            }
          }
        }
      }
    });

  // Throws if any error occur while fetching the markdown files
  if (allMarkdownResult.errors) {
    console.error(allMarkdownResult.errors);
    throw allMarkdownResult.errors;
  }

  // Items/Details are stored inside of edges
  const postsEdges = allMarkdownResult.data.allMarkdownRemark.edges;

  // Sort posts
  postsEdges.sort((postA, postB) => {
    const dateA = moment(
      postA.node.frontmatter.date,
      siteConfig.dateFromFormat
    );

    const dateB = moment(
      postB.node.frontmatter.date,
      siteConfig.dateFromFormat
    );

    if (dateA.isBefore(dateB)) return 1;
    if (dateB.isBefore(dateA)) return -1;

    return 0;
  });

  // Pagination Support for posts
  const paginatedListingTemplate = path.resolve(
    "./src/templates/paginatedListing/index.js"
  );

  const { postsPerPage } = config;
  if (postsPerPage) {
    // Get the number of pages that can be accommodated
    const pageCount = Math.ceil(postsEdges.length / postsPerPage);

    // Creates an empty array
    Array.from({ length: pageCount }).forEach((value, index) => {
      const pageNumber = index + 1;
      createPage({
        path: index === 0 ? /posts : /posts/${pageNumber}/,
        component: paginatedListingTemplate,
        context: {
          limit: postsPerPage,
          skip: index * postsPerPage,
          pageCount,
          currentPageNumber: pageNumber,
        },
      });
    });
  } else {
    // Load the landing page instead
    createPage({
      path: /,
      component: landingPage,
    });
  }
};

In the createPages function, we use the graphql helper provided by Gatsby to query data from the content layer. We used a standard Graphql query to do this and passed a query to get content from allMarkdownRemark type. Then moved forward to sort the posts by the created date.

We then pulled a postPerPage property from an imported config object, which is used to chunk down the total posts to the specified number of posts for a single page.

To create a listing page that supports pagination, we need to pass in the limit, pageNumber, and the number of pages to skip to the component that would be rendering the list. We are achieving this using the context property of the createPage config object. We will be accessing these properties from the page to make another graphql query to fetch posts within the limit.

We can also notice that we use the same template component for the listing, and only the path is changing utilizing the index of the chunk array we had defined ahead. Gatsby will pass the necessary data for a given URL matching /{chunkIndex}, so we can have / for the first ten posts, and /2 for the next ten posts.

Rendering Post Listing

The component rendering these pages could be found at src/templates/singlePost/index.js of the project folder. It also exports a graphql helper which pulls the limit and page query parameter it received from the createPages process to query gatsby for posts within the range of the current page.

import React from "react";
import { graphql, Link } from "gatsby";
import Layout from "../../layout";
import PostListing from "../../components/PostListing";
import "./index.css";

const Pagination = ({ currentPageNum, pageCount }) => {
  const prevPage = currentPageNum - 1 === 1 ? "/" : /${currentPageNum - 1}/;
  const nextPage = /${currentPageNum + 1}/;
  const isFirstPage = currentPageNum === 1;
  const isLastPage = currentPageNum === pageCount;

  return (
    <div className="paging-container">
      {!isFirstPage && <Link to={prevPage}>Previous</Link>}
      {[...Array(pageCount)].map((_val, index) => {
        const pageNum = index + 1;
        return (
          <Link
            key={listing-page-${pageNum}}
            to={pageNum === 1 ? "/" : /${pageNum}/}
          >
            {pageNum}
          </Link>
        );
      })}
      {!isLastPage && <Link to={nextPage}>Next</Link>}
    </div>
  );
};

export default (props) => {
  const { data, pageContext } = props;
  const postEdges = data.allMarkdownRemark.edges;
  const { currentPageNum, pageCount } = pageContext;

  return (
    <Layout>
      <div className="listing-container">
        <div className="posts-container">
          <PostListing postEdges={postEdges} />
        </div>

        <Pagination pageCount={pageCount} currentPageNum={currentPageNum} />
      </div>
    </Layout>
  );
};

/* eslint no-undef: "off" */
export const pageQuery = graphqlquery ListingQuery($skip: Int!, $limit: Int!) {
    allMarkdownRemark(
      sort: { fields: [fields___date], order: DESC }
      limit: $limit
      skip: $skip
    ) {
      edges {
        node {
          fields {
            slug
            date
          }
          excerpt
          timeToRead
          frontmatter {
            title
            tags
            author
            category
            date
          }
        }
      }
    }
  };

The Post Page

To view the content of a page, we need to programmatically create the page inside the gatsby-node.js API File. First, we have to define a new component to render the content with, for this, we have src/templates/singlePost/index.jsx.

import React from "react";
import { graphql, Link } from "gatsby";
import _ from "lodash";
import Layout from "../../layout";
import "./b16-tomorrow-dark.css";
import "./index.css";
import PostTags from "../../components/PostTags";

export default class PostTemplate extends React.Component {
  render() {
    const { data, pageContext } = this.props;
    const { slug } = pageContext;
    const postNode = data.markdownRemark;
    const post = postNode.frontmatter;
    if (!post.id) {
      post.id = slug;
    }

    return (
      <Layout>
        <div>
          <div>
            <h1>{post.title}</h1>
            <div className="category">
              Posted to{" "}
              <em>
                <Link
                  key={post.category}
                  style={{ textDecoration: "none" }}
                  to={/category/${_.kebabCase(post.category)}}
                >
                  <a>{post.category}</a>
                </Link>
              </em>
            </div>
            <PostTags tags={post.tags} />
            <div dangerouslySetInnerHTML={{ __html: postNode.html }} />
          </div>
        </div>
      </Layout>
    );
  }
}

/* eslint no-undef: "off" */
export const pageQuery = graphqlquery BlogPostBySlug($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      timeToRead
      excerpt
      frontmatter {
        title
        date
        category
        tags
      }
      fields {
        slug
        date
      }
    }
  };

Again, we are using a graphQL helper to pull out a page by a slug query that would be sent to the page through the createPages API.

Next, we should have the below code added to gatsby-node.js at the end of the createPages API function.

// Template to use to render the post converted HTML
  const postPage = path.resolve("./src/templates/singlePost/index.jsx");

// Loops through all the post nodes
postsEdges.forEach((edge, index) => {
  // Create post pages
  createPage({
    path: edge.node.fields.slug,
    component: postPage,
    context: {
      slug: edge.node.fields.slug,
    },
  });
});

And we could visit ‘/{pageSlug}’ and have it render the content of the markdown file for that page as HTML. As an example, http://localhost:8000/the-butterfly-of-the-edge should load the converted HTML for the markdown at: content/2020_05/01.md, similar to all valid slugs. Great!

Rendering Categories And Tags

The single post template component has a link to a page in the format /categories/{categoryName} to list posts with similar categories.

We can first catch all the categories and tags as we build the single post page in the gatsby-node.js file, then create pages for each caught category/tag passing the category/tag name.

A modification to the section for creating single post page in the gatsby-node.js looks like this:

const categorySet = new Set();
const tagSet = new Set();


const categoriesListing = path.resolve(
  "./src/templates/categoriesListing/index.jsx"
);
// Template to use to render posts based on categories
const tagsListingPage = path.resolve("./src/templates/tagsListing/index.jsx");

// Loops through all the post nodes
postsEdges.forEach((edge, index) => {
  // Generate a list of categories
  if (edge.node.frontmatter.category) {
    categorySet.add(edge.node.frontmatter.category);
  }

  // Generate a list of tags
  if (edge.node.frontmatter.tags) {
    edge.node.frontmatter.tags.forEach((tag) => {
      tagSet.add(tag);
    });
  }

  // Create post pages
  createPage({
    path: edge.node.fields.slug,
    component: postPage,
    context: {
      slug: edge.node.fields.slug,
    },
  });
});

And inside the component for listing posts by tags, we can have the pageQuery export query graphql for posts, including that tag in its tags list. We will use the filter function of graphql and the $in operator to achieve this:

// src/templates/tagsListing/

import React from "react";
import { graphql } from "gatsby";
import Layout from "../../layout";
import PostListing from "../../components/PostListing";

export default ({ pageContext, data }) => {
  const { tag } = pageContext;
  const postEdges = data.allMarkdownRemark.edges;
  return (
    <Layout>
      <div className="tag-container">
        <div>Posts posted with {tag}</div>
        <PostListing postEdges={postEdges} />
      </div>
    </Layout>
  );
};

/* eslint no-undef: "off" */
export const pageQuery = graphql`
  query TagPage($tag: String) {
    allMarkdownRemark(
      limit: 1000
      sort: { fields: [fields___date], order: DESC }
      filter: { frontmatter: { tags: { in: [$tag] } } }
    ) {
      totalCount
      edges {
        node {
          fields {
            slug
            date
          }
          excerpt
          timeToRead
          frontmatter {
            title
            tags
            author
            date
          }
        }
      }
    }
  }
`;

And we have the same process in the categories listing component, and the difference is that we only need to find where the categories match precisely with what we pass to it.

// src/templates/categoriesListing/index.jsx
import React from "react";
import { graphql } from "gatsby";
import Layout from "../../layout";
import PostListing from "../../components/PostListing";

export default ({ pageContext, data }) => {
  const { category } = pageContext;
  const postEdges = data.allMarkdownRemark.edges;
  return (
    <Layout>
      <div className="category-container">
        <div>Posts posted to {category}</div>
        <PostListing postEdges={postEdges} />
      </div>
    </Layout>
  );
};

/* eslint no-undef: "off" */
export const pageQuery = graphql`
  query CategoryPage($category: String) {
    allMarkdownRemark(
      limit: 1000
      sort: { fields: [fields___date], order: DESC }
      filter: { frontmatter: { category: { eq: $category } } }
    ) {
      totalCount
      edges {
        node {
          fields {
            slug
            date
          }
          excerpt
          timeToRead
          frontmatter {
            title
            tags
            author
            date
          }
        }
      }
    }
  }
`;

Noticeable, inside both of the tags and categories components, we render links to the single post page for further reading of a post’s content.

Adding Support For Authors

To support multiple authors, we have to make some modifications to our post content and introduce new concepts.

Load JSON Files

First, we should be able to store the content of authors in a JSON file like this:

{
  "mdField": "aleem",
  "name": "Aleem Isiaka",
  "email": "aleem.isiaka@gmail.com",
  "location": "Lagos, Nigeria",
  "avatar": "https://api.adorable.io/avatars/55/abott@adorable.png",
  "description": "Yeah, I like animals better than people sometimes... Especially dogs. Dogs are the best. Every time you come home, they act like they haven’t seen you in a year. And the good thing about dogs... is they got different dogs for different people.",
  "userLinks": [
    {
      "label": "GitHub",
      "url": "https://github.com/limistah/modern-gatsby-starter",
      "iconClassName": "fa fa-github"
    },
    {
      "label": "Twitter",
      "url": "https://twitter.com/limistah",
      "iconClassName": "fa fa-twitter"
    },
    {
      "label": "Email",
      "url": "mailto:aleem.isiaka@gmail.com",
      "iconClassName": "fa fa-envelope"
    }
  ]
}

We would be storing them in an author’s directory in the root of our project as /authors. Notice that the author JSON has mdField that would be the unique identifier to the author field we will be introducing to the markdown blog content; this ensures that authors can have multiple profiles.

Next, we have to update gatsby-config.js plugins instructing gatsby-source-filesystem to load the content from the authors/ directory into the Files Node.

// gatsby-config.js
{
  resolve: `gatsby-source-filesystem`,
  options: {
    name: "authors",
    path: `${__dirname}/authors/`,
  },
}

Lastly, we will install gatsby-transform-json to transform JSON files created for easy handling and proper processing.

npm install gatsby-transformer-json --save

And include it inside the plugins of gatsby-config.js,

module.exports = {
  plugins: [
    // ...other plugins
    `gatsby-transformer-json`
  ],
};

Querying And Creating Authors Page

To begin with, we need to query all of the authors in our authors/ directory inside of gatsby-config.js that have been loaded into the data layer, we should append the code below to createPages API function

const authorsListingPage = path.resolve(
  "./src/templates/authorsListing/index.jsx"
);

const allAuthorsJson = await graphql(`
  {
    allAuthorsJson {
      edges {
        node {
          id
          avatar
          mdField
          location
          name
          email
          description
          userLinks {
            iconClassName
            label
            url
          }
        }
      }
    }
  }
`);

const authorsEdges = allAuthorsJson.data.allAuthorsJson.edges;
authorsEdges.forEach((author) => {
  createPage({
    path: `/authors/${_.kebabCase(author.node.mdField)}/`,
    component: authorsListingPage,
    context: {
      authorMdField: author.node.mdField,
      authorDetails: author.node,
    },
  });
});

In this snippet, we are pulling all the authors from the allAuthorsJson type, then, calling forEach on the nodes to create a page where we pass the mdField to distinguish the author and the authorDetails for full information about the author.

Rendering Author’s Posts

In the component rendering the page which could be found at src/templates/authorsListing/index.jsx, we have the below content for the file

import React from "react";
import { graphql } from "gatsby";
import Layout from "../../layout";
import PostListing from "../../components/PostListing";
import AuthorInfo from "../../components/AuthorInfo";

export default ({ pageContext, data }) => {
  const { authorDetails } = pageContext;
  const postEdges = data.allMarkdownRemark.edges;
  return (
    <Layout>
      <div>
        <h1 style={{ textAlign: "center" }}>Author Roll</h1>
        <div className="category-container">
          <AuthorInfo author={authorDetails} />
          <PostListing postEdges={postEdges} />
        </div>
      </div>
    </Layout>
  );
};

/* eslint no-undef: "off" */
export const pageQuery = graphql`
  query AuthorPage($authorMdField: String) {
    allMarkdownRemark(
      limit: 1000
      sort: { fields: [fields___date], order: DESC }
      filter: { frontmatter: { author: { eq: $authorMdField } } }
    ) {
      totalCount
      edges {
        node {
          fields {
            slug
            date
          }
          excerpt
          timeToRead
          frontmatter {
            title
            tags
            author
            date
          }
        }
      }
    }
  }
`;

In the above code, we exported the pageQuery like we do, to create a GraphQL query to fetch posts matched by an author, we are using the $eq operator to achieve this are generating links to a single post page for further reading.

Conclusion

In Gatsby, we can query any data that exists inside of its data access layer with the use of GraphQL query and pass variables around using some constructs defined by the architecture of Gatsby. we have seen how we could use the graphql helper in various places and understand widely used patterns for querying data in Gatsby’s websites with the help of GraphQL.

GraphQL is very powerful and could do other things like data mutation on a server. Gatsby does not need to update its data at runtime, so it does not support the mutation feature of GraphQL.

GraphQL is a great technology, and Gatsby makes it very interesting to use in their framework.

References

How to Edit the Footer in WordPress (Step by Step)

Do you need to edit the footer area of your WordPress website? The footer area appears at the bottom of each page on your WordPress site.,

There are several different ways website owners can utilize this area and make it more useful for their website visitors.

In this article, we will show you how to edit the footer in WordPress.

Editing your footer in WordPress

What is the Footer in WordPress?

The ‘footer’ in WordPress is the bottom part of your website that appears after the content area. It normally appears on all pages on your website.

Example of the footer area on a WordPress powered website

This part of the website is located far down below and is often ignored by most beginners for a long time. However, there are several ways you can utilize this area by making it more helpful for your users, WordPress SEO, and your business.

All top WordPress themes come with footer widget area that’s easy to edit. You can also carefully edit the footer.php template file in your theme to remove unwanted links from this area.

That being said, let’s take a look at how to easily edit the footer in WordPress. You can use the following links to jump to the section you want to read.

Editing Widgets in Your Footer in WordPress

Many popular WordPress themes have widget areas in the footer.

You can use these widget areas to add text, images, or links to your privacy policy and legal disclaimers in the footer area.

Adding text and images is quite straight forward. You can simply go to the Appearance » Widgets page and add a Text, Image, or Gallery widget to your footer widget area.

Add widgets to footer in WordPress

To add a widget, simply drag and drop it into a footer area. If you need more help, then see our article on how to add and use widgets in WordPress.

Note that many themes will have multiple footer areas, and they may use them differently. You can preview your website after adding widgets to make sure that they appear where you want them to be.

Adding Links in Footer Widget Area

You may also want to add links to different pages, categories, or to the legal pages of your website in the footer area.

WordPress comes with an easy to to manage those links using the navigation menus. Simply head over to the Appearance » Menus page and click on the ‘create new menu’ link.

Create new menu in WordPress

WordPress will ask you to provide a name for your new menu. Enter a name that helps you easily identify this menu and then click on the ‘Create Menu’ button.

Enter your navigation menu name

Your menu is now ready and you can start adding links to it. Simply select the pages, posts, categories from the left column to add them to your menu.

Add pages to your menu

Once you are finished, click on the Save Menu button to store your changes. For more help, see our article on how to create navigation menus in WordPress.

Your menu is now ready to be added to the WordPress footer widget area. Simply visit the Appearance » Widgets page in your WordPress admin and then add the Navigation Menu widget to your footer area.

Adding a navigation menu widget to your website's footer

In the widget settings, select the footer navigation menu you created earlier from the dropdown menu and click on the Save button.

You can now visit your website to see your footer links in action.

A footer section with navigation menu links

You can create multiple navigation menus in WordPress and add as many navigation menu widgets to your sidebar as you need. If you need another set of links simply repeat the same steps again.

Removing the ‘Powered by WordPress’ Text from Your Footer

When you first install WordPress, your site may have a ‘Powered by WordPress’ link in a footer bar at the bottom. This isn’t a widget, so it’s often not clear how to change it.

The 'Powered by WordPress' text and link in the Twenty Twenty theme

Some themes will alter this to their own text and link. If so, you can normally change this text using the live theme customizer. Simply go to Themes » Customizer in your WordPress admin. Look for an option to edit your site footer:

The Footer tab in the WordPress theme customizer

We’re using the Astra theme for this example. With Astra, you need to go to Footer » Footer Bar in the customizer. You will then have the option to change the text of your footer bar:

Editing the footer text in the theme customizer for the Astra theme

Once you’ve finished editing the text, don’t forget to click the Publish button at the top of the screen to put your changes live.

Go ahead and view your site to see your new footer:

Viewing the new footer text live on your website

For more help, take a look at our in-depth guide to the WordPress theme customizer.

Editing the Footer Text Manually

What if your theme doesn’t have the option to edit the footer text using the customizer?

In this case, you need to edit the footer.php file. It is a template file stored in your WordPress theme folder and is responsible for displaying the footer area for that particular theme.

The easiest way to edit this is by using an FTP client to connect with your WordPress hosting.

First, download the /wp-content/themes/yourtheme/footer.php file and then edit it in a text editor.

You will need to find the line in the file with the ‘Powered by WordPress’ text. This is how it looks in the Twenty Twenty theme:

<div class="footer-credits">

	<p class="footer-copyright">&copy;
		<?php
		echo date_i18n(
			/* translators: Copyright date format, see https://www.php.net/date */
			_x( 'Y', 'copyright date format', 'twentytwenty' )
		);
		?>
		<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a>
	</p><!-- .footer-copyright -->

	<p class="powered-by-wordpress">
		<a href="<?php echo esc_url( __( 'https://wordpress.org/', 'twentytwenty' ) ); ?>">
			<?php _e( 'Powered by WordPress', 'twentytwenty' ); ?>
		</a>
	</p><!-- .powered-by-wordpress -->

</div><!-- .footer-credits -->

Then, simply delete or change that text, and reupload your footer.php file.

Tip: Make a copy of your footer.php file before making changes. That way, if you accidentally break anything, you can easily upload the original file again.

For more help, check out our guide on removing the ‘Powered by WordPress’ footer link.

Adding Code to Your WordPress Footer

Sometimes, you may need to add code snippets to your WordPress footer. This is often done in order to connect your site with an external app.

For instance, to add a Pinterest button to your site, you need to add Pinterest’s script to your footer. You may also see a tutorial that asks you to insert your Google Analytics code there.

The easiest way to do this is to install and activate the Insert Headers and Footers plugin. For more details, see our step by step guide on how to install a WordPress plugin.

Upon activation, simply go to Settings » Insert Headers and Footers in your WordPress admin. Go ahead and copy and paste your footer code into the ‘Scripts in Footer’ box:

Using the Insert Headers and Footers plugin to add code to your website's footer

Don’t forget to click the Save button before moving on.

For more help, take a look at our guide to adding header and footer code in WordPress.

If you’re looking to add Google Analytics, then we recommend you use another method instead which helps with better tracking.

We hope this article helped you learn how to edit the footer in WordPress. You may also want to see our comparison of the best drag & drop WordPress page builder plugins, and our guide on how to create a custom WordPress theme without writing any code.

If you liked this article, then please subscribe to our YouTube Channel for WordPress video tutorials. You can also find us on Twitter and Facebook.

The post How to Edit the Footer in WordPress (Step by Step) appeared first on WPBeginner.