Skip to content

Factor1 Misc Practices Snippets

Melanie Rhodes edited this page May 1, 2023 · 9 revisions

BEM

At Factor1 we use BEM naming conventions to handle class names wherever we can. Done well, it makes for streamlined SCSS styles that compile nicely.

Read up on BEM here.

<article class="blog-post">
  <a href="<?php the_permalink(); ?>">
    <div class="blog-post__img" style="background: url('<?php echo featuredURL('post_grid'); ?>') center/cover no-repeat"></div>

    <div class="blog-post__title">
      <h6><?php the_title(); ?></h6>
    </div>
  </a>
</article>
.blog-post {
  flex-basis: 30% !important;
  margin-top: 30%;
  margin-bottom: rem(20);

  a {
    position: relative;
    display: block;
    height: 100%;
    text-decoration: none;
  }

  &__img {
    position: absolute;
    bottom: 80%;
    width: 100%;
    padding-bottom: 100%;
  }

  &__title {
    position: relative;
    display: flex;
    align-items: center;
    width: 70%;
    height: 100%;
    margin: 0 auto;
    padding: rem(15) rem(20);
    box-shadow: 0 0 rem(5) rgba($black, 0.35);
    background-color: $white;
    z-index: 1;
    transition: all .4s ease;
  }
}

Background Videos

We do not use iframes as background videos, ever, due to issues they can cause. For background videos, use an ACF File field (be sure to restrict the file type to .mp4 files).

Video ACF

<?php
/*
 * Hero (global)
 *
 * Template part used on various templates/views
 *
 * @package F1 Project Name
 * @author Factor1 Studios
 * @since 0.0.1
 */

// Hero Custom Fields
$img = wp_get_attachment_image_src(get_post_thumbnail_id(), 'hero');
$videoToggle = get_field('hero_video_toggle');
$video = get_field('hero_video');
$headline = get_field('hero_headline');
$align = get_field('hero_alignment'); // left or center ?>

<section class="hero" style="background: url('<?php echo $img[0]; ?>') center/cover no-repeat">

  <?php // Optional video
  if( $videoToggle ) : ?>

    <div class="hero--home__video sm-hide">
      <video autoplay loop muted class="sm-hide">
        <source src="<?php echo $video; ?>" type="video/mp4">
      </video>
    </div>

  <?php endif; ?>

  <div class="container">
    <div class="row">
      <div class="col-12 text-<?php echo $align; ?>">
        <h1><?php echo $headline; ?></h1>
      </div>
    </div>
  </div>
</section>
/*
 * Hero (global)
 *
 * Template part used on various templates/views
 *
 * @package F1 Project Name
 * @author Factor1 Studios
 * @since 0.0.1
 */

.hero {
  position: relative;
  @include iPhoneX;
  overflow: hidden;

  // Optional video
  &__video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  video {
    position: absolute;
    top: 50%;
    left: 50%;
    min-width: 100%;
    min-height: 100%;
    width: auto;
    height: auto;
    transform: translateX(-50%) translateY(-50%);
  }

  .container {
    padding: rem(270) 0 rem(105);
  }

  &:after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(to bottom, rgba(0, 0, 0, .9), rgba(0, 0, 0, 0) 35%);
  }
}

.touch .hero__video,
.touch .hero__video video {
  display: none;
}

// Media Queries
@media screen and (max-width: $small-breakpoint) {
  .hero .container {
    padding: rem(200) 0 rem(70);
  }
}

Custom admins

We include a customized admin for every site we build. It doesn’t have to be anything super fancy, but including brand colors and their logo is a nice touch.

Below is a snippet that you can customize as needed. This snippet we generally include in inc/tweaks.php:

