Skip to content
Open

Release #4587

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3506b5f
Sync branch [skip ci]
pirate-bot Aug 12, 2026
981caec
Sync branch [skip ci]
pirate-bot Aug 12, 2026
d9f9a83
fix: enhance Playwright tests
girishpanchal30 Aug 12, 2026
0dbd5ce
fix: enhance Playwright tests
girishpanchal30 Aug 13, 2026
b62b6ea
fix: enhance Playwright tests
girishpanchal30 Aug 14, 2026
859eb81
fix: simplify request handling
girishpanchal30 Aug 14, 2026
08b8f91
fix: enhance Playwright tests
girishpanchal30 Aug 14, 2026
ee905b6
Improved handling of post content ordering (#4575)
girishpanchal30 Aug 17, 2026
8207c0e
Merge pull request #4581 from Codeinwp/bugfix/e2e
selul Aug 18, 2026
fdda1d5
Protected registered meta keys in block editor sidebar (#4584)
girishpanchal30 Aug 19, 2026
f336f90
Checked walker class existence (#4586)
girishpanchal30 Aug 19, 2026
262e1d6
Prevent duplicate footer menu IDs (#4568)
girishpanchal30 Aug 20, 2026
f714386
Added class existence checks to prevent errors (#4588)
girishpanchal30 Aug 21, 2026
d7a71a2
Enhanced color sanitization to handle non-string values (#4591)
girishpanchal30 Aug 24, 2026
fdb1cc5
Improved component resolution handling (#4592)
girishpanchal30 Aug 24, 2026
bfad0e8
Merge branch 'master' into development
selul Aug 24, 2026
9677869
Fix capitalization of 'WordPress' in readme
selul Aug 24, 2026
116d718
chore: fix WordPress spelling flagged by Theme Check and update theme…
selul Aug 24, 2026
3904282
chore: update themeisle-sdk to 3.3.60 with Theme Check spelling fixes
selul Aug 24, 2026
8b23b67
fix: restore mobile cart after AJAX updates (#4589)
girishpanchal30 Aug 24, 2026
79a19be
Applied disabled styling to the title in the editor. (#4594)
girishpanchal30 Aug 24, 2026
4abf9c8
chore: exclude composer installed.json and SDK changelog from dist zip
selul Aug 24, 2026
1dce6a0
Improved dropdown positioning (#4590)
girishpanchal30 Aug 24, 2026
8dba348
Preserved HTML markup in excerpts (#4600)
girishpanchal30 Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .distignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ header-footer-grid/package.json
header-footer-grid/package-lock.json
header-footer-grid/rollup.config.js
vendor/codeinwp/ti-onboarding/assets/vue
vendor/codeinwp/themeisle-sdk/CHANGELOG.md
vendor/composer/installed.json
vendor/codeinwp/ti-about-page/assets/scss
vendor/codeinwp/ti-about-page/assets/scss
vendor/codeinwp/ti-onboarding/assets/scss
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ jobs:
envs: "sample-data"
# - specs: "woo-visual-regression"
# envs: "woo-sample"
- specs: "editor"
envs: "sample-data"
runs-on: ubuntu-22.04
env:
ZIP_URL: "https://verti-artifacts.s3.amazonaws.com/${{ github.event.pull_request.base.repo.name }}-${{ needs.dev-zip.outputs.branch-name }}-${{ needs.dev-zip.outputs.git-sha-8 }}/neve.zip"
Expand All @@ -150,5 +152,7 @@ jobs:
if: failure()
uses: actions/upload-artifact@v4
with:
name: traces-${{ matrix.specs }}-${{ matrix.envs }}
path: ./test-results/**
if-no-files-found: ignore
retention-days: 1
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ New Features
- Integrated installation of Login Customizer, Cookie Notice, Duplicate Page, and Custom Fonts/Scripts modules
- New Maintenance and Coming Soon custom layouts [PRO]
- Admin Dashboard Customizer module to personalize the WordPress admin experience (Menu, Admin Bar, Custom Pages) [Agency]
- Included premium WP Landing Kit wordpress plugin [Agency]
- Included premium WP Landing Kit WordPress plugin [Agency]

Enhancements

Expand Down
42 changes: 32 additions & 10 deletions assets/apps/metabox/src/components/MetaFieldsManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,39 @@ class MetaFieldsManager extends Component {
});
}

addCSSToHead(css, styleID = 'neve-meta-editor-style') {
const head = document.head;
const hasStyle = document.getElementById(styleID);
if (hasStyle) {
hasStyle.innerHTML = css;
return false;
/**
* Documents the editor styles need to be added to.
*
* Since the block editor renders inside an iframe, styles added to the
* top document alone don't reach the content. Older setups without the
* iframe keep working through the top document.
*
* @return {Document[]} Target documents.
*/
getStyleTargets() {
const targets = [document];
const canvas = document.querySelector('iframe[name="editor-canvas"]');
const canvasDocument = canvas && canvas.contentDocument;

if (canvasDocument && canvasDocument.head) {
targets.push(canvasDocument);
}
const style = document.createElement('style');
style.setAttribute('id', styleID);
style.innerHTML = css;
head.appendChild(style);

return targets;
}

addCSSToHead(css, styleID = 'neve-meta-editor-style') {
this.getStyleTargets().forEach((doc) => {
const hasStyle = doc.getElementById(styleID);
if (hasStyle) {
hasStyle.innerHTML = css;
return;
}
const style = doc.createElement('style');
style.setAttribute('id', styleID);
style.innerHTML = css;
doc.head.appendChild(style);
});
}

updateTitleVisibility() {
Expand Down
50 changes: 30 additions & 20 deletions assets/js/src/frontend/navigation.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global NeveProperties menuCalcEvent CustomEvent */
/* global menuCalcEvent CustomEvent */
/* jshint esversion: 6 */
import {
toggleClass,
Expand Down Expand Up @@ -29,39 +29,49 @@ export const initNavigation = () => {
* Reposition drop downs in case they go off screen.
*/
export const repositionDropdowns = () => {
const { isRTL } = NeveProperties;
const dropDowns = document.querySelectorAll(
'.sub-menu, .minimal .nv-nav-search'
);

if (dropDowns.length === 0) return;
if (!dropDowns.length) return;

const windowWidth = window.innerWidth;

// How far a dropdown runs past the viewport: negative past the left edge,
// positive past the right edge, zero when it fits.
const getOverflow = (bounding) => {
if (bounding.left < 0) {
return bounding.left;
}

return bounding.right > windowWidth ? bounding.right - windowWidth : 0;
};

dropDowns.forEach((dropDown) => {
let bounding = dropDown.getBoundingClientRect(),
rightDist = bounding.left;
const style = dropDown.style;

if (rightDist < 0) {
dropDown.style.right = isRTL ? '-100%' : 'auto';
dropDown.style.left = isRTL ? 'auto' : 0;
}
// Drop what an earlier pass applied, so the dropdown is measured where
// the stylesheet puts it and stale offsets do not pile up.
style.right = style.left = style.transform = '';

if (rightDist + bounding.width >= windowWidth) {
dropDown.style.right = isRTL ? 0 : '100%';
dropDown.style.left = 'auto';
let overflow = getOverflow(dropDown.getBoundingClientRect());

if (!overflow) {
return;
}

// Recalculate bounding after we've made adjustments.
bounding = dropDown.getBoundingClientRect();
rightDist = bounding.left;
const edge = dropDown.matches('.sub-menu .sub-menu') ? '100%' : '0px';

style.right = overflow < 0 ? 'auto' : edge;
style.left = overflow < 0 ? edge : 'auto';

// Wider than the space on the side it opens towards, offset it to fit.
overflow = getOverflow(dropDown.getBoundingClientRect());

if (rightDist < 0 || rightDist + bounding.width >= windowWidth) {
// Calculate how much should we offset the dropdown to make it fit.
dropDown.style.transform =
if (overflow) {
style.transform =
'translateX(' +
(isRTL ? '-' : '') +
(Math.abs(rightDist) + 20) +
(overflow < 0 ? 20 - overflow : -overflow - 20) +
'px)';
}
});
Expand Down
7 changes: 7 additions & 0 deletions bin/envs/cli-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ init_environment(){
echo "Installing Neve theme from $NEVE_LOCATION"
wp --allow-root theme install --activate $NEVE_LOCATION
wp --allow-root option update fresh_site 0

# Activating Neve remaps widgets by sidebar id, and 'blog-sidebar' does not
# match the previous theme's, so the default widgets can be left unassigned.
if [ "$(wp --allow-root widget list blog-sidebar --format=count)" = "0" ]; then
echo "Populating blog-sidebar"
wp --allow-root widget add block blog-sidebar --content='<!-- wp:search /-->'
fi
echo "Installing Theme API Plugin"
wp --allow-root plugin install https://github.com/codeinwp/wp-thememods-api/archive/refs/heads/main.zip --force --activate
}
Expand Down
7 changes: 5 additions & 2 deletions bin/ss-pages.test.stub
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe( 'Starter Sites VR - {{site}}', () => {
let frontpage = "{{site}}"
cy.visit(frontpage );
cy.captureDocument();
cy.get( '#nv-primary-navigation-main' ).then( $headerMenu => {
cy.get( '[id^="nv-primary-navigation"]' ).then( $headerMenu => {
[ ...$headerMenu.find( '.menu-item a' ) ].forEach( $url => {
let url = $url.href;
if(url.includes("#")){
Expand All @@ -13,8 +13,11 @@ describe( 'Starter Sites VR - {{site}}', () => {
if(frontpage.replace(/\/*$/, "") === url.replace(/\/*$/, "")){
return;
}
if(pages.includes(url)){
return;
}

pages.push( $url.href );
pages.push( url );
} );
} );
} );
Expand Down
12 changes: 6 additions & 6 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"hfg_footer_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"footer-menu\"}],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"footer-menu\"}],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}}}",
"nav_menu_locations[footer]": 177
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"},{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}",
"nav_menu_locations[primary]": 177
}
7 changes: 7 additions & 0 deletions e2e-tests/fixtures/customizer/hfg/submenu-viewport-setup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"neve_migrated_hfg_colors": true,
"ti_prev_theme": "twentytwentyone",
"neve_ran_migrations": true,
"neve_container_width": "{\"mobile\":748,\"tablet\":992,\"desktop\":2000,\"suffix\":{\"mobile\":\"px\",\"tablet\":\"px\",\"desktop\":\"px\"}}",
"hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}"
}
15 changes: 12 additions & 3 deletions e2e-tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { defineConfig, devices } from '@playwright/test';

// Plain `|| fallback` would discard an explicit 0.
const envInt = (name: string, fallback: number) => {
const parsed = parseInt(process.env[name] || '', 10);
return Number.isNaN(parsed) ? fallback : parsed;
};

export default defineConfig({
reporter: process.env.CI ? 'github' : 'list',
forbidOnly: !!process.env.CI,
workers: process.env.CI ? 6 : undefined,
retries: 0,
timeout: parseInt(process.env.TIMEOUT || '', 10) || 150_000, // Defaults to 100 seconds.
// Same values locally and in CI, so a race reproduces in both.
workers: envInt('PW_WORKERS', 2),
retries: envInt('PW_RETRIES', 2),
timeout: envInt('TIMEOUT', 150_000), // Defaults to 100 seconds.
fullyParallel: true,
projects: [
// Setup project
Expand All @@ -26,5 +33,7 @@ export default defineConfig({
headless: true,
ignoreHTTPSErrors: true,
trace: 'retain-on-failure',
actionTimeout: 20_000,
navigationTimeout: 45_000,
},
});
5 changes: 4 additions & 1 deletion e2e-tests/specs/accessibility/aria.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ const runMenuARIATest = (deviceType = 'mobile') => {
).toHaveAttribute('aria-expanded', 'true');

// Close the menu from the overlay. Check ARIA attribute for expanded state is false when menu is closed.
// The overlay spans the viewport and the open sidebar covers its centre, so
// a real click there lands on a menu link and navigates away. Dispatching
// hits the same handler without depending on which side the sidebar is on.
await page
.locator('.header-menu-sidebar-overlay')
.click({ force: true });
.dispatchEvent('click');
await expect(
page.getByRole('button', { name: 'Navigation Menu' })
).toHaveAttribute('aria-expanded', 'false');
Expand Down
33 changes: 28 additions & 5 deletions e2e-tests/specs/admin/tpc-notice-install.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
import { test, expect } from '@playwright/test';
import { visitAdminPage } from '../../utils';
import { setCustomizeSettings, visitAdminPage } from '../../utils';

const TPC_PLUGIN =
'templates-patterns-collection/templates-patterns-collection';
const TEST_NAME = 'tpcNotice';

test.describe('Dashboard Notice', () => {
test.beforeAll(async ({ request, baseURL }) => {
const endpoint = `${baseURL}/wp-json/wp/v2/plugins/${TPC_PLUGIN}`;

await request
.put(endpoint, { data: { status: 'inactive' } })
.catch(() => null);
await request.delete(endpoint).catch(() => null);

// Overridden per-request via ?test_name=, not written to the options table.
await setCustomizeSettings(
TEST_NAME,
{
options: {
neve_notice_dismissed: 'no',
neve_install: Math.floor(Date.now() / 1000),
},
},
{ request, baseURL }
);
});

test('Starter Sites Plugin install from Dashboard Notice', async ({
page,
}) => {
await visitAdminPage(page, 'index.php', '');
await visitAdminPage(page, 'index.php', `test_name=${TEST_NAME}`);

await expect(page).toHaveURL(/wp-admin\/index.php/);

Expand All @@ -25,9 +50,7 @@ test.describe('Dashboard Notice', () => {
);

// Welcome screen
await expect(page.locator('h1')).toContainText(
'Choose a design'
);
await expect(page.locator('h1')).toContainText('Choose a design');

const categories = await page.locator('.ob-cat-wrap .cat');
await expect(categories).toContainText([
Expand Down
34 changes: 30 additions & 4 deletions e2e-tests/specs/customizer/general/custom-global-colors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,37 @@ test.describe('Custom Global Color Control', () => {
);
await clearWelcome(page);

await page.locator('[aria-label="Document Overview"]').click();
await page.locator('.block-editor-list-view-leaf').first().click();
await page.waitForFunction(() =>
(
window.wp?.data?.select('core/block-editor')?.getSettings()
?.colors || []
).some((color: { slug: string }) => color.slug === 'custom-1')
);

// Wait for the parsed block list too, so the update below has a target.
await page.waitForFunction(
() =>
(
window.wp?.data?.select('core/block-editor')?.getBlocks() ||
[]
).length > 0
);

await page.getByRole('button', { name: 'Background' }).click();
await page.getByRole('option', { name: 'Custom 1' }).click();
// Clicking the palette swatch toggles, so a block left coloured by a
// previous run would be cleared rather than set.
await page.evaluate(() => {
const { data } = window.wp;
const [block] = data.select('core/block-editor').getBlocks();
data.dispatch('core/block-editor').updateBlockAttributes(
block.clientId,
{ backgroundColor: 'custom-1' }
);
});
await page.waitForFunction(
() =>
window.wp?.data?.select('core/block-editor')?.getBlocks()?.[0]
?.attributes?.backgroundColor === 'custom-1'
);

await savePost(page);
});
Expand Down
Loading
Loading