Skip to content

Feature: Unit Blocks – merge into 2.1-trunk#815

Merged
krugazul merged 6 commits into2.1-trunkfrom
feature/unit-blocks
Dec 17, 2025
Merged

Feature: Unit Blocks – merge into 2.1-trunk#815
krugazul merged 6 commits into2.1-trunkfrom
feature/unit-blocks

Conversation

@krugazul
Copy link
Collaborator

@krugazul krugazul commented Dec 16, 2025

This PR merges the feature/unit-blocks branch into 2.1-trunk.

Summary

  • Adds and refines unit blocks functionality and related assets
  • Aligns with WordPress coding standards and repository linting rules
  • Prepared for 2.1 release branch

Notes

  • Please run CI and lint workflows
  • Changelog entry will be updated in changelog.md accordingly

Summary by CodeRabbit

  • New Features

    • Extended prefix functionality to itinerary-related blocks (accommodation, location, type, drinks, room).
  • Improvements

    • Redesigned itinerary item layout for a more compact, consistent presentation.
    • Adjusted best-time-to-visit block example alignment for improved display.
    • Destination-to-tour bindings now include parent content in fetched results.
    • Improved related-item retrieval logic for more accurate data.
  • Chores

    • Updated asset versions and changelog entry.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions github-actions bot added lang:php PHP code area:theme Theme & styles (templates, template parts, FSE) lang:javascript area:block-editor labels Dec 16, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: String must contain at most 250 character(s) at "tone_instructions"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Updated several build asset version hashes; expanded paragraph-prefix activation to include specific itinerary-related paragraph classes; added prefix-extraction logic to PHP bindings and applied prefixes to itinerary fields; restructured the itinerary pattern template; introduced dynamic post-meta key retrieval for related-item query loops.

Changes

Cohort / File(s) Summary
Asset version updates
build/blocks/best-time-to-visit/index.asset.php, build/paragraph-prefix.asset.php, build/blocks/destination-to-tour/index.asset.php
Updated generated asset version hashes (no dependency or structural changes).
Paragraph prefix activation (editor)
src/js/blocks/paragraph-prefix.js, build/paragraph-prefix.js, build/blocks/best-time-to-visit/index.js, src/blocks/best-time-to-visit/index.js
Broadened the condition enabling paragraph-prefix controls to also match itinerary-related classes (itinerary-accommodation, itinerary-location, itinerary-type, itinerary-drinks, itinerary-room). Minor example layout alignment tweak for best-time-to-visit.
Itinerary pattern template
patterns/itinerary-list.php
Replaced itinerary pattern content with full-width layout, new wrapper classes (lsx-itinerary-info, itin-*-wrapper), consolidated field rows and placeholder content, and updated metadata names.
Bindings and prefix logic (PHP)
includes/classes/blocks/class-bindings.php
Added maybe_get_prefix( $key, $build ) and updated build_itinerary_field() to prepend per-field prefixes (location, accommodation, type, drinks, room). render_itinerary_block() now uses a dedicated build template per item.
Query loop / related-item keys
includes/classes/blocks/class-query-loop.php, src/blocks/destination-to-tour/index.js, build/blocks/destination-to-tour/index.js
Replaced some custom-field queries with get_post_meta() lookups; introduced lsx_to_related_connection_query_key filter to determine meta-key for related items. Also added parents: true to paragraph binding in destination-to-tour variation.
Changelog
changelog.md
Added "Unit Blocks" entry to 2.1.0 "Added" section.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay special attention to: includes/classes/blocks/class-bindings.php (prefix extraction regex and HTML parsing edge-cases), patterns/itinerary-list.php (template/content correctness and markup classes), and includes/classes/blocks/class-query-loop.php (filter fallback and meta-key handling).

Possibly related PRs

Suggested labels

comp:block-variations, comp:block-editor, comp:block-json

Suggested reviewers

  • tibiii

Poem

🐰 I nibble prefixes from paragraph nests,

I tuck them neat in itinerary vests,
Patterns hop wider, classes align,
Build hashes refreshed — everything fine,
A rabbit’s cheer for tidy block quests!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feature: Unit Blocks – merge into 2.1-trunk' directly describes the main purpose of the PR, which is to merge unit blocks feature into the 2.1-trunk release branch.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/unit-blocks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added status:needs-review Awaiting code review meta:needs-changelog Requires a changelog entry before merge labels Dec 16, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @krugazul, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates the feature/unit-blocks branch into the 2.1-trunk, introducing new and refined unit block functionalities. It includes updates to block assets, ensures compliance with coding standards, and prepares the codebase for the upcoming 2.1 release. Key changes involve enhancing prefix handling for itinerary-related paragraph blocks and refining data retrieval for custom fields within query loops.

Highlights

  • Feature Merge: This pull request merges the feature/unit-blocks branch into the 2.1-trunk, integrating new unit block functionalities.
  • Unit Blocks Refinement: Adds and refines existing unit blocks functionality and their associated assets, ensuring they meet current standards.
  • Coding Standards & Linting: The changes align with WordPress coding standards and repository linting rules, improving code quality and consistency.
  • Itinerary Block Prefix Handling: Enhanced the logic for displaying prefix controls on paragraph blocks within itinerary sections, now supporting specific CSS classes in addition to metadata bindings.
  • Itinerary Pattern Updates: The itinerary-list.php pattern has been updated to use alignfull for columns and streamline the display of itinerary information by directly embedding prefixes into paragraph blocks.
  • Query Loop Data Retrieval: Modified the query loop to retrieve raw post meta values and introduced a filter for related connection query keys, offering more flexibility in data handling.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions bot added status:needs-review Awaiting code review and removed status:needs-review Awaiting code review labels Dec 16, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/js/blocks/paragraph-prefix.js (1)

137-143: Critical: Undeclared variable styleEl creates implicit global.