// Customize Wordpress Admin
// add login logo
function custom_loginlogo() {
  echo '<style type="text/css">
    .login {
      background: #07223a;
      background: linear-gradient(to right, #07223a, #1679af, #1679af, #07223a);
    }
    .login .message,
    .login #login_error {
      margin-top: 30px;
      border-color: #e9b730;
    }
    .login p a {
      color: #fff !important;
      transition: all .4s ease;
    }
    .login p a:hover {
      color: #e9b730 !important;
    }
    .login input[type="text"]:active,
    .login input[type="text"]:focus,
    .login input[type="password"]:active,
    .login input[type="password"]:focus,
    input[type=text]:focus,
    input[type=search]:focus,
    input[type=radio]:focus,
    input[type=tel]:focus,
    input[type=time]:focus,
    input[type=url]:focus,
    input[type=week]:focus,
    input[type=password]:focus,
    input[type=checkbox]:focus,
    input[type=color]:focus,
    input[type=date]:focus,
    input[type=datetime]:focus,
    input[type=datetime-local]:focus,
    input[type=email]:focus,
    input[type=month]:focus,
    input[type=number]:focus,
    select:focus,
    textarea:focus {
      border-color: #1679af;
    }
    .login input[type="submit"] {
      background-color: #1679af;
      border-color: #1679af;
      box-shadow: 0 1px 0 #1679af;
      text-shadow: none;
    }
    .login input[type="submit"]:hover {
      background-color: #1679af;
    }
    h1 a {
      height: 100% !important;
      width:100% !important;
      background-image: url(' . get_template_directory_uri() . '/assets/img/logo.svg) !important;
      background-postion-x: center !important;
      background-size:contain !important;
      margin-bottom:10px !important;
    }
    h1 {
      width: 320px !important;
      Height: 120px !important
    }
  </style>';
}
add_action('login_head', 'custom_loginlogo');

// add custom footer text
function modify_footer_admin () {
  echo 'Created by <a href="https://factor1studios.com">factor1</a>. ';
  echo 'Powered by<a href="https://WordPress.org">WordPress</a>.';
}
add_filter('admin_footer_text', 'modify_footer_admin');

Add Custom Colors to WYSIWYGs

This function will add the theme's colors to WYSIWYG editors for easy text editing. Add this function to inc/tweaks.php:

// Add custom colors to wysiwygs
  function custom_editor_colors($init) {
    $custom_colors = '
        "DBDBDB", "Light Gray",
        "FFFFFF", "White",
        // ... add rest of theme colors here
    ';

    // build colour grid default+custom colors
    $init['textcolor_map'] = '['.$custom_colors.']';

    // change the number of rows in the grid if the number of colors changes
    // 8 swatches per row
    $init['textcolor_rows'] = 1;

    return $init;
  }
  add_filter('tiny_mce_before_init', 'custom_editor_colors');

Important! Do not forget to client-proof this functionality and safeguard how white/light text appears in WYSYWYG editors:

In dist/editor-styles.css:

/* Do not change this! This ensures that white text remains visible in admin WYSIWYG editors */
span[style*="color: #ffffff"],
span[style*="color: #ffffff;"],
span[style*="color: #f5f5f5"],
span[style*="color: #f5f5f5;"] {
  color: #dbdbdb !important;
}

WYSIWYG Typography Classes

For sites that have some custom typography classes, it’s a good idea to add them as options in the WYSIWYG editors.

It’s also a good idea to include a stylesheet to handle the classes’ appearance in the WYSIWYG editors. You don’t need to load the fonts necessarily, and we avoid using white as a text color in the editors, but some visual indication is helpful for clients.

inc/tweaks.php is a good home for these snippets.

// Add custom classes to WYSIWYGs
function custom_wysiwyg_options( $init_array ) {
  $style_formats = array(
    array(
      'title' => 'Support',
      'block' => 'h3',
      'classes' => 'support',
      'wrapper' => false,
    ),
  );

  // Insert the array, JSON ENCODED, into 'style_formats'
  $init_array['style_formats_merge'] = true;
  $init_array['style_formats'] = wp_json_encode( $style_formats );
  return $init_array;
}
// add_filter( 'tiny_mce_before_init', 'custom_wysiwyg_options' );

// Add editor styles from custom wysiwyg options
function custom_editor_styles() {
  add_editor_style('/assets/css/editor-styles.min.css');
}
// add_action('init', 'custom_editor_styles');

Add async defer to Font Awesome script

Add this in inc/tweaks.php:

// Add async defer to font awesome script
function add_async_attribute($tag, $handle) {
  if ( 'font-awesome' !== $handle )
    return $tag;
    return str_replace( ' src', ' async="async" src', $tag );
}
add_filter('script_loader_tag', 'add_async_attribute', 10, 2);

Enqueuing Google Fonts (with Google's new syntax)

Due to some changes in the url structure for Google fonts, enqueuing more than one family can cause some fonts to drop.

To avoid this issue, make sure to pass an empty array for dependencies and set the version to null in the enqueue function.

// inc/enqueues.php
wp_enqueue_style('google-fonts', 'https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700;1,800&display=swap', array(), null);

Display page templates in admin

Add the following snippet to inc/tweaks.php. It will add a column to the pages list view in the WP admin showing what template is used on each page:

// Display page templates in admin
add_filter( 'manage_pages_columns', 'page_column_views' );
add_action( 'manage_pages_custom_column', 'page_custom_column_views', 5, 2 );
function page_column_views( $defaults ) {
  $defaults['page-layout'] = __('Template');
  return $defaults;
}
function page_custom_column_views( $column_name, $id ) {
  if ( $column_name === 'page-layout' ) {
    $set_template = get_post_meta( get_the_ID(), '_wp_page_template', true );
    if ( $set_template == 'default' ) {
     echo 'Default';
    }
    $templates = get_page_templates();
    ksort( $templates );
    foreach ( array_keys( $templates ) as $template ) :
      if ( $set_template == $templates[$template] ) echo $template;
    endforeach;
  }
}

Display featured images in admin

First, add an admin thumbnail size in inc/thumbnails.php:

if( function_exists('prelude_features') ){
  // Use add_image_size below to add additional thumbnail sizes
  add_image_size( 'admin_thumb', 75, 75, array('center', 'center') );
  ...
}

Then, add the following snippet to inc/tweaks.php. It will add a column to the posts list view in the WP admin their featured images (this can also be adapted to add to page views and other CPTs):

// Display featured images in admin list
// Add the posts and pages columns filter. They both use the same function.
add_filter('manage_posts_columns', 'add_post_admin_thumbnail_column', 2);

// Add the column
function add_post_admin_thumbnail_column($columns) {
  $columns['admin_thumb'] = __('Featured Image');
  return $columns;
}

// Manage Post and Page Admin Panel Columns
add_action('manage_posts_custom_column', 'show_post_thumbnail_column', 5, 2);
// add_action('manage_pages_custom_column', 'show_post_thumbnail_column', 5, 2); // Uncomment this to show page featured images

// Get featured-thumbnail size post thumbnail and display it
function show_post_thumbnail_column($columns, $id) {
  switch($columns){
    case 'admin_thumb':
    if( function_exists('the_post_thumbnail') ) {
      echo the_post_thumbnail( 'admin_thumb' );
    }
    else
      echo 'hmm… your theme doesn\'t support featured image…';
    break;
  }
}

Remove Additional CSS option/Theme & Plugin Editors from the Admin

We can only guarantee our own, QA-tested code. So to prevent clients from adding anything that causes issues or conflicts, we disable the Additional CSS option from the WordPress Customizer as well as the Theme and Plugin file editors.

Add these snippets to inc/tweaks.php:

// Remove additional css option from customizer
function prefix_remove_css_section( $wp_customize ) {
  $wp_customize->remove_section( 'custom_css' );
}
add_action( 'customize_register', 'prefix_remove_css_section', 15 );

// Remove theme/plugin editors from admin
define( 'DISALLOW_FILE_EDIT', true );

iPhoneX Styles

We have developed a streamlined set of snippets to handle the notch with iPhone X phones, based on this article from CSS Tricks.

Enable in header.php:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">

Add this snippet as a mixin in assets/scss/mixins/_sugar.scss

// iPhoneX
@mixin iPhoneX() {
  padding: 0 env(safe-area-inset-right) 0 env(safe-area-inset-left);
}

To use this, make sure there is a containing element around .container elements. This outer element will hold any section background images, colors, etc. and gets the mixin applied to it, which will stretch those to the edges of the screen.

<?php
/*
 * Hero (global)
 *
 * Template part used on various templates/views
 *
 * @package F1 Project Name
 * @author Factor1 Studios
 * @since 0.0.1
 */

// Hero Custom Fields
$img = wp_get_attachment_image_src(get_post_thumbnail_id(), 'hero');
$headline = get_field('hero_headline'); ?>

<section class="hero" style="background: url('<?php echo $img[0]; ?>') center/cover no-repeat">
  <div class="container">
    <div class="row">
      <div class="col-12">
        <h1><?php echo $headline; ?></h1>
      </div>
    </div>
  </div>
</section>
/*
 * Hero (home)
 *
 * Template part used on the home template
 *
 * @package F1 Project Name
 * @author Factor1 Studios
 * @since 0.0.1
 */

.hero--home {
  position: relative;
  @include iPhoneX;
  overflow: hidden;

  .container {
    padding: rem(270) 0 rem(250);
    z-index: 1;
  }

  &:after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(to bottom, rgba(0, 0, 0, .9), rgba(0, 0, 0, 0) 35%);
  }
}

