You've already forked wc-bootstrap
Initial theme scaffold from wp-theme-template
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
180
functions.php
Normal file
180
functions.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce Bootstrap functions and definitions.
|
||||
*
|
||||
* Child theme of WP Bootstrap that overrides WooCommerce plugin templates
|
||||
* with Bootstrap 5 structures and styling.
|
||||
*
|
||||
* @package WcBootstrap
|
||||
* @since 0.1.0
|
||||
*/
|
||||
|
||||
// Prevent direct access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define theme constants.
|
||||
*
|
||||
* CRITICAL: WordPress reads the version from TWO places:
|
||||
* 1. style.css header "Version:" — WordPress uses THIS for admin display
|
||||
* 2. This PHP constant — used internally by the theme
|
||||
* Both MUST be updated on every release.
|
||||
*/
|
||||
define( 'WC_BOOTSTRAP_VERSION', '0.1.0' );
|
||||
define( 'WC_BOOTSTRAP_PATH', get_stylesheet_directory() . '/' );
|
||||
define( 'WC_BOOTSTRAP_URL', get_stylesheet_directory_uri() . '/' );
|
||||
|
||||
/**
|
||||
* Load Composer autoloader if present.
|
||||
*/
|
||||
if ( file_exists( WC_BOOTSTRAP_PATH . 'vendor/autoload.php' ) ) {
|
||||
require_once WC_BOOTSTRAP_PATH . 'vendor/autoload.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up theme defaults and registers support for various WordPress features.
|
||||
*/
|
||||
function wc_bootstrap_setup(): void {
|
||||
// Make theme available for translation.
|
||||
load_child_theme_textdomain( 'wc-bootstrap', WC_BOOTSTRAP_PATH . 'languages' );
|
||||
}
|
||||
add_action( 'after_setup_theme', 'wc_bootstrap_setup' );
|
||||
|
||||
/**
|
||||
* Register plugin template overrides.
|
||||
*
|
||||
* Prepends the child theme's templates/ directory to the plugin's Twig loader,
|
||||
* so child theme templates take priority over plugin templates.
|
||||
*/
|
||||
function wc_bootstrap_register_template_override(): void {
|
||||
$override = new \WcBootstrap\TemplateOverride();
|
||||
$override->register();
|
||||
}
|
||||
add_action( 'after_setup_theme', 'wc_bootstrap_register_template_override' );
|
||||
|
||||
/**
|
||||
* Enqueue child theme styles.
|
||||
*
|
||||
* Loads parent theme stylesheet first, then child theme overrides.
|
||||
* CSS cascade order:
|
||||
* 1. wp-bootstrap (parent)
|
||||
* 2. woocommerce (plugin styles)
|
||||
* 3. wc-bootstrap-style (child theme style.css)
|
||||
* 4. wc-bootstrap-overrides (plugin CSS overrides)
|
||||
*/
|
||||
function wc_bootstrap_enqueue_styles(): void {
|
||||
$theme_version = wp_get_theme()->get( 'Version' );
|
||||
|
||||
// Enqueue parent theme stylesheet.
|
||||
wp_enqueue_style(
|
||||
'wp-bootstrap-style',
|
||||
get_template_directory_uri() . '/assets/css/style.min.css',
|
||||
array(),
|
||||
wp_get_theme( 'wp-bootstrap' )->get( 'Version' )
|
||||
);
|
||||
|
||||
// Enqueue child theme stylesheet.
|
||||
wp_enqueue_style(
|
||||
'wc-bootstrap-style',
|
||||
get_stylesheet_directory_uri() . '/style.css',
|
||||
array( 'wp-bootstrap-style' ),
|
||||
$theme_version
|
||||
);
|
||||
|
||||
// Enqueue plugin Bootstrap override styles.
|
||||
// Depend on plugin stylesheets so overrides always load after plugin CSS.
|
||||
wp_enqueue_style(
|
||||
'wc-bootstrap-overrides',
|
||||
get_stylesheet_directory_uri() . '/assets/css/wc-bootstrap.css',
|
||||
array( 'wc-bootstrap-style', 'woocommerce' ),
|
||||
$theme_version
|
||||
);
|
||||
}
|
||||
add_action( 'wp_enqueue_scripts', 'wc_bootstrap_enqueue_styles' );
|
||||
|
||||
/**
|
||||
* Handle plugin page rendering via plugin render filter.
|
||||
*
|
||||
* Delegates page rendering to the parent theme's TwigService so that plugin pages
|
||||
* share the same page shell (header, footer, layout) as native WordPress pages.
|
||||
* Falls back to letting the plugin handle rendering if the parent theme is not available.
|
||||
*
|
||||
* @param bool $rendered Whether the page has been rendered.
|
||||
* @param string $content Pre-rendered plugin HTML content.
|
||||
* @param array $context Plugin template context.
|
||||
* @return bool True if rendering was handled, false to let plugin use fallback.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_render_page( bool $rendered, string $content, array $context ): bool {
|
||||
if ( ! class_exists( '\WPBootstrap\Twig\TwigService' )
|
||||
|| ! class_exists( '\WPBootstrap\Template\ContextBuilder' ) ) {
|
||||
return false; // Can't render, let plugin use its own fallback
|
||||
}
|
||||
|
||||
$context_builder = new \WPBootstrap\Template\ContextBuilder();
|
||||
$theme_context = $context_builder->build();
|
||||
$twig = \WPBootstrap\Twig\TwigService::getInstance();
|
||||
|
||||
// Inject plugin content as the page post content so page.html.twig renders it
|
||||
// inside the standard content block. Title is empty so the parent theme does not
|
||||
// render its own <h1> — plugin templates handle their own headings.
|
||||
$theme_context['post'] = array_merge(
|
||||
$theme_context['post'] ?? [],
|
||||
[
|
||||
'content' => $content,
|
||||
'title' => '',
|
||||
'thumbnail' => '',
|
||||
]
|
||||
);
|
||||
|
||||
echo $twig->render( 'pages/page.html.twig', $theme_context );
|
||||
return true;
|
||||
}
|
||||
add_filter( 'woocommerce_render_page', 'wc_bootstrap_render_page', 10, 3 );
|
||||
|
||||
/**
|
||||
* Signal to the plugin that its content will be wrapped by the parent theme.
|
||||
*
|
||||
* When the parent theme's TwigService is available, the plugin templates should skip
|
||||
* their outer wrapper elements (breadcrumbs, sidebar, page shell) to avoid double-wrapping.
|
||||
*
|
||||
* @param bool $wrapped Whether content is theme-wrapped.
|
||||
* @return bool
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_is_wrapped( bool $wrapped ): bool {
|
||||
if ( class_exists( '\WPBootstrap\Twig\TwigService' ) ) {
|
||||
return true;
|
||||
}
|
||||
return $wrapped;
|
||||
}
|
||||
add_filter( 'woocommerce_is_theme_wrapped', 'wc_bootstrap_is_wrapped' );
|
||||
|
||||
/**
|
||||
* Add sticky header scroll shadow behavior.
|
||||
*
|
||||
* Toggles an 'is-stuck' class on the navbar when the page is scrolled,
|
||||
* adding a subtle box-shadow to visually separate the header from content.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_sticky_header_script(): void {
|
||||
?>
|
||||
<script>
|
||||
(function() {
|
||||
var header = document.querySelector('header.sticky-top');
|
||||
if (!header) return;
|
||||
var onScroll = function() {
|
||||
header.classList.toggle('is-stuck', window.scrollY > 0);
|
||||
};
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
onScroll();
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
add_action( 'wp_footer', 'wc_bootstrap_sticky_header_script' );
|
||||
Reference in New Issue
Block a user