styleEl is used without being declared with let or const, which creates an implicit global variable. This is a bug that will cause issues in strict mode and pollutes the global namespace.

                     let existingStyle = targetDoc.getElementById( uniqueId );
                     if ( ! existingStyle ) {
-                        styleEl = targetDoc.createElement( 'style' );
+                        const styleEl = targetDoc.createElement( 'style' );
                         styleEl.id = uniqueId;
                         targetDoc.head.appendChild( styleEl );
+                        styleEl.textContent = css;
+                    } else {
+                        existingStyle.textContent = css;
                     }
-                    styleEl.textContent = css;

The current code also has a logic issue: when existingStyle is found, styleEl remains undefined, yet styleEl.textContent = css is called outside the if block.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7148c78 and d4933bd.

📒 Files selected for processing (9)
  • build/blocks/best-time-to-visit/index.asset.php (1 hunks)
  • build/blocks/best-time-to-visit/index.js (1 hunks)
  • build/paragraph-prefix.asset.php (1 hunks)
  • build/paragraph-prefix.js (1 hunks)
  • includes/classes/blocks/class-bindings.php (5 hunks)
  • includes/classes/blocks/class-query-loop.php (2 hunks)
  • patterns/itinerary-list.php (2 hunks)
  • src/blocks/best-time-to-visit/index.js (1 hunks)
  • src/js/blocks/paragraph-prefix.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use semicolons to terminate statements in JavaScript block code

Ensure all generated code follows ESLint rules and WordPress Coding Standards before deployment

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • src/js/blocks/paragraph-prefix.js
**/*.{php,js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (GEMINI.md)

Follow WordPress Coding Standards including proper namespacing, security practices (sanitization/escaping), and code organization

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • src/js/blocks/paragraph-prefix.js
  • includes/classes/blocks/class-bindings.php
**/*.{js,jsx,ts,tsx,php}

📄 CodeRabbit inference engine (GEMINI.md)

Implement accessibility features following WCAG 2.2 AA standards in all block components and patterns

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • src/js/blocks/paragraph-prefix.js
  • includes/classes/blocks/class-bindings.php
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Validate generated code against WordPress standards, test thoroughly, check security implications, and review for proper sanitization/escaping

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • src/js/blocks/paragraph-prefix.js
  • includes/classes/blocks/class-bindings.php
**/*.{js,jsx,ts,tsx,php,scss,css}

📄 CodeRabbit inference engine (GEMINI.md)

Use camelCase for variable and function names, kebab-case for CSS classes, and snake_case for PHP variable names per WordPress Coding Standards

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • src/js/blocks/paragraph-prefix.js
  • includes/classes/blocks/class-bindings.php
**/*.{js,jsx,ts,tsx,scss,css}

📄 CodeRabbit inference engine (GEMINI.md)

For performance optimization, implement code splitting, lazy loading, and minimize CSS/JavaScript bundle sizes in block components

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • src/js/blocks/paragraph-prefix.js
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts,tsx,jsx}: Use async/await syntax; avoid .then() chains
Use named exports; avoid default exports unless wrapping a module

Files:

  • build/blocks/best-time-to-visit/index.js
  • build/paragraph-prefix.js
  • src/blocks/best-time-to-visit/index.js
  • src/js/blocks/paragraph-prefix.js
src/blocks/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Block API v3 standards when developing blocks

Files:

  • src/blocks/best-time-to-visit/index.js
{src/blocks/**/*.{js,jsx,ts,tsx},src/**/*.php,inc/**/*.php}

📄 CodeRabbit inference engine (AGENTS.md)

Apply WCAG 2.2 AA accessibility standards to all blocks and UI components

Files:

  • src/blocks/best-time-to-visit/index.js
src/**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{js,ts,tsx,jsx}: Document public functions with JSDoc
Do not include any WordPress-related imports, functions, or file structures
Do not reference or assume plugins like WooCommerce or Wetu

Files:

  • src/blocks/best-time-to-visit/index.js
  • src/js/blocks/paragraph-prefix.js
**/blocks/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

PHP render callbacks must be properly documented with descriptions of attributes and return values

Files:

  • includes/classes/blocks/class-query-loop.php
  • build/blocks/best-time-to-visit/index.asset.php
  • includes/classes/blocks/class-bindings.php
**/*query*loop*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Implement filter and search functionality in query-loop patterns with proper WP_Query parameter handling and caching strategies

Files:

  • includes/classes/blocks/class-query-loop.php
**/*.php

📄 CodeRabbit inference engine (AGENTS.md)

Follow WordPress Coding Standards (WPCS) for all WordPress code

**/*.php: Store block patterns in the /patterns/ directory at the root of the plugin (WordPress standard for plugins), not in /includes/patterns/
Use text domain 'tour-operator' for all localization strings in the plugin

Files:

  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • includes/classes/blocks/class-bindings.php
**/*.{php,html}

📄 CodeRabbit inference engine (.github/instructions/patterns-templates-refactoring.instructions.md)

**/*.{php,html}: Always use LSX_TO_URL and LSX_TO_PATH constants for asset paths in plugin files
Include CSS variable fallbacks with absolute hex values in inline styles for plugin compatibility with any theme
Use CSS variable format var(--wp--preset--[type]--[name], fallback_value) in inline styles, not var:preset|[type]|[name] format
Use var:preset|[type]|[name] format only within JSON block attributes, not in inline styles
Use the correct spacing preset names: 'tiny' (10px), 'small' (16px), 'medium' (32px), 'large' (48px), and 'x-small' (8px)

Files:

  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • includes/classes/blocks/class-bindings.php
**/*.{php,twig}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not generate .php, .twig, or legacy CMS files

Files:

  • includes/classes/blocks/class-query-loop.php
  • patterns/itinerary-list.php
  • build/blocks/best-time-to-visit/index.asset.php
  • build/paragraph-prefix.asset.php
  • includes/classes/blocks/class-bindings.php
