Sharing an agency fork of bedrock + sage for inspiration

Ahoy, since I finally completed the migration to bud and a bunch of other stuff I thought I’d share the bedrock + sage fork we use at our agency. For various reasons we don’t really follow all roots conventions nor do we have access to radicle so this is closer to the older setup.

First of all thanks to all of you for your great work, if it wasn’t for Roots I personally wouldn’t have agreed to doing WP development in the first place. Recently I was skeptical to Bud but it turned out to be super flexible and a joy to work with–Thanks Kelly! I hope others find something useful or inspirational in our implementations.

Repo: GitHub - generoi/bedrock
Live: https://gdsbedrock.kinsta.cloud/

Repo has been public for a long time but it used to be private so it lost it’s fork status unfortunately.

I tried to summarize what we do differently to bring inspiration to others.

Bedrock additions:

Sage differences:

  • Pint and prettier merged just now
  • Bud merged just now but we stick closer to laravel mix setup due how we enqueue assets.
  • We enqueue core block styles but with should_load_separate_core_block_assets and then we add our own block stylesheets compiled as individual stylesheets.
  • Blocks are built using core functions + react + blade for views and we use block.json asset loading so individual scripts/styles here too. Wrote a BudBlock extension for reading the block.json assets.
  • We use Sage SVG for including FontAwesome Pro icons (so repo wont work unless you have a key). Extended Sage SVG with better a11y support, I’ll open a PR at some point. Wrote a BudCopyWithoutManifest extension to copy all icons into dist folder but skipping the manfest since there’s thousands of them.
  • We use Navi for navigation. Eventually I’d like this to use the navigation block instead but not a fan of it yet.
  • Our goal is “everything is a block” but without FSE, so eg content-single-product.blade.php uses @blocks and @block directives. For clients (and for easier overview) we usually have a blocks demo page where all variations are presented and tested. Here’s the current demo.
  • Recently added a pretty untested setup with spatie/laravel-csp to set up CSP headers + add nonces to all WP scripts.
  • Set Cache-Control headers for frontend content since we have some customer sites behind Fastly. Our ideal fastly setup is a super long stale-while-revalidate so users get cached results even if out of date. We also serve cached content to anyone who’s not seeing the admin toolbar.
  • For purging proxy caches such as Fastly (or just kinsta) we use a custom generoi/sage-cachetags package where we add suppogate/cache-tags HTTP headers based on content rendered on a page.
  • Mostly our JS components are written as web components. I just find them easy to avoid FOUC and encapsulate a11y quirks :man_shrugging:
  • Oh, it should pass WCAG 2.2 AA-level but with so many recent changes it needs another audit
  • Pagespeed score is ~99/100 on basic product pages with GTM + CMP + Meta Pixel but without custom events setup. Reality for us is this often drops to 80 once growth hackers get in there. As long as we pass core web vitals we’re happy…
  • Just added built-in WooCommerce support since we needed a boilerplate for our customers.

Some blocks that might be useful:

  • Accordion
  • Carousel which supports arbitrary content + multiple slides per row. CSS Snap based but to make it accessible turned out it needed quite a bit of JS.
  • Gallery carousel to replace WooCommerce gallery, it wraps two before mentioned carousels, one for main image and one for thumbnail pager.
  • Media card basis for content cards.
  • Page title just prints the page title regardless of what page it’s on, plan once block bindings has better support is start using template parts for default archives, 404 page etc. Currently we cant because all our clients need multilingual support and it’s a mess with FSE.
  • Post teaser renders a blade view of composed blocks so template remains in code.
  • Share widget

Block hooks

  • Query block variations are removed and instead we add our own using the Post teaser block mentioned before. Eg we have a Article grid query block variation which when inserted renders Post teasers without granular control but still allows editor to filter the query.
  • Product collection block variations are filtered to remove inline styles + use Post teaser, we keep the variations though since they’re useful.
  • Handpicked posts filter added to query block

TODO eventually

  • REST API support to sage-cachetags
  • Template parts once block bindings is supported across more core blocks
  • Tabs block but I still haven’t figured out a good web component structure for it that makes it avoid FOUC
  • sizes=“auto” is finally getting browser support and need to add it
  • publish our varnish configurations for fastly but kinda want a terraform recipe to deploy them
  • Time from designers to fix some less opinionated defaults
  • Remove SASS and just use CSS but we use a fair amount of mixins and without there being a WIP spec for it I dont want to add a PostCSS plugin. Maybe we dont need mixins :man_shrugging:
  • Audit WCAG 2.2 AA-level again, WooCommerce components are not audited.
  • If we get the navigation to be a block + template parts going, we might drop Blade so it’s easier for other agencies to take over if client drops us.
20 Likes

Wow what an awesome resource and inspiration! :open_mouth:

Thanks for sharing it and also thanks for your sage-woocommerce package as well, been using it on all of our woocommerce sites!

2 Likes

Amazing share, nice one @oxyc! You’ll help a heap of people out with this, for sure.

Thank you for sharing. I’ve noticed you mentioned Satipress, can I ask you which PHP version are you using because I think it only supports up to 8.0?

Thank you.

It works just fine with some depreciation notices which are easy to patch

I appreciate the dedication, respect! :clap:

1 Like

Now I’m actually trying to get rid of satispress and instead wrote a github action which auto-updates git repositories of premium plugins. For now I only have a workflow for plugins using EDD github-workflows-plugins/.github/workflows/edd-update.yml at 5d407d3f054552ef20d65e0b58637ca69121738a · generoi/github-workflows-plugins · GitHub

Basically we would have a private github repo per plugin with a composer.json and then a cron scheduled github action to update, commit, tag and release:

name: Build
on:
  workflow_dispatch:
  schedule:
    - cron: '5 4 * * *'
jobs:
  build:
    uses: generoi/github-workflows-plugins/.github/workflows/edd-update.yml@master
    secrets:
      LICENSE_KEY: ${{ secrets.LICENSE_KEY }}
    with:
      source_url: 'https://licensed.site'
      item_name: 'Polylang Pro'
      endpoint_url: 'https://polylang.pro'

It’s leveraging the EDD licensing API.

For now this is an experiment but let’s see… One nice thing is that it will give changelogs to dependabot updates which I’ve desperately wanted. Also makes it easier to monitor and removes satispress as an attack vector.

Besides EDD plugins, ACF already has composer installation and composer-gravityforms looks interesting for Gravityforms (haven’t tested it). At least for us this would basically just leave woocommerce plugins to explore.

1 Like

Take a look at this for keeping premium plugins up to date in private Git repos!

2 Likes

Awesome, thanks! Pretty much the same thing :slight_smile: Since I already built the changelog scrapers and set it up for acf/polylang/gravityforms/facetwp/wpai i’ll stick to ours. Wish I would have seen it before though :smiley: Happy to learn it’s reliable!

Edit: moved the repo GitHub - generoi/github-action-update-plugins

1 Like

Our white whale is getting WooCommerce to work. I’ll race you! (I will not be racing)

This works Add woocommerce downloader · generoi/github-action-update-plugins@297250a · GitHub but lets see if the access token needs to be refreshed (i got it from the options table)