// Media Queries
@media screen and (max-width: $small-breakpoint) {
  .hero--home .container {
    padding: rem(170) 0 rem(210);
  }
}

Footer Site Credit

Unless told otherwise, always include “Site by factor1” in the footer.

<p>Site by <a href="https://factor1studios.com" class="factor1">factor1</a></p>

.factor1 {
  font: 700 rem(14)/1 'Helvetica', sans-serif;
  letter-spacing: -.1em;
  color: $white;

  &:hover {
    color: $buff;
  }
}

Custom WooCommerce Add to Cart Form (with quantity parameter)

Add these snippets to your PHP & JS functions to make use of WooCommerce's built-in quantity parameter:

PHP Function (adds this as a shortcode option)

function custom_add_to_cart( $atts = array(), $content = null ) {
  $id = get_the_ID(); 

  $form = '
    <form class="custom-add-to-cart">
      <input type="number" name="quantity" id="quantity" min="0" max="100" step="1" value="1" />
      <input type="hidden" value="' . $id . '" name="product_id" id="product_id" />
      <input type="hidden" value="' . esc_url(wc_get_cart_url()) . '" name="cart" id="cart" />
      <button type="submit" class="button--primary">Add to Cart</button>
    </form>
  ';

  return $form;
}
add_shortcode('custom_add_to_cart', 'custom_add_to_cart');

JS 'Redirect' (requires DOMPurify: yarn add dompurify)

import * as DOMPurify from 'dompurify';

...

// Pass variable to query string
$("form.custom-add-to-cart").on("submit", function(e) {
  e.preventDefault();

  let data = $(this).find(":input"),
    qty = DOMPurify.sanitize(data[0].value),
    product = DOMPurify.sanitize(data[1].value),
    cart = DOMPurify.sanitize(data[2].value);

  let newUrl = `${cart}?add-to-cart=${product}&quantity=${qty}`;

  window.location.href = newUrl;
});

MISC PHP Functions

Here's some other common functions to add in as needed.

// Slugify strings
function slugify($str, $delimiter = '-'){
  $slug = strtolower(trim(preg_replace('/[\s-]+/', $delimiter, preg_replace('/[^A-Za-z0-9-]+/', $delimiter, preg_replace('/[&]/', 'and', preg_replace('/[\']/', '', iconv('UTF-8', 'ASCII//TRANSLIT', $str))))), $delimiter));
  return $slug;
}

// Custom Excerpt Length
function custom_excerpt_length( $length ) {
  return 20;
}
add_filter( 'excerpt_length', 'custom_excerpt_length', 999 );

// Adjust queries
function adjust_queries($query) {
  // Blog 
  if( !is_admin() && (is_home() || is_category() || is_tag() || is_search() ) && $query->is_main_query() ) {
    $featured = get_field('blog_featured_post', get_option('page_for_posts'))->ID;

    if( $featured ) {
      $query->set('post__not_in', array($featured));
    }
  }
}
add_action('pre_get_posts', 'adjust_queries');