**/patterns/*.php

📄 CodeRabbit inference engine (.github/instructions/figma-to-wordpress-pattern-extraction.instructions.md)

**/patterns/*.php: WordPress pattern PHP files must be located in /patterns/[pattern-slug].php at root level with required metadata in PHP DocBlock
Use plugin constants like LSX_TO_URL for asset paths in pattern files, not theme functions like get_template_directory_uri()
Always use 'tour-operator' as the text domain for internationalization functions in WordPress pattern files
Wrap all user-facing text in internationalization functions (esc_html_e(), (), esc_attr()) in WordPress pattern files
Preserve Figma layer names in WordPress blocks using the metadata attribute with 'name' property
Use block binding source 'lsx/post-meta' for custom data connections in WordPress block patterns
Use self-closing block syntax for dynamic/static blocks (e.g., lsx-tour-operator/icons, post-featured-image) that render via PHP
Do not embed SVG markup directly in icon block patterns; use self-closing icon block syntax to allow dynamic rendering
Include absolute fallback values (hex colors, rem sizes) for all CSS variables in inline styles within WordPress patterns
Use WordPress preset slug format in JSON block attributes (var:preset|color|slug format) separately from inline CSS fallback syntax
Add PHP DocBlock metadata with title, slug (tour-operator/pattern-name format), description, categories, keywords, block types, and post types to WordPress pattern files
Use LSX_TO_URL constant to reference plugin assets instead of theme asset functions in pattern content strings
Include the phpcs:ignoreFile comment for PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage at the top of WordPress pattern PHP files
Use available icon block attributes (iconType: 'outline'|'solid', iconName from icon library) in lsx-tour-operator/icons blocks within patterns

**/patterns/*.php: Use PHP array return format for plugin patterns instead of file header comments (unlike themes where patterns auto-register from /patterns/ using file headers)
Include required pattern properties: 'title' and e...

Files:

  • patterns/itinerary-list.php
**/{patterns,templates,parts}/*.{php,html}

📄 CodeRabbit inference engine (.github/instructions/patterns-templates-refactoring.instructions.md)

**/{patterns,templates,parts}/*.{php,html}: For icon blocks, use self-closing syntax and never embed HTML content inside icon block markup to prevent validation errors
Use primary color preset for buttons, borders, and main brand elements; use 'contrast' preset for text/links; use 'base' for white backgrounds

Files:

  • patterns/itinerary-list.php
**/{templates,patterns,parts}/*.{php,html}

📄 CodeRabbit inference engine (.github/instructions/patterns-templates-refactoring.instructions.md)

Use wide alignment constraint for main content containers in single templates and align-full for full-width sections like breadcrumbs

Files:

  • patterns/itinerary-list.php
🧬 Code graph analysis (2)
build/paragraph-prefix.js (1)
build/blocks/best-time-to-visit/index.js (4)
  • e (1-1)
  • t (1-1)
  • a (1-1)
  • i (1-1)
includes/classes/blocks/class-bindings.php (2)
includes/functions.php (5)
  • lsx_to_has_itinerary (38-52)
  • lsx_to_itinerary_loop (62-70)
  • lsx_to_itinerary_loop_item (80-86)
  • lsx_to_itinerary_accommodation (349-351)
  • lsx_to_itinerary_accommodation_type (361-363)
includes/template-tags/general.php (2)
  • lsx_to_itinerary_drinks_basis (90-103)
  • lsx_to_itinerary_room_basis (53-66)
🪛 PHPMD (2.15.0)
includes/classes/blocks/class-query-loop.php

528-528: The variable $found_items is not named in camelCase. (undefined)

(CamelCaseVariableName)

includes/classes/blocks/class-bindings.php

311-311: The variable $build_template is not named in camelCase. (undefined)

(CamelCaseVariableName)


319-319: The variable $itinerary_count is not named in camelCase. (undefined)

(CamelCaseVariableName)


420-423: The method build_itinerary_field uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)

(ElseExpression)


431-437: The method maybe_get_prefix is not named in camelCase. (undefined)

(CamelCaseMethodName)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (14)
build/paragraph-prefix.asset.php (1)

1-1: LGTM!

Standard auto-generated asset file with updated version hash reflecting the source changes.

build/blocks/best-time-to-visit/index.js (1)

1-1: LGTM!

Minified build output corresponding to the source file. Logic verification is performed on the source file.

src/blocks/best-time-to-visit/index.js (2)

45-49: Verify alignment consistency between inner blocks.

The parent wrapper (line 38) and example (line 103) use verticalAlignment: 'top', but this inner group still uses verticalAlignment: 'middle'. If the change to 'top' was intentional for consistent visual appearance, consider updating this inner group as well.

                     {
                         layout: {
                             type: 'flex',
                             flexWrap: 'nowrap',
-                            verticalAlignment: 'middle',
+                            verticalAlignment: 'top',
                         },
                     },

103-103: LGTM!

Vertical alignment change to 'top' in the example block aligns with the parent wrapper's layout setting.

build/blocks/best-time-to-visit/index.asset.php (1)

1-1: LGTM!

Standard auto-generated asset file with correct wp-i18n dependency.

includes/classes/blocks/class-query-loop.php (1)

178-179: LGTM!

Direct use of get_post_meta for raw value retrieval is cleaner and more efficient than the previous approach.

build/paragraph-prefix.js (1)

1-1: Build reflects source file issues.

This minified build contains the undeclared styleEl variable bug identified in src/js/blocks/paragraph-prefix.js. Once the source file is fixed, this will need to be rebuilt.

includes/classes/blocks/class-bindings.php (3)

420-423: Logic is correct; else block is appropriate here.

The static analysis hint suggests avoiding else expressions, but in this context, the else block clearly separates the two mutually exclusive outcomes (hide element vs. prepend prefix). The current structure is readable and appropriate.


370-398: Prefix handling for itinerary fields looks good.

The addition of prefix extraction for location, accommodation, type, drinks, and room fields follows a consistent pattern and integrates well with the existing field-building logic.


318-336: Itinerary rendering refactor using build template is well-structured.

The change to use $build_template as a dedicated template for each itinerary item iteration is a cleaner approach than mutating the original block content directly. The implementation correctly preserves the template and aggregates results.

patterns/itinerary-list.php (4)

59-60: "Card Link" placeholder coordinates with PHP rendering logic.

The placeholder text "Card Link" in the paragraph blocks is intentionally replaced by the maybe_get_prefix method in class-bindings.php. This coupling works but could benefit from a code comment explaining the relationship for future maintainers.

Consider adding a comment near the pattern content explaining the placeholder:

// Note: "Card Link" is a placeholder that gets replaced during render by class-bindings.php::maybe_get_prefix()

Also applies to: 67-68, 75-76, 83-84, 91-92


16-23: Pattern metadata is properly configured.

The pattern array includes all required properties: title, description, categories, keywords, and inserter setting. The inserter => false is appropriate for patterns intended for programmatic insertion only.


57-94: Itinerary information rows are well-structured.

The wrapper groups (itin-location-wrapper, itin-accommodation-wrapper, etc.) provide proper hooks for the PHP rendering logic to hide empty fields. The use of self-closing icon block syntax and prefix attributes follows the coding guidelines.


24-25: Full-width alignment correctly implemented.

The columns block now uses align="full" attribute and alignfull class, which is appropriate for full-width sections per the coding guidelines.

Comment on lines +311 to +315
$build_template = $block_content;
$group = array();

//$pattern_registry = \WP_Block_Patterns_Registry::get_instance();
//$pattern_registry->get_registered();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove commented-out code or explain its purpose.

The commented-out pattern registry code on lines 314-315 appears to be dead code. If it's no longer needed, remove it to maintain code cleanliness. If it's intended for future use, add a TODO comment explaining the intent.

 		$build_template = $block_content;
 		$group          = array();

-		//$pattern_registry = \WP_Block_Patterns_Registry::get_instance();
-		//$pattern_registry->get_registered();
-
 		// Iterate through and build our itinerary from the block content template.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$build_template = $block_content;
$group = array();
//$pattern_registry = \WP_Block_Patterns_Registry::get_instance();
//$pattern_registry->get_registered();
$build_template = $block_content;
$group = array();
// Iterate through and build our itinerary from the block content template.
🧰 Tools
🪛 PHPMD (2.15.0)

311-311: The variable $build_template is not named in camelCase. (undefined)

(CamelCaseVariableName)

🤖 Prompt for AI Agents
In includes/classes/blocks/class-bindings.php around lines 311 to 315, there is
commented-out code referencing the WP_Block_Patterns_Registry; remove these two
commented lines if they are not needed to eliminate dead code and keep the file
clean, or if they are intentionally left for future use, replace the commented
lines with a single TODO comment that explains why the registry code is
preserved and when/how it should be re-enabled.

Comment on lines +431 to +437
public function maybe_get_prefix( $key, $build ) {
$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
if ( preg_match( $pattern, $build, $matches ) ) {
return str_replace( 'Card Link', '', $matches[1] );
}
return '';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add PHPDoc documentation for the new method.

Per coding guidelines, PHP render callbacks and methods must be properly documented with descriptions of attributes and return values. The maybe_get_prefix method is missing its PHPDoc block.

+	/**
+	 * Extracts the prefix text from a block's HTML content based on a CSS class key.
+	 *
+	 * Searches for a paragraph element with the specified class and returns its
+	 * inner content with placeholder text removed.
+	 *
+	 * @param string $key   The CSS class identifier to search for (e.g., 'itinerary-location').
+	 * @param string $build The HTML content to search within.
+	 * @return string The extracted prefix text, or empty string if not found.
+	 */
 	public function maybe_get_prefix( $key, $build ) {
 		$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
 		if ( preg_match( $pattern, $build, $matches ) ) {
 			return str_replace( 'Card Link', '', $matches[1] );
 		}
 		return '';
 	}
