Snippets frequently used with Sage
- Sage Snippets
- Load custom fonts in TinyMCE
- Text selection color
- ACF theme options page w/ ACF Builder
- Theme color meta tag
- Nicer Gravity Forms Spinner
- Basic button style
- Gravity Forms styles (Tailwind)
- Font Awesome icon in Search Form
- Responsive oembed
- Tailwind config
- Add base Tailwind body classes to templates and editor
- PurgeCSS (for use with Tailwind)
Table of contents generated with markdown-toc
In setup.php
/**
* Theme assets
*/
function custom_fonts()
{
return [
'hoefler-fonts' => 'https://cloud.typography.com/1234/2345/css/fonts.css',
'adobe-fonts' => 'https://use.typekit.net/asdf.css',
];
}
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null);
wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);
foreach (custom_fonts() as $handle => $url) {
wp_enqueue_style($handle, $url, false, null);
}
if (is_single() && comments_open() && get_option('thread_comments')) {
wp_enqueue_script('comment-reply');
}
}, 100);
// add custom font stylesheets to list of sheets for TinyMCE
add_filter('mce_css', function ($sheets) {
foreach (custom_fonts() as $url) {
$sheets .= ",$url";
}
return $sheets;
});
/**
* Text selection color
*/
::selection {
@apply bg-primary text-white;
}
.bg-primary ::selection,
.bg-black ::selection {
@apply bg-secondary text-black;
}
Install
composer require stoutlogic/acf-builder
Add page
use StoutLogic\AcfBuilder\FieldsBuilder;
add_action('acf/init', function () {
acf_add_options_sub_page(array(
'page_title' => 'Theme Settings',
'menu_title' => 'Theme',
'parent_slug' => 'options-general.php',
));
acf_add_local_field_group(
(new FieldsBuilder('options'))
// chain field methods here
->setLocation('options_page', '==', 'acf-options-theme')
->getRootContext()
->build()
);
});
/**
* Add theme color meta
*/
add_action('wp_head', function () {
?>
<meta name="theme-color" content="#f05323" />
<?php
});
Filters
add_filter('gform_ajax_spinner_url', function ($image_src, $form) {
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}, 10, 2);
Styles
body {
.gform_wrapper .gform_ajax_spinner {
margin-top: 0;
padding-left: 0;
border: 4px solid rgba(255, 255, 255, 0.3);
border-left: 4px solid config("colors.secondary");
animation: spinner 1.1s infinite linear;
border-radius: 50%;
width: 15px;
height: 15px;
}
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
%btn {
@apply cursor-pointer block my-1 px-3 py-2 text-primary text-center font-sans font-medium uppercase text-xs tracking-wide border border-primary bg-white;
transition: 0.2s ease;
&:hover {
@apply bg-primary text-white;
}
&:focus {
outline-color: config("colors.secondary");
}
@screen md {
@apply inline-block;
}
}
.btn {
@extend %btn;
}
/** Gravity Forms */
body {
.gform_wrapper {
@apply max-w-sm;
}
.gform_wrapper .gform_heading {
@apply mb-4;
}
.gform_wrapper span.gform_description {
@apply font-light w-auto;
}
.gform_wrapper label.gfield_label,
.gform_wrapper .field_sublabel_below .ginput_complex.ginput_container label {
@apply font-sans text-xs font-medium uppercase;
}
.gform_wrapper .field_sublabel_below .ginput_complex.ginput_container label {
@apply text-2xs tracking-normal;
}
.gform_wrapper input[type="email"],
.gform_wrapper input[type="date"],
.gform_wrapper input[type="datetime"],
.gform_wrapper input[type="datetime-local"],
.gform_wrapper input[type="month"],
.gform_wrapper input[type="number"],
.gform_wrapper input[type="password"],
.gform_wrapper input[type="search"],
.gform_wrapper input[type="tel"],
.gform_wrapper input[type="text"],
.gform_wrapper input[type="time"],
.gform_wrapper input[type="week"],
.gform_wrapper input[type="url"],
.gform_wrapper select,
.gform_wrapper textarea,
/* prettier-ignore */
.gform_wrapper input:not([type="radio"]):not([type="checkbox"]):not([type="submit"]):not([type="button"]):not([type="image"]):not([type="file"]) {
@apply border-solid border border-grey-light py-1 px-2 text-sm font-light;
transition: all 200ms ease-in-out;
&:focus {
@apply border-grey outline-none shadow;
}
}
.gform_wrapper .button,
.gform_wrapper .gform_footer input[type="submit"] {
@extend %btn;
}
.gform_wrapper .gfield_required {
color: inherit;
}
.gform_wrapper .validation_error {
@apply p-4 py-8 text-red text-center text-base font-regular border-`;
}
.gform_wrapper .gfield_error .gfield_label,
.gform_wrapper li.gfield_error div.ginput_complex.ginput_container label,
.gform_wrapper li.gfield_error ul.gfield_checkbox,
.gform_wrapper li.gfield_error ul.gfield_radio {
@apply text-red;
}
/* prettier-ignore */
.gform_wrapper li.gfield_error input:not([type="radio"]):not([type="checkbox"]):not([type="submit"]):not([type="button"]):not([type="image"]):not([type="file"]),
.gform_wrapper li.gfield_error textarea {
@apply border-red;
}
.gform_wrapper .validation_message {
@apply w-full text-red font-regular;
}
.gform_validation_container {
display: none !important;
}
}
Filters:
/**
* Use Font Awesome icon in search submit button
*/
add_filter('get_search_form', function ($html) {
return str_replace('<input type="submit" class="search-submit" value="Search" />', '<button class="search-submit" value="Search"><i class="fas fa-search"></i> <span class="sr-only">Search</span></button>', $html);
});
Filters:
/**
* Indicate the an embed is a video
*/
add_filter('embed_oembed_html', function ($cache, $url, $attr, $post_ID) {
$video_providers = [
'youtube',
'vimeo',
'dailymotion',
'video',
'vine',
'funnyordie',
'hulu',
'wordpress.tv',
'animoto',
'collegehumor'
];
$oembed_obj = new \WP_oEmbed;
$provider = $oembed_obj->get_provider($url);
foreach ($video_providers as $source) {
if (strpos($provider, $source)) {
return sprintf('<div class="video-wrapper">%s</div>', $cache);
}
}
return $cache;
}, 10, 4);
Styles:
.video-wrapper {
@apply relative overflow-hidden max-w-full text-0;
padding-bottom: 56.25%;
height: 0;
iframe {
@apply absolute pin-t pin-l w-full h-full;
}
}
^ Could probably be improved
In relevant parts of config file:
textSizes: {
...
'0': '0',
}
Filters:
/**
* Add <body> classes
*/
function tailwind_body_classes()
{
return ['font-serif', 'font-light', 'leading-normal', 'text-grey'];
}
add_filter('body_class', function (array $classes) {
/** Add Tailwind base classes */
$classes = array_merge($classes, tailwind_body_classes());
return array_filter($classes);
});
// add Tailwind body classes in TinyMCE
add_filter('tiny_mce_before_init', function ($mce) {
$mce['body_class'] .= ' ' . implode(' ', tailwind_body_classes());
return $mce;
});
Install:
yarn add --dev purgecss-webpack-plugin glob-all purgecss-whitelister
Webpack config:
// under imports
const glob = require("glob-all");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const whitelister = require("purgecss-whitelister");
class TailwindExtractor {
static extract(content) {
return content.match(/[A-z0-9-:\/]+/g) || [];
}
}
// at end of plugins array
new PurgecssPlugin({
paths: glob.sync([
"app/**/*.php",
"resources/views/**/*.php",
"resources/assets/scripts/**/*.js",
]),
whitelist: [
"menu-footer-menu",
"nav-links",
"tinymce",
...whitelister("node_modules/tailwindcss/css/preflight.css"),
],
whitelistPatternsChildren: [
/^gfield/,
/^gform/,
/^ginput/,
/^page-template-default/,
/^post-template-default/,
/^entry-content/,
/^video-wrapper/,
],
extractors: [
{
extractor: TailwindExtractor,
extensions: ["js", "php"],
},
],
}),