baseline functions

This commit is contained in:
2025-09-04 16:06:34 +01:00
parent fa02de6495
commit 945d685586
27 changed files with 15904 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
<?php
namespace App\ACF;
class CloneGroup
{
public function __construct()
{
}
public function block_background()
{
return [
'contrast',
'bg_colour',
'bg_tint',
];
}
public function block_intro()
{
return [
'overline',
'heading',
'blurb',
'intro_alignment',
];
}
public function block_footer()
{
return [
'blurb_footer',
'links',
'footer_alignment',
];
}
public function block_settings()
{
return [
'section_anchor_id',
'padding_top',
'padding_bottom',
'container_width',
'angle_status',
'angle_position',
'angle_direction',
'angle_colour',
'angle_tint',
];
}
public function block_all()
{
return array_merge($this->block_intro(), $this->block_footer(), $this->block_settings(), $this->block_background());
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace App\ACF;
use ourcodeworld\NameThatColor\ColorInterpreter as NameThatColor;
use App\Utilities;
class Dynamic
{
public function __construct()
{
add_filter('acf/load_field/name=colour', [ $this, 'load_colours' ]);
add_filter('acf/load_field/name=bg_colour', [ $this, 'load_colours' ]);
add_filter('acf/load_field/name=tint', [ $this, 'load_tints' ]);
add_filter('acf/load_field/name=bg_tint', [ $this, 'load_tints' ]);
add_filter('acf/load_field/name=fontawesome_regular', [ $this, 'load_fontawesome_regular_icons' ]);
add_filter('acf/load_field/name=fontawesome_solid', [ $this, 'load_fontawesome_solid_icons' ]);
add_filter('acf/load_field/name=fontawesome_brands', [ $this, 'load_fontawesome_brand_icons' ]);
add_action( 'acf/input/admin_footer', [$this, 'colour_ui'] );
}
public function load_colours( $field )
{
$colour = new Utilities\Colour;
$NameThatColour = new NameThatColor;
$defined = get_field('badegg_colours', 'option');
$colours = $colour->values();
$field['choices'] = [];
foreach($colours as $slug => $hex):
$field['choices'][$slug] = '<i class="fas fa-circle" style="color: '. $hex .'"></i> ' . @$NameThatColour->name($hex)['name'];
endforeach;
$field['choices']['quaternary-white'] = '<i class="fas fa-circle text-gradient text-gradient-quaternary-white"></i> ' . @$NameThatColour->name($colour->name2hex('quaternary'))['name'] . ' to White';
$field['choices']['quinary-white'] = '<i class="fas fa-circle text-gradient text-gradient-quinary-white"></i> ' . @$NameThatColour->name($colour->name2hex('quinary'))['name'] . ' to White';
$field['choices']['white-quaternary'] = '<i class="fas fa-circle text-gradient text-gradient-white-quaternary"></i> White to ' . @$NameThatColour->name($colour->name2hex('quaternary'))['name'];
$field['choices']['white-quinary'] = '<i class="fas fa-circle text-gradient text-gradient-white-quinary"></i> White to ' . @$NameThatColour->name($colour->name2hex('quinary'))['name'];
return $field;
}
public function load_tints( $field )
{
$colour = new Utilities\Colour;
$tints = $colour->tints();
$field['choices'] = [];
foreach($tints as $slug => $hex):
if($slug):
$field['choices'][$slug] = ucfirst($slug);
else:
$field['choices'][0] = 'None';
endif;
endforeach;
return $field;
}
public function load_fontawesome_regular_icons( $field )
{
$field['choices'] = [];
$field['choices'] = $this->fontawesome_choices('regular');
return $field;
}
public function load_fontawesome_solid_icons( $field )
{
$field['choices'] = [];
$field['choices'] = $this->fontawesome_choices('solid');
return $field;
}
public function load_fontawesome_brand_icons( $field )
{
$field['choices'] = [];
$field['choices'] = $this->fontawesome_choices('brands');
return $field;
}
public function fontawesome_choices($set = 'solid')
{
$path = get_stylesheet_directory() . '/resources/json/font-awesome-' . $set . '.json';
$json = @file_get_contents($path);
if(!$json) return false;
$icons = json_decode($json, true);
$choices = [
'0' => '<i class="fa-solid"></i> <span>Please select an icon</span>',
];
foreach($icons as $slug => $props):
if(in_array($slug, range(0,9))) continue;
$choices[$slug] = '<i class="fa-'.$set.' fa-'.$slug.'" style="color: #2271b1;"></i> <span>' . (ucwords(str_replace('-', ' ', $slug))) . '</span>';
endforeach;
return $choices;
}
public function colour_ui()
{ ?>
<script type="text/javascript">
console.log("Script loaded from sage/app/ACF/Dynamic.php");
(function($) {
function my_custom_escaping_method( original_value){
return original_value;
}
acf.add_filter('select2_escape_markup', function( escaped_value, original_value, $select, settings, field, instance ){
console.log(field.data('name'));
const whitelist = [
'colour',
'bg_colour',
'angle_colour',
];
// do something to the original_value to override the default escaping, then return it.
// this value should still have some kind of escaping for security, but you may wish to allow specific HTML.
if (whitelist.includes(field.data( 'name' ))) {
return my_custom_escaping_method( original_value );
}
// return
return escaped_value;
});
})(jQuery);
</script>
<?php }
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\ACF;
class JSON
{
public function __construct()
{
add_filter('acf/settings/save_json', [$this, 'save']);
add_filter('acf/settings/load_json', [$this, 'load']);
}
public function save( $path )
{
$path = get_stylesheet_directory() . '/resources/acf';
return $path;
}
public function load( $paths )
{
unset($paths[0]);
$paths[] = get_stylesheet_directory() . '/resources/acf';
return $paths;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\ACF;
class Options
{
public function __construct()
{
add_filter('acf/init', [$this, 'company']);
}
public function company()
{
acf_add_options_page([
'page_title' => __('Global Settings'),
'menu_title' => __('Global Settings'),
'menu_slug' => 'theme-global-settings',
'capability' => 'edit_others_posts',
'redirect' => false,
'icon_url' => 'dashicons-admin-site',
]);
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace App\Admin;
class Comments
{
public function __construct()
{
add_action('admin_init', [$this, 'commentstatusdiv']); // Disable comment status div meta box
add_action('wp_dashboard_setup', [$this, 'dashboard_activity']); // Remove the Activity widget
add_action('wp_before_admin_bar_render', [$this, 'remove_menu_item']); // Remove from admin bar
add_action('admin_menu', [$this, 'admin_menu']); // Remove from backend menu
add_action('wp_dashboard_setup', [$this, 'dashboard_recent_comments']); // Remove Dashboard Meta Box
add_filter('comments_rewrite_rules', '__return_empty_array'); // Remove comment rewrite rule
add_action('after_theme_setup', [$this, 'theme_support']); // Remove comment theme support
add_filter('rewrite_rules_array', [$this, 'rewrite']); // Clean up rewrite rule
}
public function commentstatusdiv()
{
remove_meta_box( 'commentstatusdiv', 'post', 'normal' );
remove_post_type_support( 'post', 'comments' );
remove_meta_box( 'commentstatusdiv', 'page', 'normal' );
remove_post_type_support( 'page', 'comments' );
}
public function dashboard_activity()
{
remove_meta_box( 'dashboard_activity', 'dashboard', 'normal' );
}
public function remove_menu_item()
{
global $wp_admin_bar;
$wp_admin_bar->remove_menu('comments');
}
public function admin_menu()
{
remove_menu_page( 'edit-comments.php' );
remove_submenu_page( 'options-general.php', 'options-discussion.php' );
}
public function dashboard_recent_comments()
{
remove_meta_box( 'dashboard_recent_comments', 'dashboard', 'normal' );
}
public function theme_support()
{
remove_theme_support('comments');
}
public function rewrite($rules)
{
foreach ($rules as $rule => $rewrite) {
if (preg_match('/.*(feed)/', $rule)) {
unset($rules[$rule]);
}
if (preg_match('/.*(comment-page)/', $rule)) {
unset($rules[$rule]);
}
}
return $rules;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Admin;
class DisablePost
{
public function __construct()
{
add_filter('register_post_type_args', [$this, 'args'], 0, 2);
add_filter('register_taxonomy_args', [$this, 'args'], 0, 2);
}
public function args($args, $type)
{
$types = [
'post',
'post_tag',
'category',
];
if(in_array($type, $types)) {
$args['public'] = false;
}
return $args;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Admin;
class Enqueue
{
public function __construct()
{
add_action( 'admin_enqueue_scripts', [$this, 'fontawesome']);
}
public function fontawesome()
{
wp_enqueue_style(
'fontawesome',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css',
false,
'6.5.2',
'all'
);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Admin;
class Integrations
{
public function __construct()
{
add_action( 'wp_head', [$this, 'FathomAnalytics']);
}
public function FathomAnalytics()
{
$fathomID = get_field('badegg_integrations_fathom_id', 'option');
if($fathomID && WP_ENV == 'production'): ?>
<!-- Fathom - beautiful, simple website analytics -->
<script src="https://cdn.usefathom.com/script.js" data-site="<?= $fathomID ?>" defer></script>
<!-- / Fathom -->
<?php endif;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Admin;
class Menus
{
public function __construct()
{
add_action('admin_menu', [$this, 'cleanup_appearance']);
}
public function cleanup_appearance()
{
$customize_url = add_query_arg(
'return',
urlencode(
remove_query_arg(
wp_removable_query_args(),
wp_unslash( $_SERVER['REQUEST_URI'] )
)
),
'customize.php'
);
remove_submenu_page( 'themes.php', $customize_url );
remove_submenu_page( 'themes.php', 'widgets.php' );
remove_submenu_page( 'themes.php', 'site-editor.php' );
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace App\PostTypes;
class Driver
{
public function __construct()
{
add_action('init', [$this, 'register']);
}
public function register()
{
$td = 'sage';
$postType = 'driver';
register_extended_post_type(
$postType,
[
'labels' => [
'featured_image' => __('Portrait', $td),
],
'menu_position' => 40,
'supports' => [
'title',
'excerpt',
'thumbnail',
'page-attributes',
],
'menu_icon' => 'dashicons-car',
'rewrite' => false,
'has_archive' => false,
'publicly_queryable' => false,
'exclude_from_search' => true,
'capability_type' => 'page',
'show_in_nav_menus' => false,
'admin_cols' => [
'credentials' =>[
'title' => __('Credentials', $td),
'meta_key' => 'badegg_driver_credentials',
],
'driver_category' => [
'title' => __('Category', $td),
'taxonomy' => 'driver_category',
],
'portrait' => [
'title' => __('Portrait', $td),
'featured_image' => 'thumbnail',
'width' => 48,
// 'height' => 48,
],
],
],
);
register_extended_taxonomy(
'driver_category',
$postType,
[
// 'meta_box' => 'radio',
'rewrite' => false,
'publicly_queryable' => false,
'show_in_nav_menus' => false,
],
[
'singular' => __('Category', $td),
'plural' => __('Categories', $td),
]
);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\PostTypes;
class FAQ
{
public function __construct()
{
add_action('init', [$this, 'register']);
}
public function register()
{
$td = 'sage';
$postType = 'faq';
register_extended_post_type(
$postType,
[
'menu_position' => 40,
'supports' => [
'title',
'editor',
],
'menu_icon' => 'dashicons-admin-comments',
'rewrite' => false,
'has_archive' => false,
'publicly_queryable' => false,
'exclude_from_search' => true,
'capability_type' => 'page',
'show_in_nav_menus' => false,
'admin_cols' => [
'faq_category' => [
'title' => __('Category', $td),
'taxonomy' => 'faq_category',
],
],
],
);
register_extended_taxonomy(
'faq_category',
$postType,
[
// 'meta_box' => 'radio',
'rewrite' => false,
'publicly_queryable' => false,
'show_in_nav_menus' => false,
],
[
'singular' => __('Category', $td),
'plural' => __('Categories', $td),
]
);
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\PostTypes;
class Organization
{
public function __construct()
{
add_action('init', [$this, 'register']);
}
public function register()
{
$td = 'sage';
$postType = 'organization';
register_extended_post_type(
$postType,
[
'menu_position' => 40,
'labels' => [
'featured_image' => __('Logo', $td),
],
'supports' => [
'title',
'page-attributes',
'thumbnail',
],
'menu_icon' => 'dashicons-building',
'rewrite' => false,
'has_archive' => false,
'publicly_queryable' => false,
'exclude_from_search' => true,
'capability_type' => 'page',
'show_in_nav_menus' => false,
'admin_cols' => [
'organisation_relationship' => [
'title' => __('Relationship', $td),
'taxonomy' => 'organisation_relationship',
],
],
],
);
register_extended_taxonomy(
'organisation_relationship',
$postType,
[
'meta_box' => 'radio',
'rewrite' => false,
'publicly_queryable' => false,
],
[
'singular' => __('Relationship', $td),
'plural' => __('Relationships', $td),
]
);
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace App\PostTypes;
class Social
{
public function __construct()
{
add_action('init', [$this, 'register']);
}
public function register()
{
$td = 'sage';
$postType = 'social';
register_extended_post_type(
$postType,
[
'menu_position' => 28,
'supports' => [
'title',
'page-attributes',
],
'menu_icon' => 'dashicons-share',
'rewrite' => false,
'has_archive' => false,
'publicly_queryable' => false,
'exclude_from_search' => true,
'capability_type' => 'page',
'show_in_nav_menus' => false,
'admin_cols' => [
'social_link' => [
'title' => __('Social Link', $td),
'meta_key' => 'fontawesome_brands',
'function' => function(){
$icon = get_field('fontawesome_brands');
$url = get_field('url');
if($icon): ?>
<a
href="<?= $url ?: '#' ?>"
class="fa-brands fa-<?= $icon ?>"
rel="nofollow noindex"
style="font-size: 2em;"
></a>
<?php endif;
},
],
],
],
);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\PostTypes;
class Testimonial
{
public function __construct()
{
add_action('init', [$this, 'register']);
}
public function register()
{
$td = 'sage';
$postType = 'testimonial';
register_extended_post_type(
$postType,
[
'menu_position' => 40,
'supports' => [
'title',
],
'menu_icon' => 'dashicons-format-quote',
'rewrite' => false,
'has_archive' => false,
'publicly_queryable' => false,
'exclude_from_search' => true,
'capability_type' => 'page',
'show_in_nav_menus' => false,
'admin_cols' => [
'social_link' => [
'title' => __('Name', $td),
'meta_key' => 'badegg_testimonial_name',
],
],
],
);
}
}

View File

@@ -0,0 +1,161 @@
<?php
namespace App\Utilities;
class Colour
{
public function name2hex($colour = null, $tint = null)
{
if(!$colour) return false;
if($colour == 'black'):
$hex = '#000000';
elseif($colour == 'white'):
$hex = '#FFFFFF';
else:
// TODO: replace company_info settings page and lookup function
$hex = @$this->values()[(string)$colour];
endif;
if($tint):
$tints = $this->tints();
$hex = $this->adjustBrightness($hex, $tints[$tint]);
endif;
return $hex;
}
public function values()
{
$colours = get_field('badegg_colours', 'option');
$values = [];
if($colours):
foreach($colours as $index => $props):
$index = $index + 1;
$hex = @$props['hex'];
if($hex) $values[$this->latinate($index)] = $hex;
endforeach;
endif;
$values['0'] = '#FFFFFF';
$values['black'] = '#000000';
return $values;
}
public function tints()
{
return [
'lightest' => 100,
'lighter' => 66,
'light' => 33,
'0' => 0,
'dark' => -33,
'darker' => -66,
'darkest' => -100,
];
}
public function is_dark($colour = '#FFFFF')
{
// https://css-tricks.com/snippets/php/convert-hex-to-rgb/
if ( @$colour[0] == '#' ) $colour = substr( $colour, 1 );
if ( strlen( $colour ) == 6 ) {
list( $r, $g, $b ) = [
$colour[0] . $colour[1],
$colour[2] . $colour[3],
$colour[4] . $colour[5],
];
} elseif ( strlen( $colour ) == 3 ) {
list( $r, $g, $b ) = [
$colour[0] . $colour[0],
$colour[1] . $colour[1],
$colour[2] . $colour[2],
];
} else {
return false;
}
$r = hexdec( $r );
$g = hexdec( $g );
$b = hexdec( $b );
// return array( 'red' => $r, 'green' => $g, 'blue' => $b );
$hsp = sqrt(
0.299 * ($r * $r) +
0.587 * ($g * $g) +
0.114 * ($b * $b)
);
if($hsp > 200) {
return false;
} else {
return true;
}
}
public function is_light($colour = '#000000', $override = null)
{
if($this->is_dark($colour, $override)) {
return false;
} else {
return true;
}
}
public function adjustBrightness($hex, $steps)
{
// Steps should be between -255 and 255. Negative = darker, positive = lighter
$steps = max(-255, min(255, $steps));
// Normalize into a six character long hex string
$hex = str_replace('#', '', $hex);
if (strlen($hex) == 3) {
$hex = str_repeat(substr($hex,0,1), 2).str_repeat(substr($hex,1,1), 2).str_repeat(substr($hex,2,1), 2);
}
// Split into three parts: R, G and B
$color_parts = str_split($hex, 2);
$return = '#';
foreach ($color_parts as $color) {
$color = hexdec($color); // Convert to decimal
$color = max(0,min(255,$color + $steps)); // Adjust color
$return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code
}
return $return;
}
public function latinate($x = 0)
{
$latinate = [
1 => 'primary',
2 => 'secondary',
3 => 'tertiary',
4 => 'quaternary',
5 => 'quinary',
6 => 'senary',
7 => 'septenary',
8 => 'octonary',
9 => 'nonary',
10 => 'denary',
11 => 'undenary',
12 => 'duodenary',
];
if(array_key_exists($x, $latinate)):
return $latinate[$x];
else:
return 0;
endif;
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace App\Utilities;
class CssClasses {
public function section($props = [])
{
$Colour = new Colour;
$hex = $Colour->name2hex(@$props['bg_colour'], @$props['bg_tint']);
$pattern = @$props['pattern'];
$pattern_top = @$props['pattern_top'];
$pattern_bottom = @$props['pattern_bottom'];
$classes = [
'section',
'section-' . str_replace('acf/', '', $props['name']),
'bg-' . $this->colourTint([
'colour' => @$props['bg_colour'],
'tint' => @$props['bg_tint'],
]),
];
if(@$props['angle_status'])
$classes[] = 'section-has-angle';
if(@$props['angle_position'])
$classes[] = 'section-has-angle-' . $props['angle_position'];
if(@$props['padding_top'])
$classes[] = 'section-zero-top';
if(@$props['padding_bottom'])
$classes[] = 'section-zero-bottom';
if(@$props['bg_image'])
$classes[] = "bg-watermarked";
if($Colour->is_dark($hex) && $this->is_knockout_block($props['name']))
$classes[] = 'knockout';
if(@$props['className']) $args = array_merge($classes, explode(' ', $props['className']));
return $classes;
}
public function button($args = [])
{
$default_args = [
'colour' => null,
'style' => null,
];
$args = wp_parse_args($args, $default_args);
$classes = [
'button',
];
if($args['colour']) $classes[] = $args['colour'];
if($args['style']) $classes[] = $args['style'];
return $classes;
}
public function colourTint($props = [])
{
if(@$props['colour']):
$colour = $props['colour'];
if($props['colour'] != 'black' && @$props['tint']):
$colour .= '-' . $props['tint'];
endif;
else:
$colour = 'white';
endif;
return $colour;
}
public function is_knockout_block($name = null)
{
$blacklist = [
'cards-alternating',
];
if(in_array($name, $blacklist)):
return false;
else:
return true;
endif;
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace App\Utilities;
class ImageSrcset
{
public function add($args = [])
{
$args = wp_parse_args($args, $this->default_args());
$multipliers = $this->multipliers();
if(is_null($args['height'])) $args['height'] = $args['width'];
if($args['sizes'] < 5) $multipliers = array_slice($multipliers, 0, $args['sizes']);
foreach ( $multipliers as $slug => $scale ):
add_image_size (
$args['name'] . '-' . $slug,
round((int)$args['width'] * $scale),
round((int)$args['height'] * $scale),
$args['crop']
);
endforeach;
}
public function default_args()
{
return [
'name' => 'hero',
'width' => 1920,
'height' => null,
'crop' => true,
'sizes' => 5,
];
}
public function multipliers()
{
return [
'xl' => 1,
'lg' => 0.75,
'md' => 0.52083333,
'sm' => 0.33333333,
'xs' => 0.20833333,
];
}
public function render($args = [])
{
global $_wp_additional_image_sizes;
$default_args = [
'name' => 'hero',
'image' => null,
'lazy' => true,
'sizes' => 5,
'class' => null,
];
$args = wp_parse_args($args, $default_args);
$name = $args['name'];
$image = ($args['image']) ? $args['image'] : get_post_thumbnail_id();
if(!$image) return false;
$properties = @$_wp_additional_image_sizes[$name . '-xl'];
$width = @$properties['width'];
$height = @$properties['height'];
$sizes = [
'xl' => 1,
'lg' => 0.75,
'md' => 0.52083333,
'sm' => 0.33333333,
'xs' => 0.20833333,
];
if($args['sizes'] < 5) $sizes = array_slice($sizes, 0, $args['sizes']);
$class = $name . '-image';
if($args['class']) $class .= ' ' . $args['class'];
ob_start();
$full = wp_get_attachment_image_src($image, $name . '-xl');
$lazy = wp_get_attachment_image_src($image, 'lazy');
$alt = get_post_meta( $image, '_wp_attachment_image_alt', true );
$srcsets = [];
foreach($sizes as $size => $multiplier) {
$file = wp_get_attachment_image_src($image, $name . '-' . $size);
$srcsets[] = $file[0] . ' ' . $file[1] . 'w';
}
$atts = [
'class' => $class,
'src' => $full[0],
'srcset' => implode(', ', $srcsets),
'width' => $width,
'height' => $height,
'alt' => $alt,
];
if($args['lazy'] && !is_admin()):
$atts['class'] .= ' lazy';
$atts['src'] = $lazy[0];
$atts['srcset'] = null;
$atts['data-src'] = $full[0];
$atts['data-srcset'] = implode(', ', $srcsets);
endif;
?>
<img
<?php foreach($atts as $att => $value):
if($value) echo $att . '="' . $value . '" ';
endforeach; ?>
/>
<?php
return ob_get_clean();
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Utilities;
class VideoSrcset
{
public function sizes($video_srcset = [])
{
if(empty($video_srcset)) return false;
$sizes = [];
foreach($video_srcset as $size => $video):
if($video):
$sizes[$size] = $video['width'];
endif;
endforeach;
if(!empty($sizes)):
return json_encode($sizes);
else:
return false;
endif;
}
public function smallest($video_srcset = [])
{
if(empty($video_srcset)) return false;
$smallest = null;
foreach($video_srcset as $size => $video):
if($smallest) continue;
if($video) $smallest = $size;
endforeach;
return $smallest;
}
}