🧰 Tools
🪛 PHPMD (2.15.0)

431-437: The method maybe_get_prefix is not named in camelCase. (undefined)

(CamelCaseMethodName)

🤖 Prompt for AI Agents
In includes/classes/blocks/class-bindings.php around lines 431 to 437, the new
method maybe_get_prefix is missing PHPDoc; add a PHPDoc block immediately above
the method that briefly describes what the method does, documents the parameters
($key string The CSS class/key to search for, $build string The HTML block
content to search), specifies the return value (string The extracted prefix or
an empty string), and includes any relevant tags such as @since and @return (and
@param for each parameter) consistent with existing project doc style.

Comment on lines +432 to +434
$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
if ( preg_match( $pattern, $build, $matches ) ) {
return str_replace( 'Card Link', '', $matches[1] );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Hardcoded placeholder string creates tight coupling.

The hardcoded 'Card Link' string creates implicit coupling between this PHP method and the pattern template. Consider extracting this as a class constant or making it configurable to improve maintainability and make the relationship explicit.

+	/**
+	 * Placeholder text used in itinerary patterns that gets replaced with actual content.
+	 *
+	 * @var string
+	 */
+	const ITINERARY_PLACEHOLDER = 'Card Link';
+
 	public function maybe_get_prefix( $key, $build ) {
 		$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
 		if ( preg_match( $pattern, $build, $matches ) ) {
-			return str_replace( 'Card Link', '', $matches[1] );
+			return str_replace( self::ITINERARY_PLACEHOLDER, '', $matches[1] );
 		}
 		return '';
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
if ( preg_match( $pattern, $build, $matches ) ) {
return str_replace( 'Card Link', '', $matches[1] );
/**
* Placeholder text used in itinerary patterns that gets replaced with actual content.
*
* @var string
*/
const ITINERARY_PLACEHOLDER = 'Card Link';
public function maybe_get_prefix( $key, $build ) {
$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
if ( preg_match( $pattern, $build, $matches ) ) {
return str_replace( self::ITINERARY_PLACEHOLDER, '', $matches[1] );
}
return '';
}
🤖 Prompt for AI Agents
In includes/classes/blocks/class-bindings.php around lines 432 to 434, the
method currently uses the hardcoded string 'Card Link' when stripping the
matched content which couples the code to the template; replace the literal with
a named class constant (e.g. CARD_LINK_PLACEHOLDER) or a configurable
property/filter and use that constant/property in the str_replace call so the
placeholder is explicit and maintainable, add the constant to the class (or
accept/configure via constructor or apply_filters) and update any tests/usages
to reference the new constant/property.

Comment on lines +522 to +528
/**
* lsx_to_related_connection_found_items filter.
* @var $key
* @var $current_item_ID
*/
$key = apply_filters( 'lsx_to_related_connection_query_key', $to . '_to_' . $from, get_the_ID() );
$found_items = get_post_meta( get_the_ID(), $key, true );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider improving the filter documentation.

The filter introduction is a good refactor for flexibility. However, the docblock format could be improved to follow WordPress documentation standards for filters:

-		/**
-		 * lsx_to_related_connection_found_items filter.
-		 * @var $key
-		 * @var $current_item_ID
-		 */
-		$key         = apply_filters( 'lsx_to_related_connection_query_key', $to . '_to_' . $from, get_the_ID() );
+		/**
+		 * Filters the post meta key used to retrieve related connection items.
+		 *
+		 * @since 2.1.0
+		 *
+		 * @param string $key     The default meta key (e.g., 'tour_to_accommodation').
+		 * @param int    $post_id The current post ID.
+		 * @return string The filtered meta key.
+		 */
+		$key         = apply_filters( 'lsx_to_related_connection_query_key', $to . '_to_' . $from, get_the_ID() );

Note: The PHPMD warning about $found_items naming is a false positive — WordPress PHP coding standards use snake_case for variable names.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* lsx_to_related_connection_found_items filter.
* @var $key
* @var $current_item_ID
*/
$key = apply_filters( 'lsx_to_related_connection_query_key', $to . '_to_' . $from, get_the_ID() );
$found_items = get_post_meta( get_the_ID(), $key, true );
/**
* Filters the post meta key used to retrieve related connection items.
*
* @since 2.1.0
*
* @param string $key The default meta key (e.g., 'tour_to_accommodation').
* @param int $post_id The current post ID.
* @return string The filtered meta key.
*/
$key = apply_filters( 'lsx_to_related_connection_query_key', $to . '_to_' . $from, get_the_ID() );
$found_items = get_post_meta( get_the_ID(), $key, true );
🧰 Tools
🪛 PHPMD (2.15.0)

528-528: The variable $found_items is not named in camelCase. (undefined)

(CamelCaseVariableName)

<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)"><!-- wp:group {"metadata":{"name":"' . esc_attr__( 'Location Row', 'tour-operator' ) . '"},"className":"itin-location-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"wrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-location-wrapper"><!-- wp:group {"style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"destinationIcon"} /-->
<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add absolute fallback values for CSS variables in inline styles.

Per coding guidelines, inline styles must include CSS variable fallbacks with absolute hex/rem values for plugin compatibility with any theme. The spacing variables should have fallback values.

For example, line 54 should include fallbacks:

-<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)">
+<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30, 1.5rem);padding-right:var(--wp--preset--spacing--30, 1.5rem);padding-bottom:var(--wp--preset--spacing--30, 1.5rem);padding-left:var(--wp--preset--spacing--30, 1.5rem)">

This applies to other inline styles throughout the pattern as well (lines 35, 41, etc.).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)">
<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30, 1.5rem);padding-right:var(--wp--preset--spacing--30, 1.5rem);padding-bottom:var(--wp--preset--spacing--30, 1.5rem);padding-left:var(--wp--preset--spacing--30, 1.5rem)">
🤖 Prompt for AI Agents
In patterns/itinerary-list.php around line 54 (and similarly update lines 35,
41, etc.), the inline style uses CSS variables without absolute fallbacks;
update each var(...) to include a concrete fallback value (e.g. spacing vars use
a rem fallback like var(--wp--preset--spacing--30, 1.875rem) and color vars use
a hex fallback like var(--wp--preset--color--base-background, #ffffff)),
applying the corresponding rem/hex fallbacks for every spacing and color
variable in the inline style attributes so the block works even when theme
variables are unavailable.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +431 to +435
public function maybe_get_prefix( $key, $build ) {
$pattern = '/<p\s+[^>]*\bclass="[^"]*\b' . esc_attr( $key ) . '\b[^"]*"[^>]*>(.*?)<\/p>/is';
if ( preg_match( $pattern, $build, $matches ) ) {
return str_replace( 'Card Link', '', $matches[1] );
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve itinerary prefixes on frontend output

The new itinerary pattern now stores labels (e.g., “Location:”, “Accommodation:”, “Type:”) in the paragraph prefix attribute while the rendered HTML contains only the Card Link placeholder. maybe_get_prefix() still derives the prefix from the paragraph inner HTML and strips the placeholder (str_replace( 'Card Link', '', $matches[1] )), so it returns an empty string for all itinerary fields. When build_itinerary_field() then concatenates $prefix . $value, the frontend itinerary list renders values without any labels, while the prefix pseudo-element is applied only in the editor. Users viewing itineraries will no longer see which value corresponds to location, accommodation, type, drinks, or room.

Useful? React with 👍 / 👎.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request merges the feature/unit-blocks branch, introducing new unit block functionalities and refining existing ones. The changes align with WordPress coding standards. My review focuses on improving code clarity, maintainability, and addressing some internationalization regressions. I've pointed out areas with commented-out code, redundant conditions, and opportunities for refactoring to reduce code duplication. I've also highlighted incorrect PHPDoc and hardcoded strings that should be made translatable.

Comment on lines +54 to +97
<div class="wp-block-group lsx-itinerary-info has-base-background-color has-background" style="border-radius:0.5rem;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)">

<!-- wp:paragraph {"style":{"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"medium"} -->
<p class="has-medium-font-size" style="font-style:normal;font-weight:700">' . esc_html__( 'Location:', 'tour-operator' ) . '</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:paragraph {"metadata":{"name":"' . esc_attr__( 'Location Value', 'tour-operator' ) . '"},"className":"itinerary-location","fontSize":"medium"} -->
<p class="itinerary-location has-medium-font-size">' . esc_html__( 'Location', 'tour-operator' ) . '</p>
<!-- wp:group {"metadata":{"name":"Location Row"},"className":"itin-location-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-location-wrapper"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"destinationIcon"} /-->
<!-- wp:paragraph {"metadata":{"name":"Location Value"},"className":"itinerary-location","fontSize":"medium","prefix":"Location:","prefixBold":true} -->
<p class="itinerary-location has-medium-font-size">Card Link</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:group {"metadata":{"name":"' . esc_attr__( 'Accommodation Row', 'tour-operator' ) . '"},"className":"itin-accommodation-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"wrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-accommodation-wrapper"><!-- wp:group {"style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"accommodationIcon"} /-->

<!-- wp:paragraph {"style":{"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"medium"} -->
<p class="has-medium-font-size" style="font-style:normal;font-weight:700">' . esc_html__( 'Accommodation:', 'tour-operator' ) . '</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:paragraph {"metadata":{"name":"' . esc_attr__( 'Accommodation Value', 'tour-operator' ) . '"},"className":"itinerary-accommodation","fontSize":"medium"} -->
<p class="itinerary-accommodation has-medium-font-size">' . esc_html__( 'Card Link', 'tour-operator' ) . '</p>
<!-- wp:group {"metadata":{"name":"Accommodation Row"},"className":"itin-accommodation-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-accommodation-wrapper"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"accommodationIcon"} /-->
<!-- wp:paragraph {"metadata":{"name":"Accommodation Value"},"className":"itinerary-accommodation","fontSize":"medium","prefix":"Accommodation:","prefixBold":true} -->
<p class="itinerary-accommodation has-medium-font-size">Card Link</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:group {"metadata":{"name":"' . esc_attr__( 'Type Row', 'tour-operator' ) . '"},"className":"itin-type-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"wrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-type-wrapper"><!-- wp:group {"style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"accommodationTypeIcon"} /-->

<!-- wp:paragraph {"style":{"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"medium"} -->
<p class="has-medium-font-size" style="font-style:normal;font-weight:700">' . esc_html__( 'Type:', 'tour-operator' ) . '</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:paragraph {"metadata":{"name":"' . esc_attr__( 'Type Value', 'tour-operator' ) . '"},"className":"itinerary-type","fontSize":"medium"} -->
<p class="itinerary-type has-medium-font-size">' . esc_html__( 'Card Link', 'tour-operator' ) . '</p>
<!-- wp:group {"metadata":{"name":"Type Row"},"className":"itin-type-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"top"}} -->
<div class="wp-block-group itin-type-wrapper"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"accommodationTypeIcon"} /-->
<!-- wp:paragraph {"metadata":{"name":"Type Value"},"className":"itinerary-type","fontSize":"medium","prefix":"Type:","prefixBold":true} -->
<p class="itinerary-type has-medium-font-size">Card Link</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:group {"metadata":{"name":"' . esc_attr__( 'Drinks Basis Row', 'tour-operator' ) . '"},"className":"itin-drinks-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"wrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-drinks-wrapper"><!-- wp:group {"style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"drinksBasisIcon"} /-->

<!-- wp:paragraph {"style":{"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"medium"} -->
<p class="has-medium-font-size" style="font-style:normal;font-weight:700">' . esc_html__( 'Drinks Basis:', 'tour-operator' ) . '</p>
<!-- wp:group {"metadata":{"name":"Drinks Basis Row"},"className":"itin-drinks-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"top"}} -->
<div class="wp-block-group itin-drinks-wrapper"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"drinksBasisIcon"} /-->
<!-- wp:paragraph {"metadata":{"name":"Drinks Basis Value"},"className":"itinerary-drinks","fontSize":"medium","prefix":"Drinks Basis:","prefixBold":true} -->
<p class="itinerary-drinks has-medium-font-size">Card Link</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:paragraph {"metadata":{"name":"' . esc_attr__( 'Drinks Basis Value', 'tour-operator' ) . '"},"className":"itinerary-drinks","fontSize":"medium"} -->
<p class="itinerary-drinks has-medium-font-size">' . esc_html__( 'Card Link', 'tour-operator' ) . '</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:group {"metadata":{"name":"' . esc_attr__( 'Room Basis Row', 'tour-operator' ) . '"},"className":"itin-room-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"wrap","verticalAlignment":"center"}} -->
<div class="wp-block-group itin-room-wrapper"><!-- wp:group {"style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"roomBasisIcon"} /-->

<!-- wp:paragraph {"style":{"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"medium"} -->
<p class="has-medium-font-size" style="font-style:normal;font-weight:700">' . esc_html__( 'Room Basis:', 'tour-operator' ) . '</p>
<!-- wp:group {"metadata":{"name":"Room Basis Row"},"className":"itin-room-wrapper","style":{"spacing":{"blockGap":"0.3125rem"}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"top"}} -->
<div class="wp-block-group itin-room-wrapper"><!-- wp:lsx-tour-operator/icons {"iconType":"solid","iconName":"roomBasisIcon"} /-->
<!-- wp:paragraph {"metadata":{"name":"Room Basis Value"},"className":"itinerary-room","fontSize":"medium","prefix":"Room Basis:","prefixBold":true} -->
<p class="itinerary-room has-medium-font-size">Card Link</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->

<!-- wp:paragraph {"metadata":{"name":"' . esc_attr__( 'Room Basis Value', 'tour-operator' ) . '"},"className":"itinerary-room","fontSize":"medium"} -->
<p class="itinerary-room has-medium-font-size">' . esc_html__( 'Card Link', 'tour-operator' ) . '</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group --></div>
<!-- /wp:group --></div>

</div><!-- /wp:group --></div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This refactoring has introduced internationalization (i18n) regressions. Several strings that were previously translatable are now hardcoded:

  1. The placeholder text Card Link is no longer wrapped in a translation function like esc_html__().
  2. The metadata.name attributes in the block comments (e.g., "name":"Location Row") are also hardcoded and should be made translatable with esc_attr__().

Please wrap these strings in the appropriate WordPress translation functions to ensure the pattern is fully localizable.

Comment on lines +314 to +315
//$pattern_registry = \WP_Block_Patterns_Registry::get_instance();
//$pattern_registry->get_registered();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This commented-out code should be removed to keep the codebase clean. If this was for debugging, it should be removed before merging.

Comment on lines 370 to 398
case 'location':
$value = lsx_to_itinerary_destinations( '', '', false );
$pattern = '/(<p\s+[^>]*\bclass="[^"]*\bitinerary-location\b[^"]*"[^>]*>).*?(<\/p>)/is';
$prefix = $this->maybe_get_prefix( 'itinerary-location', $build );
break;

case 'accommodation':
$value = lsx_to_itinerary_accommodation( '', '', false );
$pattern = '/(<p\s+[^>]*\bclass="[^"]*\bitinerary-accommodation\b[^"]*"[^>]*>).*?(<\/p>)/is';
$prefix = $this->maybe_get_prefix( 'itinerary-accommodation', $build );
break;

case 'type':
$value = lsx_to_itinerary_accommodation_type( '', '', false );
$pattern = '/(<p\s+[^>]*\bclass="[^"]*\bitinerary-type\b[^"]*"[^>]*>).*?(<\/p>)/is';
$prefix = $this->maybe_get_prefix( 'itinerary-type', $build );
break;

case 'drinks':
$value = lsx_to_itinerary_drinks_basis( '', '', false );
$pattern = '/(<p\s+[^>]*\bclass="[^"]*\bitinerary-drinks\b[^"]*"[^>]*>).*?(<\/p>)/is';
$prefix = $this->maybe_get_prefix( 'itinerary-drinks', $build );
break;

case 'room':
$value = lsx_to_itinerary_room_basis( '', '', false );
$pattern = '/(<p\s+[^>]*\bclass="[^"]*\bitinerary-room\b[^"]*"[^>]*>).*?(<\/p>)/is';
$prefix = $this->maybe_get_prefix( 'itinerary-room', $build );
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The switch statement contains a lot of repetitive code for cases 'location', 'accommodation', 'type', 'drinks', and 'room'. This could be refactored to be more concise and maintainable by using a data structure like an associative array to map fields to their respective functions and then handling them generically.

For example:

$field_map = [
    'location'      => 'lsx_to_itinerary_destinations',
    'accommodation' => 'lsx_to_itinerary_accommodation',
    'type'          => 'lsx_to_itinerary_accommodation_type',
    'drinks'        => 'lsx_to_itinerary_drinks_basis',
    'room'          => 'lsx_to_itinerary_room_basis',
];

if ( array_key_exists( $field, $field_map ) ) {
    $value   = call_user_func( $field_map[ $field ], '', '', false );
    $pattern = '/(<p\s+[^>]*\bclass="[^"]*\bitinerary-' . $field . '\b[^"]*"[^>]*>).*?(<\/p>)/is';
    $prefix  = $this->maybe_get_prefix( 'itinerary-' . $field, $build );
    break;
}

@@ -408,6 +417,9 @@ public function build_itinerary_field( $build = '', $field = '', $count = 1 ) {
if ( '' === $value || false === $value || empty( $value ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The condition '' === $value || false === $value || empty( $value ) is redundant. The empty() function already checks for '' and false, among other empty values. You can simplify this to just empty( $value ) for better readability and conciseness.

if ( empty( $value ) ) {

Comment on lines +178 to +179
// Get the raw unfiltered value.
$value = get_post_meta( get_the_ID(), $meta_key, true );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While using get_post_meta() directly to get the raw value is a valid approach, it bypasses the lsx_to_custom_field_query() function which might contain important logic or filters. Ensure that this change is intentional and that bypassing the existing helper function doesn't lead to unintended side effects or inconsistencies in how meta values are retrieved across the plugin.

Comment on lines +522 to +526
/**
* lsx_to_related_connection_found_items filter.
* @var $key
* @var $current_item_ID
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The PHPDoc for this filter is incorrect. The filter name in the comment (lsx_to_related_connection_found_items) does not match the one being used (lsx_to_related_connection_query_key), and @var should be @param for function/filter parameters. Please correct the docblock to accurately reflect the filter being added.

		/**
		 * Filters the meta key for the related connection query.
		 *
		 * @param string $key             The meta key, e.g., '{$to}_to_{$from}'.
		 * @param int    $current_item_ID The current post ID.
		 */

@github-actions github-actions bot added lang:md Markdown content/docs status:needs-review Awaiting code review and removed status:needs-review Awaiting code review labels Dec 17, 2025
@krugazul krugazul merged commit 8975da9 into 2.1-trunk Dec 17, 2025
6 of 10 checks passed
@krugazul krugazul deleted the feature/unit-blocks branch December 17, 2025 12:14
@krugazul krugazul restored the feature/unit-blocks branch December 17, 2025 12:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4933bd and 6f4c275.

📒 Files selected for processing (4)
  • build/blocks/destination-to-tour/index.asset.php (1 hunks)
  • build/blocks/destination-to-tour/index.js (1 hunks)
  • changelog.md (1 hunks)
  • src/blocks/destination-to-tour/index.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use semicolons to terminate statements in JavaScript block code

Ensure all generated code follows ESLint rules and WordPress Coding Standards before deployment

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
**/*.{php,js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (GEMINI.md)

Follow WordPress Coding Standards including proper namespacing, security practices (sanitization/escaping), and code organization

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
  • build/blocks/destination-to-tour/index.asset.php
**/*.{js,jsx,ts,tsx,php}

📄 CodeRabbit inference engine (GEMINI.md)

Implement accessibility features following WCAG 2.2 AA standards in all block components and patterns

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
  • build/blocks/destination-to-tour/index.asset.php
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Validate generated code against WordPress standards, test thoroughly, check security implications, and review for proper sanitization/escaping

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
  • build/blocks/destination-to-tour/index.asset.php
**/*.{js,jsx,ts,tsx,php,scss,css}

📄 CodeRabbit inference engine (GEMINI.md)

Use camelCase for variable and function names, kebab-case for CSS classes, and snake_case for PHP variable names per WordPress Coding Standards

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
  • build/blocks/destination-to-tour/index.asset.php
**/*.{js,jsx,ts,tsx,scss,css}

📄 CodeRabbit inference engine (GEMINI.md)

For performance optimization, implement code splitting, lazy loading, and minimize CSS/JavaScript bundle sizes in block components

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts,tsx,jsx}: Use async/await syntax; avoid .then() chains
Use named exports; avoid default exports unless wrapping a module

Files:

  • build/blocks/destination-to-tour/index.js
  • src/blocks/destination-to-tour/index.js
src/blocks/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Block API v3 standards when developing blocks

Files:

  • src/blocks/destination-to-tour/index.js
{src/blocks/**/*.{js,jsx,ts,tsx},src/**/*.php,inc/**/*.php}

📄 CodeRabbit inference engine (AGENTS.md)

Apply WCAG 2.2 AA accessibility standards to all blocks and UI components

Files:

  • src/blocks/destination-to-tour/index.js
src/**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{js,ts,tsx,jsx}: Document public functions with JSDoc
Do not include any WordPress-related imports, functions, or file structures
Do not reference or assume plugins like WooCommerce or Wetu

Files:

  • src/blocks/destination-to-tour/index.js
**/blocks/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

PHP render callbacks must be properly documented with descriptions of attributes and return values

Files:

  • build/blocks/destination-to-tour/index.asset.php
**/*.php

📄 CodeRabbit inference engine (AGENTS.md)

Follow WordPress Coding Standards (WPCS) for all WordPress code

**/*.php: Store block patterns in the /patterns/ directory at the root of the plugin (WordPress standard for plugins), not in /includes/patterns/
Use text domain 'tour-operator' for all localization strings in the plugin

Files:

  • build/blocks/destination-to-tour/index.asset.php
**/*.{php,html}

📄 CodeRabbit inference engine (.github/instructions/patterns-templates-refactoring.instructions.md)

**/*.{php,html}: Always use LSX_TO_URL and LSX_TO_PATH constants for asset paths in plugin files
Include CSS variable fallbacks with absolute hex values in inline styles for plugin compatibility with any theme
Use CSS variable format var(--wp--preset--[type]--[name], fallback_value) in inline styles, not var:preset|[type]|[name] format
Use var:preset|[type]|[name] format only within JSON block attributes, not in inline styles
Use the correct spacing preset names: 'tiny' (10px), 'small' (16px), 'medium' (32px), 'large' (48px), and 'x-small' (8px)

Files:

  • build/blocks/destination-to-tour/index.asset.php
**/*.{php,twig}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not generate .php, .twig, or legacy CMS files

Files:

  • build/blocks/destination-to-tour/index.asset.php
🧬 Code graph analysis (1)
build/blocks/destination-to-tour/index.js (2)
build/blocks/units/index.js (4)
  • t (1-1)
  • e (1-1)
  • n (1-1)
  • s (1-1)
build/blocks/destination-to-accommodation/index.js (4)
  • t (1-1)
  • o (1-1)
  • a (1-1)
  • s (1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (1)
src/blocks/destination-to-tour/index.js (1)

79-79: The lsx/post-connection binding source properly supports the parents parameter.

The parameter is correctly implemented in the post_connections_callback method at lines 179–181 of includes/classes/blocks/class-bindings.php, where it filters the post list to include only top-level items when set to true. Existing block instances without this parameter maintain current functionality since the default value is false, ensuring backward compatibility.

- **Sticky Menu Block** - Added sticky navigation menu block with desktop and mobile navigation support for single post templates, includes anchor support and section group functionality - [#684](https://github.com/lightspeedwp/tour-operator/pull/684), Issue [#496](https://github.com/lightspeedwp/tour-operator/issues/496)
- **TO Videos Block** - Added YouTube video gallery block for displaying videos on tours, accommodation, and destination templates in a professional gallery layout - [#598](https://github.com/lightspeedwp/tour-operator/pull/598), Issue [#397](https://github.com/lightspeedwp/tour-operator/issues/397)
- **Check-in/Checkout Time Icon Blocks** - Added icon-based blocks (replacing images) for check-in and checkout times with filters to display only on relevant post types (accommodation) and related templates - [#645](https://github.com/lightspeedwp/tour-operator/pull/645)
- **Unit Blocks** - Added comprehensive unit blocks functionality with refined assets and WordPress coding standards alignment - [#815](https://github.com/lightspeedwp/tour-operator/pull/815)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Expand the changelog entry with more detail.

The Unit Blocks changelog entry is quite brief compared to other entries in this section. Consider adding more detail about:

  • What unit blocks functionality was added
  • What specific assets were refined
  • What WordPress coding standards alignment changes were made

This will help users better understand the scope of changes in this release.

🤖 Prompt for AI Agents
In changelog.md around line 36, expand the single-line "Unit Blocks" entry into
a more descriptive paragraph that lists what unit block functionality was added
(e.g., new block types, settings, and editor interactions), specifies which
assets were refined (e.g., updated stylesheets, SVG icons, JS bundle size
optimizations and image assets), and enumerates the WordPress coding standards
alignment changes (e.g., PHP linting fixes, sanitized inputs, docblock updates,
and PSR-style formatting). Replace the terse line with a concise 2–4 sentence
entry covering these points and include the existing PR reference and issue
number for traceability.

@coderabbitai coderabbitai bot mentioned this pull request Dec 18, 2025
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:block-editor area:theme Theme & styles (templates, template parts, FSE) lang:javascript lang:md Markdown content/docs lang:php PHP code meta:needs-changelog Requires a changelog entry before merge status:needs-review Awaiting code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant