feat: Bootstrap 5 block renderer, widget cards, and sidebar post layout (v1.1.0)
All checks were successful
Create Release Package / PHP Lint (push) Successful in 1m7s
Create Release Package / Build Release (push) Successful in 1m41s

Add BlockRenderer class injecting Bootstrap classes into 8 core block types
(table, button, buttons, image, search, quote, pullquote, list) via per-block
render_block filters using WP_HTML_Tag_Processor.

Add WidgetRenderer class wrapping sidebar widgets in Bootstrap card components
with h4 heading hierarchy via dynamic_sidebar_params and widget_block_content
filters.

Add widget SCSS stylesheet for list styling, search input-group, tag cloud
pills, and card-flush list positioning.

Add single-sidebar.html.twig as the default post template with two-column
Bootstrap layout (col-lg-8 content, col-lg-4 sidebar). Full-width available
via template selection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 23:43:43 +01:00
parent 9904bf508a
commit 3165e60639
16 changed files with 955 additions and 49 deletions

145
src/scss/_widgets.scss Normal file
View File

@@ -0,0 +1,145 @@
// Widget Bootstrap 5 styling
// Targets sidebar widget inner content rendered by WordPress core widgets.
// Block widgets nest content inside .wp-block-group wrappers.
// Widget headings (block widgets use h4.wp-block-heading after WidgetRenderer transform)
.widget .card-title,
.widget .wp-block-heading {
margin-bottom: $spacer * 0.75;
}
// Widget lists (Recent Posts, Archives, Categories, Recent Comments)
// Covers both legacy (ul direct child) and block widget (ul inside .wp-block-group)
.widget ul,
.widget ol {
list-style: none;
padding-left: 0;
margin-bottom: 0;
li {
padding: $list-group-item-padding-y $list-group-item-padding-x;
border-bottom: var(--bs-border-width) solid var(--bs-border-color);
&:last-child {
border-bottom: 0;
}
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
// Flush lists to card edges (negate card-body padding)
// Handles both direct children and block widget nesting (.wp-block-group > ul)
.widget .card-body > ul,
.widget .card-body > ol,
.widget .card-body > nav > ul,
.widget .card-body > .wp-block-group > ul,
.widget .card-body > .wp-block-group > ol {
margin: 0 calc(-1 * var(--bs-card-spacer-x)) calc(-1 * var(--bs-card-spacer-y));
li:first-child {
border-top: var(--bs-border-width) solid var(--bs-border-color);
}
}
// Widget select dropdowns (Archives dropdown, Categories dropdown)
.widget select {
display: block;
width: 100%;
padding: $input-padding-y $input-padding-x;
font-size: $input-font-size;
line-height: $input-line-height;
color: var(--bs-body-color);
background-color: var(--bs-body-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
border-radius: var(--bs-border-radius);
appearance: auto;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
&:focus {
border-color: $input-focus-border-color;
outline: 0;
box-shadow: $input-focus-box-shadow;
}
}
// Widget search form (legacy get_search_form() widgets)
.widget .search-form {
display: flex;
gap: 0.5rem;
.search-field {
flex: 1;
display: block;
width: 100%;
padding: $input-padding-y $input-padding-x;
font-size: $input-font-size;
line-height: $input-line-height;
color: var(--bs-body-color);
background-color: var(--bs-body-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
border-radius: var(--bs-border-radius);
&:focus {
border-color: $input-focus-border-color;
outline: 0;
box-shadow: $input-focus-box-shadow;
}
}
.search-submit {
@extend .btn;
@extend .btn-primary;
}
}
// Block search widget — hide label, make input-group flush
.widget .wp-block-search {
.wp-block-search__label {
display: none;
}
}
// Tag cloud
.widget .tagcloud {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
a {
display: inline-block;
padding: 0.25rem 0.5rem;
font-size: $font-size-sm !important; // Override inline font-size from WP
line-height: 1.5;
color: var(--bs-body-color);
background-color: var(--bs-tertiary-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
border-radius: var(--bs-border-radius-pill);
text-decoration: none;
transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;
&:hover {
background-color: var(--bs-primary);
border-color: var(--bs-primary);
color: #fff;
}
}
}
// Post date in Recent Posts widget
.widget .post-date {
display: block;
font-size: $small-font-size;
color: var(--bs-secondary-color);
}
// Recent Comments styling
.widget .recentcomments {
font-size: $font-size-sm;
}