diff --git a/.distignore b/.distignore index 00f7f99..1c86fb2 100644 --- a/.distignore +++ b/.distignore @@ -4,6 +4,7 @@ /config /node_modules /tests +/bin .distignore .editorconfig diff --git a/.gitattributes b/.gitattributes index d8401c1..c2d7c0f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,7 +4,7 @@ /node_modules export-ignore -diff /tests export-ignore /vendor export-ignore -diff - +/bin export-ignore /.distignore export-ignore /.editorconfig export-ignore /.gitattributes export-ignore diff --git a/.plugin-data b/.plugin-data index 8bc87bb..fdbda80 100644 --- a/.plugin-data +++ b/.plugin-data @@ -1,4 +1,4 @@ { - "version": "2.1.0", + "version": "2.1.1", "slug": "blockparty-faq" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfa564..77c9f73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.1.1] - 2026-08-04 + +### Changed + +- Performance improvements removed script blocking time. + ## [2.1.0] - 2026-06-30 ### Added diff --git a/README.md b/README.md index aec715d..dcc06cb 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ A Gutenberg block for SEO friendly FAQ in an accessible accordion. - `npm run start` - Start the development server with hot reload - `npm run env:start` - Start the WordPress environment (wp-env) - `npm run env:stop` - Stop the WordPress environment +- `npm run bump -- ` - Bump the plugin version across package, blocks, PHP, and docs ### Note @@ -51,40 +52,8 @@ FAQ structured data (JSON-LD) requires Yoast SEO, Rank Math, or SEOPress. All th ## Changelog -### 1.0.0 - 2024-04-02 +See [readme.txt](readme.txt) and [CHANGELOG.md](CHANGELOG.md) for the full version history. -- initial commit. +--- -### 1.0.1 - 2024-04-03 - -- fix css variable names - -### 1.0.2 - 2024-06-06 - -- Add support for PHP 8.2 - -### 2.0.0 - 2026-01-26 - -- **Major block structure refactoring** : Transition from a monolithic block to a nested architecture with child blocks (`faq-item`, `faq-question`, `faq-answer`) -- **Configurable accordion mode** : Added `isAccordion` attribute allowing to toggle between an interactive accordion mode and a static mode -- **InnerBlocks support in answers** : Ability to add any Gutenberg block (lists, paragraphs, images, etc.) in FAQ answers -- **Front-end JavaScript** : Added `script.js` to handle accordion interactivity on the front-end with customizable configuration via the `beapi_faq_block_config` filter -- **Automatic migration** : Migration system from the old format (`questions` array attribute) to the new format (InnerBlocks) -- **Complete internationalization** : Support for PO/MO translations for PHP and JSON for JavaScript -- **Aligned build structure** : Reorganization to follow the `blockparty-accordion` model with `block.json` in each block directory -- **Add/remove buttons** : Added buttons to add and remove FAQ items directly from the editor - -### 2.0.1 - 2026-01-27 - -- Fix build blocks - -### 2.0.2 - 2026-01-27 - -- Add missing isAccordion attribute - -### 2.0.3 - 2026-02-17 - -- Allow adding "Button" blocks in the answer content -- Add spacing support for answers -- Add font size support for the question -- Strip HTML tags from the question in structured data +Developed with ❤️ by [Be API](https://beapi.fr) diff --git a/bin/bump.sh b/bin/bump.sh new file mode 100644 index 0000000..38f9f7a --- /dev/null +++ b/bin/bump.sh @@ -0,0 +1,262 @@ +#!/usr/bin/env bash +# +# Bump the plugin version across package, block metadata, PHP, and docs. +# +# Usage (no chmod required): +# bash bin/bump.sh patch +# bash bin/bump.sh minor +# bash bin/bump.sh major +# bash bin/bump.sh 2.2.0 +# npm run bump -- patch +# npm run bump -- 2.2.0 +# +# macOS sed (-i '') is assumed. +# + +set -euo pipefail + +# --------------------------------------------------------------------------- +# Assets — add or remove paths here +# --------------------------------------------------------------------------- + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" + +# JSON files that expose a top-level "version" field +JSON_VERSION_FILES=( + ".plugin-data" + "package.json" + "src/faq/block.json" + "src/faq-answer/block.json" + "src/faq-item/block.json" + "src/faq-question/block.json" +) + +PACKAGE_LOCK_FILE="package-lock.json" +PHP_FILE="blockparty-faq.php" +README_TXT="readme.txt" +CHANGELOG="CHANGELOG.md" + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +UPDATED_FILES=() + +log_updated() { + UPDATED_FILES+=( "$1" ) +} + +require_file() { + local file="$1" + if [[ ! -f "${ROOT_DIR}/${file}" ]]; then + echo "Error: Missing file ${file}" >&2 + exit 1 + fi +} + +replace_json_version() { + local file="$1" + local path="${ROOT_DIR}/${file}" + require_file "${file}" + sed -i '' "s/\"version\": \"[0-9]*\.[0-9]*\.[0-9]*\"/\"version\": \"${VERSION}\"/" "${path}" + log_updated "${file}" +} + +usage() { + local code="${1:-0}" + echo "Usage: bash bin/bump.sh " + echo "" + echo "Examples:" + echo " bash bin/bump.sh patch" + echo " bash bin/bump.sh minor" + echo " bash bin/bump.sh 2.2.0" + echo " npm run bump -- patch" + exit "${code}" +} + +resolve_version() { + local current="$1" + local input="$2" + + if [[ "${input}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "${input}" + return + fi + + local major minor patch + IFS='.' read -r major minor patch <<< "${current}" + + case "${input}" in + major) + echo "$((major + 1)).0.0" + ;; + minor) + echo "${major}.$((minor + 1)).0" + ;; + patch) + echo "${major}.${minor}.$((patch + 1))" + ;; + *) + echo "Error: Unknown bump argument \"${input}\". Use patch, minor, major, or an explicit x.y.z version." >&2 + exit 1 + ;; + esac +} + +escape_sed() { + printf '%s\n' "$1" | sed -e 's/[.[\*^$\/]/\\&/g' +} + +# --------------------------------------------------------------------------- +# Args +# --------------------------------------------------------------------------- + +if [[ -z "${1:-}" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage "$([[ -n "${1:-}" ]] && echo 0 || echo 1)" +fi + +INPUT="$1" + +require_file ".plugin-data" +CURRENT="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([0-9]*\.[0-9]*\.[0-9]*\)".*/\1/p' "${ROOT_DIR}/.plugin-data" | head -n 1)" + +if [[ -z "${CURRENT}" ]]; then + echo "Error: Could not read current version from .plugin-data" >&2 + exit 1 +fi + +if ! [[ "${CURRENT}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: Invalid current version \"${CURRENT}\" in .plugin-data" >&2 + exit 1 +fi + +VERSION="$(resolve_version "${CURRENT}" "${INPUT}")" + +if [[ "${VERSION}" == "${CURRENT}" ]]; then + echo "Error: Version is already ${CURRENT}" >&2 + exit 1 +fi + +echo "Bumping version: ${CURRENT} → ${VERSION}" +TODAY="$(date +%Y-%m-%d)" + +# --------------------------------------------------------------------------- +# JSON version fields +# --------------------------------------------------------------------------- + +for file in "${JSON_VERSION_FILES[@]}"; do + replace_json_version "${file}" +done + +# --------------------------------------------------------------------------- +# package-lock.json (root + packages[""] only) +# --------------------------------------------------------------------------- + +if [[ -f "${ROOT_DIR}/${PACKAGE_LOCK_FILE}" ]]; then + # Root "version" (near top of file) + sed -i '' '1,5s/"version": "[0-9]*\.[0-9]*\.[0-9]*"/"version": "'"${VERSION}"'"/' "${ROOT_DIR}/${PACKAGE_LOCK_FILE}" + # packages[""].version + sed -i '' '6,12s/"version": "[0-9]*\.[0-9]*\.[0-9]*"/"version": "'"${VERSION}"'"/' "${ROOT_DIR}/${PACKAGE_LOCK_FILE}" + log_updated "${PACKAGE_LOCK_FILE}" +fi + +# --------------------------------------------------------------------------- +# Main plugin PHP +# --------------------------------------------------------------------------- + +require_file "${PHP_FILE}" +sed -i '' "s/^\( \* Version:[[:space:]]*\)$(escape_sed "${CURRENT}")/\1${VERSION}/" "${ROOT_DIR}/${PHP_FILE}" +sed -i '' "s/define( 'BLOCKPARTY_FAQ_VERSION', '$(escape_sed "${CURRENT}")' )/define( 'BLOCKPARTY_FAQ_VERSION', '${VERSION}' )/" "${ROOT_DIR}/${PHP_FILE}" +log_updated "${PHP_FILE}" + +# --------------------------------------------------------------------------- +# readme.txt — Stable tag + changelog + Upgrade Notice stubs +# --------------------------------------------------------------------------- + +require_file "${README_TXT}" +sed -i '' "s/^\(Stable tag:[[:space:]]*\)$(escape_sed "${CURRENT}")/\1${VERSION}/" "${ROOT_DIR}/${README_TXT}" + +if grep -q "^= ${VERSION} - " "${ROOT_DIR}/${README_TXT}"; then + echo "Error: readme.txt already contains a changelog entry for ${VERSION}" >&2 + exit 1 +fi + +awk -v ver="${VERSION}" -v today="${TODAY}" -v current="${CURRENT}" ' + { + if ( $0 ~ ("^= " current " - ") ) { + print "= " ver " - " today " =" + print "* TBD" + print "" + } + print + } +' "${ROOT_DIR}/${README_TXT}" > "${ROOT_DIR}/${README_TXT}.tmp" +mv "${ROOT_DIR}/${README_TXT}.tmp" "${ROOT_DIR}/${README_TXT}" + +if grep -q "^= ${VERSION} =$" "${ROOT_DIR}/${README_TXT}"; then + echo "Error: readme.txt already contains an Upgrade Notice for ${VERSION}" >&2 + exit 1 +fi + +awk -v ver="${VERSION}" ' + { + print + if ( $0 == "== Upgrade Notice ==" ) { + getline + print "" + print "= " ver " =" + print "TBD" + print "" + if ( $0 != "" ) { + print + } + } + } +' "${ROOT_DIR}/${README_TXT}" > "${ROOT_DIR}/${README_TXT}.tmp" +mv "${ROOT_DIR}/${README_TXT}.tmp" "${ROOT_DIR}/${README_TXT}" +log_updated "${README_TXT}" + +# --------------------------------------------------------------------------- +# CHANGELOG.md — Keep a Changelog entry +# --------------------------------------------------------------------------- + +require_file "${CHANGELOG}" + +if grep -q "^## \[${VERSION}\]" "${ROOT_DIR}/${CHANGELOG}"; then + echo "Error: CHANGELOG.md already contains an entry for ${VERSION}" >&2 + exit 1 +fi + +awk -v ver="${VERSION}" -v today="${TODAY}" ' + { + print + if ( !inserted && index( $0, "Semantic Versioning" ) ) { + getline + print "" + print "## [" ver "] - " today + print "" + print "### Changed" + print "" + print "- TBD" + print "" + inserted = 1 + # Marker is followed by a blank line; skip the consumed blank. + next + } + } +' "${ROOT_DIR}/${CHANGELOG}" > "${ROOT_DIR}/${CHANGELOG}.tmp" +mv "${ROOT_DIR}/${CHANGELOG}.tmp" "${ROOT_DIR}/${CHANGELOG}" +log_updated "${CHANGELOG}" + +# --------------------------------------------------------------------------- +# Summary +# --------------------------------------------------------------------------- + +echo "" +echo "Bumped version ${CURRENT} → ${VERSION}" +echo "Updated files:" +for file in "${UPDATED_FILES[@]}"; do + echo " - ${file}" +done +echo "" +echo "Fill in the TBD changelog entries before releasing." diff --git a/blockparty-faq.php b/blockparty-faq.php index 6c1174e..ba57330 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -4,7 +4,7 @@ * Description: A FAQ block for WordPress Editor that provided structured data based on FAQ schema. * Requires at least: 6.2 * Requires PHP: 8.1 - * Version: 2.1.0 + * Version: 2.1.1 * Plugin URI: https://beapi.fr * Author: Be API Technical team * Author URI: https://beapi.fr @@ -45,7 +45,7 @@ } // Plugin constants -define( 'BLOCKPARTY_FAQ_VERSION', '2.1.0' ); +define( 'BLOCKPARTY_FAQ_VERSION', '2.1.1' ); // Plugin URL and PATH define( 'BLOCKPARTY_FAQ_DIR', plugin_dir_path( __FILE__ ) ); diff --git a/package-lock.json b/package-lock.json index 42a09a5..877ac3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockparty-faq", - "version": "2.1.0", + "version": "2.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockparty-faq", - "version": "2.1.0", + "version": "2.1.1", "license": "GPL-2.0-or-later", "dependencies": { "@beapi/be-a11y": "^1.7.2", diff --git a/package.json b/package.json index a8d1b72..4739d74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockparty-faq", - "version": "2.1.0", + "version": "2.1.1", "description": "SEO friendly FAQ module in an accessible accordion", "author": "Be API Technical team", "license": "GPL-2.0-or-later", @@ -15,7 +15,8 @@ "make-pot": "wp i18n make-pot . languages/blockparty-faq.pot --exclude=\"src\" --domain=blockparty-faq", "make-json": "wp i18n make-json languages/blockparty-faq-fr_FR.po languages/ --no-purge", "env:start": "wp-env start", - "env:stop": "wp-env stop" + "env:stop": "wp-env stop", + "bump": "bash bin/bump.sh" }, "dependencies": { "@beapi/be-a11y": "^1.7.2", diff --git a/readme.txt b/readme.txt index 02056ca..e70c5ea 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: block, faq, accordion, gutenberg, schema, seo, accessibility Requires at least: 6.2 Tested up to: 6.8 Requires PHP: 8.1 -Stable tag: 2.1.0 +Stable tag: 2.1.1 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -57,6 +57,9 @@ Yes. The front-end accordion uses `@beapi/be-a11y` with proper ARIA attributes ( == Changelog == += 2.1.1 - 2026-08-04 = +* Performance improvements removed script blocking time. + = 2.1.0 - 2026-06-30 = * Added configurable FAQ question heading level (h2–h6). * Added Rank Math SEO integration for FAQ structured data. diff --git a/src/faq-answer/block.json b/src/faq-answer/block.json index 69f4061..1f88f5b 100644 --- a/src/faq-answer/block.json +++ b/src/faq-answer/block.json @@ -2,10 +2,12 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-answer", - "version": "2.1.0", + "version": "2.1.1", "title": "FAQ Answer", "category": "design", - "parent": [ "blockparty/faq-item" ], + "parent": [ + "blockparty/faq-item" + ], "description": "Content of the FAQ answer.", "supports": { "html": false, diff --git a/src/faq-item/block.json b/src/faq-item/block.json index 97292d5..b45013d 100644 --- a/src/faq-item/block.json +++ b/src/faq-item/block.json @@ -2,10 +2,12 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-item", - "version": "2.1.0", + "version": "2.1.1", "title": "FAQ Item", "category": "design", - "parent": [ "blockparty/faq" ], + "parent": [ + "blockparty/faq" + ], "description": "A FAQ item containing a question and an answer.", "supports": { "html": false, diff --git a/src/faq-question/block.json b/src/faq-question/block.json index 9a21948..7ff59d7 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -2,12 +2,16 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-question", - "version": "2.1.0", + "version": "2.1.1", "title": "FAQ Question", "category": "design", - "parent": [ "blockparty/faq-item" ], + "parent": [ + "blockparty/faq-item" + ], "description": "Content of the FAQ question.", - "usesContext": [ "blockparty/headingLevel" ], + "usesContext": [ + "blockparty/headingLevel" + ], "supports": { "html": false, "inserter": false, @@ -28,7 +32,13 @@ "headingLevel": { "type": "number", "default": 3, - "enum": [ 2, 3, 4, 5, 6 ] + "enum": [ + 2, + 3, + 4, + 5, + 6 + ] } }, "textdomain": "blockparty-faq", diff --git a/src/faq/block.json b/src/faq/block.json index 0507dec..ba4cecf 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq", - "version": "2.1.0", + "version": "2.1.1", "title": "FAQ", "category": "design", "description": "A FAQ block for WordPress Editor that provided structured data based on FAQ schema.", @@ -18,7 +18,13 @@ "headingLevel": { "type": "number", "default": 3, - "enum": [ 2, 3, 4, 5, 6 ] + "enum": [ + 2, + 3, + 4, + 5, + 6 + ] } }, "providesContext": { diff --git a/src/faq/script.js b/src/faq/script.js index 9e2a33f..bd9b564 100644 --- a/src/faq/script.js +++ b/src/faq/script.js @@ -3,7 +3,10 @@ import { Accordion } from '@beapi/be-a11y'; // eslint-disable-next-line no-undef const accordionConfig = beapiFaqBlock.accordionConfig; -window.addEventListener( 'load', function () { +/** + * Initialize FAQ accordion instances. + */ +const init = () => { Accordion.init( '.wp-block-blockparty-faq:has(button.wp-block-blockparty-faq-trigger)', accordionConfig @@ -14,4 +17,10 @@ window.addEventListener( 'load', function () { panelSelector: '.faq__panel', triggerSelector: '.faq__trigger', } ); -} ); +}; + +if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', init ); +} else { + init(); +}