Files
wp-bootstrap/functions.php
magdev 5268289782
All checks were successful
Create Release Package / PHP Lint (push) Successful in 50s
Create Release Package / Build Release (push) Successful in 1m14s
v1.0.0 - Release: widget area, documentation refresh
- Register sidebar widget area via register_sidebar()
- Render WordPress widgets in Twig sidebar with fallback to built-in content
- Update README.md with accurate feature counts and descriptions
- Update translation files with widget area strings
- Bump version to 1.0.0

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-08 18:43:09 +01:00

798 lines
30 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* WP Bootstrap functions and definitions.
*
* @link https://developer.wordpress.org/themes/basics/theme-functions/
*
* @package WPBootstrap
* @since 0.0.1
*/
// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Load Composer autoloader.
if ( file_exists( get_template_directory() . '/vendor/autoload.php' ) ) {
require_once get_template_directory() . '/vendor/autoload.php';
}
/**
* Sets up theme defaults and registers support for various WordPress features.
*/
if ( ! function_exists( 'wp_bootstrap_setup' ) ) :
function wp_bootstrap_setup() {
// Add support for post formats.
add_theme_support( 'post-formats', array(
'aside', 'audio', 'chat', 'gallery', 'image',
'link', 'quote', 'status', 'video',
) );
// Make theme available for translation.
load_theme_textdomain( 'wp-bootstrap', get_template_directory() . '/languages' );
// Add editor styles.
add_editor_style( 'assets/css/editor-style.css' );
// Register navigation menu locations.
register_nav_menus( array(
'primary' => __( 'Primary Navigation', 'wp-bootstrap' ),
'footer' => __( 'Footer Navigation', 'wp-bootstrap' ),
) );
}
endif;
add_action( 'after_setup_theme', 'wp_bootstrap_setup' );
/**
* Register widget areas.
*
* @since 1.0.0
*/
if ( ! function_exists( 'wp_bootstrap_register_sidebars' ) ) :
function wp_bootstrap_register_sidebars() {
register_sidebar( array(
'name' => __( 'Sidebar', 'wp-bootstrap' ),
'id' => 'primary-sidebar',
'description' => __( 'Add widgets here to appear in the sidebar.', 'wp-bootstrap' ),
'before_widget' => '<div id="%1$s" class="widget mb-4 %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="sidebar-heading h6 text-uppercase fw-semibold">',
'after_title' => '</h3>',
) );
}
endif;
add_action( 'widgets_init', 'wp_bootstrap_register_sidebars' );
/**
* Enqueue theme scripts and styles.
*/
if ( ! function_exists( 'wp_bootstrap_enqueue_scripts' ) ) :
function wp_bootstrap_enqueue_scripts() {
$theme_version = wp_get_theme()->get( 'Version' );
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
// Enqueue the compiled Bootstrap + custom CSS.
wp_enqueue_style(
'wp-bootstrap-style',
get_template_directory_uri() . '/assets/css/style' . $suffix . '.css',
array(),
$theme_version
);
// Enqueue Bootstrap JS bundle (includes Popper).
wp_enqueue_script(
'wp-bootstrap-js',
get_template_directory_uri() . '/assets/js/bootstrap.bundle.min.js',
array(),
$theme_version,
true
);
// Enqueue dark mode toggle script.
wp_enqueue_script(
'wp-bootstrap-dark-mode',
get_template_directory_uri() . '/assets/js/dark-mode.js',
array(),
$theme_version,
array(
'strategy' => 'defer',
'in_footer' => false,
)
);
// Inline script to prevent flash of wrong theme.
wp_add_inline_script(
'wp-bootstrap-dark-mode',
'(function(){var t=localStorage.getItem("wp-bootstrap-theme")||(window.matchMedia("(prefers-color-scheme:dark)").matches?"dark":"light");document.documentElement.setAttribute("data-bs-theme",t)})();',
'before'
);
}
endif;
add_action( 'wp_enqueue_scripts', 'wp_bootstrap_enqueue_scripts' );
/**
* Preload critical fonts for performance.
*
* @since 0.3.0
*/
if ( ! function_exists( 'wp_bootstrap_preload_fonts' ) ) :
function wp_bootstrap_preload_fonts() {
$fonts = array(
'inter/InterVariable.woff2',
'lora/Lora-VariableFont.woff2',
);
$base = get_template_directory_uri() . '/assets/fonts/';
foreach ( $fonts as $font ) {
printf(
'<link rel="preload" href="%s" as="font" type="font/woff2" crossorigin>' . "\n",
esc_url( $base . $font )
);
}
}
endif;
add_action( 'wp_head', 'wp_bootstrap_preload_fonts', 1 );
/**
* Enqueue RTL stylesheet for right-to-left languages.
*
* @since 0.3.0
*/
if ( ! function_exists( 'wp_bootstrap_rtl_styles' ) ) :
function wp_bootstrap_rtl_styles() {
if ( ! is_rtl() ) {
return;
}
$theme_version = wp_get_theme()->get( 'Version' );
wp_enqueue_style(
'wp-bootstrap-rtl',
get_template_directory_uri() . '/assets/css/rtl.css',
array( 'wp-bootstrap-style' ),
$theme_version
);
}
endif;
add_action( 'wp_enqueue_scripts', 'wp_bootstrap_rtl_styles', 20 );
/**
* Bridge WordPress style variation colors to Bootstrap CSS custom properties.
*
* Reads the active color palette (theme.json + variation + user overrides)
* and outputs inline CSS for both light and dark modes so the dark-mode toggle
* switches between two variation-aware color schemes.
*
* Theme colors (primaryinfo) go into :root and apply in both modes.
* Surface colors (body-bg, tertiary-bg, etc.) are computed separately for
* [data-bs-theme=light] and [data-bs-theme=dark].
*
* For light palettes: light mode uses base/contrast; dark mode uses dark/light slugs.
* For dark palettes: dark mode uses base/contrast; light mode swaps them.
*
* @since 0.3.2
*/
if ( ! function_exists( 'wp_bootstrap_variation_colors' ) ) :
function wp_bootstrap_variation_colors() {
// Read the theme origin palette — this contains the base theme.json
// colors merged with the active style variation (if any).
$theme_palette = wp_get_global_settings( array( 'color', 'palette', 'theme' ) );
$colors = array();
if ( ! empty( $theme_palette ) && is_array( $theme_palette ) ) {
foreach ( $theme_palette as $entry ) {
if ( ! empty( $entry['slug'] ) && ! empty( $entry['color'] ) ) {
$colors[ $entry['slug'] ] = $entry['color'];
}
}
}
// Compare against base theme.json defaults to detect an active variation.
// WordPress puts variation colors in the 'theme' origin, not 'custom'.
$base_defaults = array(
'base' => '#ffffff',
'contrast' => '#212529',
'primary' => '#0d6efd',
);
$is_default = true;
foreach ( $base_defaults as $slug => $default_color ) {
if ( ! empty( $colors[ $slug ] ) && strtolower( $colors[ $slug ] ) !== $default_color ) {
$is_default = false;
break;
}
}
// No variation active — let Bootstrap's compiled CSS handle both modes.
if ( $is_default ) {
return;
}
if ( empty( $colors['base'] ) || empty( $colors['contrast'] ) ) {
return;
}
// Theme colors apply in both modes via :root.
$theme_slugs = array(
'primary' => '--bs-primary',
'secondary' => '--bs-secondary',
'success' => '--bs-success',
'danger' => '--bs-danger',
'warning' => '--bs-warning',
'info' => '--bs-info',
);
$root_css = '';
foreach ( $theme_slugs as $slug => $var ) {
if ( ! empty( $colors[ $slug ] ) ) {
$hex = esc_attr( $colors[ $slug ] );
$rgb = wp_bootstrap_hex_to_rgb( $colors[ $slug ] );
$root_css .= "{$var}:{$hex};";
if ( $rgb ) {
$root_css .= "{$var}-rgb:{$rgb};";
}
}
}
// Link colors from primary (both modes).
if ( ! empty( $colors['primary'] ) ) {
$primary_rgb = wp_bootstrap_hex_to_rgb( $colors['primary'] );
$root_css .= '--bs-link-color:' . esc_attr( $colors['primary'] ) . ';';
$root_css .= '--bs-link-color-rgb:' . $primary_rgb . ';';
$root_css .= '--bs-link-hover-color:' . esc_attr( $colors['primary'] ) . ';';
$root_css .= '--bs-link-hover-color-rgb:' . $primary_rgb . ';';
}
// Determine if this is a dark palette (base luminance < contrast luminance).
$is_dark = wp_bootstrap_relative_luminance( $colors['base'] )
< wp_bootstrap_relative_luminance( $colors['contrast'] );
// Resolve light-mode and dark-mode base colors.
if ( $is_dark ) {
// Dark palette: dark mode is native, light mode swaps base↔contrast.
$light_bg = $colors['contrast'];
$light_fg = $colors['base'];
$dark_bg = $colors['base'];
$dark_fg = $colors['contrast'];
} else {
// Light palette: light mode is native, dark mode uses dark/light slugs.
$light_bg = $colors['base'];
$light_fg = $colors['contrast'];
$dark_bg = $colors['dark'] ?? '#212529';
$dark_fg = $colors['light'] ?? '#f8f9fa';
}
// Also set light/dark slug variables for utilities like bg-light, bg-dark.
if ( ! empty( $colors['light'] ) ) {
$root_css .= '--bs-light:' . esc_attr( $colors['light'] ) . ';';
$root_css .= '--bs-light-rgb:' . wp_bootstrap_hex_to_rgb( $colors['light'] ) . ';';
}
if ( ! empty( $colors['dark'] ) ) {
$root_css .= '--bs-dark:' . esc_attr( $colors['dark'] ) . ';';
$root_css .= '--bs-dark-rgb:' . wp_bootstrap_hex_to_rgb( $colors['dark'] ) . ';';
}
// Build surface CSS for a given bg/fg pair.
$light_css = wp_bootstrap_build_surface_css( $light_bg, $light_fg, false );
$dark_css = wp_bootstrap_build_surface_css( $dark_bg, $dark_fg, true );
$css = ':root{' . $root_css . '}'
. '[data-bs-theme=light]{' . $light_css . '}'
. '[data-bs-theme=dark]{' . $dark_css . '}';
// Attach after the compiled stylesheet so variation values override
// Bootstrap's hardcoded dark-mode defaults via source order.
wp_add_inline_style( 'wp-bootstrap-style', $css );
}
endif;
add_action( 'wp_enqueue_scripts', 'wp_bootstrap_variation_colors', 30 );
/**
* Build Bootstrap surface CSS variables for a given background/foreground pair.
*
* Computes body-bg, body-color, tertiary-bg, secondary-bg, secondary-color,
* emphasis-color, and border-color — mirroring how Bootstrap derives them.
*
* @since 0.3.2
*
* @param string $bg Background hex color.
* @param string $fg Foreground (text) hex color.
* @param bool $is_dark Whether this is for dark mode.
* @return string CSS declarations (no selector).
*/
if ( ! function_exists( 'wp_bootstrap_build_surface_css' ) ) :
function wp_bootstrap_build_surface_css( $bg, $fg, $is_dark ) {
$bg_rgb = wp_bootstrap_hex_to_rgb( $bg );
$fg_rgb = wp_bootstrap_hex_to_rgb( $fg );
$css = '--bs-body-bg:' . esc_attr( $bg ) . ';';
$css .= '--bs-body-bg-rgb:' . $bg_rgb . ';';
$css .= '--bs-body-color:' . esc_attr( $fg ) . ';';
$css .= '--bs-body-color-rgb:' . $fg_rgb . ';';
if ( $is_dark ) {
$secondary_bg = wp_bootstrap_mix_hex( $fg, $bg, 0.16 );
$tertiary_bg = wp_bootstrap_mix_hex( $fg, $bg, 0.08 );
$border_color = wp_bootstrap_mix_hex( $fg, $bg, 0.24 );
$emphasis = '#FFFFFF';
} else {
$secondary_bg = wp_bootstrap_mix_hex( $fg, $bg, 0.08 );
$tertiary_bg = wp_bootstrap_mix_hex( $fg, $bg, 0.04 );
$border_color = wp_bootstrap_mix_hex( $fg, $bg, 0.16 );
$emphasis = '#000000';
}
$css .= '--bs-secondary-color:rgba(' . $fg_rgb . ',0.75);';
$css .= '--bs-secondary-bg:' . $secondary_bg . ';';
$css .= '--bs-secondary-bg-rgb:' . wp_bootstrap_hex_to_rgb( $secondary_bg ) . ';';
$css .= '--bs-tertiary-color:rgba(' . $fg_rgb . ',0.5);';
$css .= '--bs-tertiary-bg:' . $tertiary_bg . ';';
$css .= '--bs-tertiary-bg-rgb:' . wp_bootstrap_hex_to_rgb( $tertiary_bg ) . ';';
$css .= '--bs-emphasis-color:' . $emphasis . ';';
$css .= '--bs-emphasis-color-rgb:' . wp_bootstrap_hex_to_rgb( $emphasis ) . ';';
$css .= '--bs-border-color:' . $border_color . ';';
return $css;
}
endif;
/**
* Convert a hex color string to an RGB triplet string.
*
* @since 0.3.2
*
* @param string $hex Hex color (e.g. "#0d6efd" or "0d6efd").
* @return string RGB triplet (e.g. "13,110,253") or empty string on failure.
*/
if ( ! function_exists( 'wp_bootstrap_hex_to_rgb' ) ) :
function wp_bootstrap_hex_to_rgb( $hex ) {
$hex = ltrim( $hex, '#' );
if ( strlen( $hex ) === 3 ) {
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
}
if ( strlen( $hex ) !== 6 ) {
return '';
}
return hexdec( substr( $hex, 0, 2 ) ) . ','
. hexdec( substr( $hex, 2, 2 ) ) . ','
. hexdec( substr( $hex, 4, 2 ) );
}
endif;
/**
* Mix two hex colors by a given weight.
*
* @since 0.3.2
*
* @param string $color1 Hex color to mix in.
* @param string $color2 Base hex color.
* @param float $weight Weight of color1 (0.0 to 1.0).
* @return string Resulting hex color.
*/
if ( ! function_exists( 'wp_bootstrap_mix_hex' ) ) :
function wp_bootstrap_mix_hex( $color1, $color2, $weight ) {
$c1 = wp_bootstrap_hex_to_rgb_array( $color1 );
$c2 = wp_bootstrap_hex_to_rgb_array( $color2 );
if ( ! $c1 || ! $c2 ) {
return $color2;
}
$r = (int) round( $c1[0] * $weight + $c2[0] * ( 1 - $weight ) );
$g = (int) round( $c1[1] * $weight + $c2[1] * ( 1 - $weight ) );
$b = (int) round( $c1[2] * $weight + $c2[2] * ( 1 - $weight ) );
return sprintf( '#%02x%02x%02x', max( 0, min( 255, $r ) ), max( 0, min( 255, $g ) ), max( 0, min( 255, $b ) ) );
}
endif;
/**
* Convert a hex color to an array of [r, g, b] integers.
*
* @since 0.3.2
*
* @param string $hex Hex color.
* @return array|false Array of [r, g, b] or false on failure.
*/
if ( ! function_exists( 'wp_bootstrap_hex_to_rgb_array' ) ) :
function wp_bootstrap_hex_to_rgb_array( $hex ) {
$hex = ltrim( $hex, '#' );
if ( strlen( $hex ) === 3 ) {
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
}
if ( strlen( $hex ) !== 6 ) {
return false;
}
return array(
hexdec( substr( $hex, 0, 2 ) ),
hexdec( substr( $hex, 2, 2 ) ),
hexdec( substr( $hex, 4, 2 ) ),
);
}
endif;
/**
* Compute relative luminance of a hex color (0.0 = black, 1.0 = white).
*
* @since 0.3.2
*
* @param string $hex Hex color.
* @return float Relative luminance.
*/
if ( ! function_exists( 'wp_bootstrap_relative_luminance' ) ) :
function wp_bootstrap_relative_luminance( $hex ) {
$rgb = wp_bootstrap_hex_to_rgb_array( $hex );
if ( ! $rgb ) {
return 0.0;
}
$channels = array();
foreach ( $rgb as $val ) {
$val /= 255;
$channels[] = ( $val <= 0.03928 ) ? $val / 12.92 : pow( ( $val + 0.055 ) / 1.055, 2.4 );
}
return 0.2126 * $channels[0] + 0.7152 * $channels[1] + 0.0722 * $channels[2];
}
endif;
/**
* Enqueue Bootstrap JS in the block editor for interactive previews.
*
* @since 0.2.0
*/
if ( ! function_exists( 'wp_bootstrap_enqueue_editor_assets' ) ) :
function wp_bootstrap_enqueue_editor_assets() {
$theme_version = wp_get_theme()->get( 'Version' );
wp_enqueue_script(
'wp-bootstrap-editor-js',
get_template_directory_uri() . '/assets/js/bootstrap.bundle.min.js',
array(),
$theme_version,
true
);
}
endif;
add_action( 'enqueue_block_editor_assets', 'wp_bootstrap_enqueue_editor_assets' );
/**
* Register custom block categories for Bootstrap components.
*
* @since 0.2.0
*
* @param array $categories Existing block categories.
* @param WP_Block_Editor_Context $context Block editor context.
* @return array Modified categories.
*/
if ( ! function_exists( 'wp_bootstrap_block_categories' ) ) :
function wp_bootstrap_block_categories( array $categories, $context ): array {
$bootstrap_categories = array(
array(
'slug' => 'wp-bootstrap-layout',
'title' => __( 'Bootstrap Layout', 'wp-bootstrap' ),
'icon' => 'layout',
),
array(
'slug' => 'wp-bootstrap-components',
'title' => __( 'Bootstrap Components', 'wp-bootstrap' ),
'icon' => 'grid-view',
),
array(
'slug' => 'wp-bootstrap-navigation',
'title' => __( 'Bootstrap Navigation', 'wp-bootstrap' ),
'icon' => 'menu',
),
);
return array_merge( $bootstrap_categories, $categories );
}
endif;
add_filter( 'block_categories_all', 'wp_bootstrap_block_categories', 10, 2 );
/**
* Register block pattern categories.
*/
if ( ! function_exists( 'wp_bootstrap_pattern_categories' ) ) :
function wp_bootstrap_pattern_categories() {
register_block_pattern_category(
'wp-bootstrap_page',
array(
'label' => __( 'Pages', 'wp-bootstrap' ),
'description' => __( 'A collection of full page layouts.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_hero',
array(
'label' => __( 'Hero Sections', 'wp-bootstrap' ),
'description' => __( 'Large hero and banner sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_cta',
array(
'label' => __( 'Call to Action', 'wp-bootstrap' ),
'description' => __( 'Call to action sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_features',
array(
'label' => __( 'Features', 'wp-bootstrap' ),
'description' => __( 'Feature and service showcase sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_testimonials',
array(
'label' => __( 'Testimonials', 'wp-bootstrap' ),
'description' => __( 'Testimonial and review sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_pricing',
array(
'label' => __( 'Pricing', 'wp-bootstrap' ),
'description' => __( 'Pricing table sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_contact',
array(
'label' => __( 'Contact', 'wp-bootstrap' ),
'description' => __( 'Contact information sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap_text',
array(
'label' => __( 'Text & Content', 'wp-bootstrap' ),
'description' => __( 'Text-focused content sections.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap-layout',
array(
'label' => __( 'Layout', 'wp-bootstrap' ),
'description' => __( 'Layout building blocks for page structure.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap-components',
array(
'label' => __( 'Components', 'wp-bootstrap' ),
'description' => __( 'Reusable Bootstrap component patterns.', 'wp-bootstrap' ),
)
);
register_block_pattern_category(
'wp-bootstrap-navigation',
array(
'label' => __( 'Navigation', 'wp-bootstrap' ),
'description' => __( 'Navigation and header patterns.', 'wp-bootstrap' ),
)
);
}
endif;
add_action( 'init', 'wp_bootstrap_pattern_categories' );
/**
* Register custom block styles for Bootstrap components.
*
* @since 0.1.0
*/
if ( ! function_exists( 'wp_bootstrap_block_styles' ) ) :
function wp_bootstrap_block_styles() {
// core/list - Checkmark style.
register_block_style( 'core/list', array(
'name' => 'checkmark-list',
'label' => __( 'Checkmark', 'wp-bootstrap' ),
'inline_style' => '
ul.is-style-checkmark-list { list-style-type: "\2713"; }
ul.is-style-checkmark-list li { padding-inline-start: 1ch; }',
) );
// core/list - Unstyled.
register_block_style( 'core/list', array(
'name' => 'list-unstyled',
'label' => __( 'Unstyled', 'wp-bootstrap' ),
'inline_style' => '
ul.is-style-list-unstyled, ol.is-style-list-unstyled { list-style: none; padding-inline-start: 0; }',
) );
// core/group - Card.
register_block_style( 'core/group', array(
'name' => 'card',
'label' => __( 'Card', 'wp-bootstrap' ),
'inline_style' => '
.is-style-card { border: 1px solid var(--wp--preset--color--light, #dee2e6); border-radius: 0.375rem; padding: var(--wp--preset--spacing--40); background: var(--wp--preset--color--base); }',
) );
// core/group - Card with Shadow.
register_block_style( 'core/group', array(
'name' => 'card-shadow',
'label' => __( 'Card with Shadow', 'wp-bootstrap' ),
'inline_style' => '
.is-style-card-shadow { border: 1px solid var(--wp--preset--color--light, #dee2e6); border-radius: 0.375rem; padding: var(--wp--preset--spacing--40); background: var(--wp--preset--color--base); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); }',
) );
// core/group - Alert Info.
register_block_style( 'core/group', array(
'name' => 'alert-info',
'label' => __( 'Alert - Info', 'wp-bootstrap' ),
'inline_style' => '
.is-style-alert-info { background-color: #cff4fc; border: 1px solid #9eeaf9; color: #055160; border-radius: 0.375rem; padding: var(--wp--preset--spacing--30); }',
) );
// core/group - Alert Success.
register_block_style( 'core/group', array(
'name' => 'alert-success',
'label' => __( 'Alert - Success', 'wp-bootstrap' ),
'inline_style' => '
.is-style-alert-success { background-color: #d1e7dd; border: 1px solid #a3cfbb; color: #0a3622; border-radius: 0.375rem; padding: var(--wp--preset--spacing--30); }',
) );
// core/group - Alert Warning.
register_block_style( 'core/group', array(
'name' => 'alert-warning',
'label' => __( 'Alert - Warning', 'wp-bootstrap' ),
'inline_style' => '
.is-style-alert-warning { background-color: #fff3cd; border: 1px solid #ffe69c; color: #664d03; border-radius: 0.375rem; padding: var(--wp--preset--spacing--30); }',
) );
// core/group - Alert Danger.
register_block_style( 'core/group', array(
'name' => 'alert-danger',
'label' => __( 'Alert - Danger', 'wp-bootstrap' ),
'inline_style' => '
.is-style-alert-danger { background-color: #f8d7da; border: 1px solid #f1aeb5; color: #58151c; border-radius: 0.375rem; padding: var(--wp--preset--spacing--30); }',
) );
// core/table - Striped Rows.
register_block_style( 'core/table', array(
'name' => 'table-striped',
'label' => __( 'Striped Rows', 'wp-bootstrap' ),
'inline_style' => '
.is-style-table-striped tbody tr:nth-of-type(odd) > * { background-color: rgba(0, 0, 0, 0.05); }',
) );
// core/table - Hover Rows.
register_block_style( 'core/table', array(
'name' => 'table-hover',
'label' => __( 'Hover Rows', 'wp-bootstrap' ),
'inline_style' => '
.is-style-table-hover tbody tr:hover > * { background-color: rgba(0, 0, 0, 0.075); }',
) );
// core/table - Bordered.
register_block_style( 'core/table', array(
'name' => 'table-bordered',
'label' => __( 'Bordered', 'wp-bootstrap' ),
'inline_style' => '
.is-style-table-bordered, .is-style-table-bordered td, .is-style-table-bordered th { border: 1px solid var(--wp--preset--color--light, #dee2e6); }',
) );
// core/quote - Accent Border.
register_block_style( 'core/quote', array(
'name' => 'blockquote-accent',
'label' => __( 'Accent Border', 'wp-bootstrap' ),
'inline_style' => '
.is-style-blockquote-accent { border-inline-start: 4px solid var(--wp--preset--color--primary); background: var(--wp--preset--color--light); padding: var(--wp--preset--spacing--30); border-start-start-radius: 0; border-start-end-radius: 0.375rem; border-end-end-radius: 0.375rem; border-end-start-radius: 0; }',
) );
// core/image - Shadow.
register_block_style( 'core/image', array(
'name' => 'shadow',
'label' => __( 'Shadow', 'wp-bootstrap' ),
'inline_style' => '
.is-style-shadow img { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); }',
) );
// core/image - Large Rounded.
register_block_style( 'core/image', array(
'name' => 'rounded-lg',
'label' => __( 'Large Rounded', 'wp-bootstrap' ),
'inline_style' => '
.is-style-rounded-lg img { border-radius: 0.75rem; }',
) );
// core/button - Large.
register_block_style( 'core/button', array(
'name' => 'btn-lg',
'label' => __( 'Large', 'wp-bootstrap' ),
'inline_style' => '
.is-style-btn-lg .wp-block-button__link { padding: 0.75rem 1.5rem; font-size: 1.25rem; border-radius: 0.5rem; }',
) );
// core/button - Small.
register_block_style( 'core/button', array(
'name' => 'btn-sm',
'label' => __( 'Small', 'wp-bootstrap' ),
'inline_style' => '
.is-style-btn-sm .wp-block-button__link { padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.25rem; }',
) );
// core/separator - Wide.
register_block_style( 'core/separator', array(
'name' => 'separator-wide',
'label' => __( 'Wide', 'wp-bootstrap' ),
'inline_style' => '
.is-style-separator-wide { max-width: none; }',
) );
}
endif;
add_action( 'init', 'wp_bootstrap_block_styles' );
/**
* Initialize Twig template engine.
*/
if ( ! function_exists( 'wp_bootstrap_init_twig' ) ) :
function wp_bootstrap_init_twig() {
if ( class_exists( '\\WPBootstrap\\Twig\\TwigService' ) ) {
\WPBootstrap\Twig\TwigService::getInstance();
}
}
endif;
add_action( 'after_setup_theme', 'wp_bootstrap_init_twig' );
/**
* Initialize Twig template controller for frontend rendering.
*
* Hooks into template_redirect to render Bootstrap 5 HTML
* via Twig templates instead of FSE block markup on the frontend.
*
* @since 0.1.1
*/
if ( ! function_exists( 'wp_bootstrap_init_templates' ) ) :
function wp_bootstrap_init_templates() {
if ( class_exists( '\\WPBootstrap\\Template\\TemplateController' ) ) {
new \WPBootstrap\Template\TemplateController();
}
}
endif;
add_action( 'after_setup_theme', 'wp_bootstrap_init_templates' );
/**
* Customize comment form fields with Bootstrap classes.
*
* @since 0.1.1
*
* @param array $fields Default comment form fields.
* @return array Modified fields with Bootstrap classes.
*/
if ( ! function_exists( 'wp_bootstrap_comment_form_fields' ) ) :
function wp_bootstrap_comment_form_fields( array $fields ): array {
$commenter = wp_get_current_commenter();
$required = get_option( 'require_name_email' );
$req_attr = $required ? ' required' : '';
$fields['author'] = '<div class="mb-3">'
. '<label for="author" class="form-label">' . __( 'Name', 'wp-bootstrap' ) . ( $required ? ' <span class="text-danger">*</span>' : '' ) . '</label>'
. '<input id="author" name="author" type="text" class="form-control" value="' . esc_attr( $commenter['comment_author'] ) . '"' . $req_attr . '>'
. '</div>';
$fields['email'] = '<div class="mb-3">'
. '<label for="email" class="form-label">' . __( 'Email', 'wp-bootstrap' ) . ( $required ? ' <span class="text-danger">*</span>' : '' ) . '</label>'
. '<input id="email" name="email" type="email" class="form-control" value="' . esc_attr( $commenter['comment_author_email'] ) . '"' . $req_attr . '>'
. '</div>';
$fields['url'] = '<div class="mb-3">'
. '<label for="url" class="form-label">' . __( 'Website', 'wp-bootstrap' ) . '</label>'
. '<input id="url" name="url" type="url" class="form-control" value="' . esc_attr( $commenter['comment_author_url'] ) . '">'
. '</div>';
if ( isset( $fields['cookies'] ) ) {
$fields['cookies'] = '<div class="mb-3 form-check">'
. '<input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" class="form-check-input" value="yes">'
. '<label for="wp-comment-cookies-consent" class="form-check-label">'
. __( 'Save my name, email, and website in this browser for the next time I comment.', 'wp-bootstrap' )
. '</label></div>';
}
return $fields;
}
endif;
add_filter( 'comment_form_default_fields', 'wp_bootstrap_comment_form_fields' );