Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"pestphp/pest": "^3.8",
"pestphp/pest-plugin-laravel": "^3.1",
"orchestra/testbench": "^10.2",
"artisanpack-ui/cms-framework": "^1.1"
"artisanpack-ui/cms-framework": "^2.0"
},
"repositories": [
{
Expand All @@ -48,10 +48,10 @@
],
"suggest": {
"artisanpack-ui/media-library": "Recommended ^1.2 — default media library integration. Wire MediaModal + uploadMedia through registerArtisanpackMediaBridge() in the editor bootstrap to power Gutenberg's media picker and upload flows. Not enforced by Composer; host apps are free to install a different library and register a custom bridge instead.",
"artisanpack-ui/cms-framework": "Required ^1.1 for the site editor — the `/visual-editor/site-editor` route is hard-coupled to cms-framework's templates, parts, patterns, global styles, and menus modules (plan 14). Without it, the post-content editor still works but the site editor route returns an install gate."
"artisanpack-ui/cms-framework": "Required ^2.0 for the site editor + comments family — the `/visual-editor/site-editor` route is hard-coupled to cms-framework's templates, parts, patterns, global styles, and menus modules (plan 14), and the comments-family forks (#519) consume the Blog module's `Comment` model + `Post::comments` relation introduced in 2.1. Without it, the post-content editor still works but the site editor route returns an install gate and the comments-family blocks render against an empty data set."
},
"_comments": {
"repositories": "The path repository to ../cms-framework is a development-only convenience for the symlinked workflow used in the dev-app (see ../artisanpack-ui-dev/composer.json). On a fresh clone without the sibling cms-framework checkout, composer install will fail to resolve cms-framework — that's expected for now; the package's release pipeline pulls cms-framework from Packagist via the ^1.1 constraint. CI removes this entry before installing. Tracked for a permanent fix (e.g. an env-gated repository) in #434."
"repositories": "The path repository to ../cms-framework is a development-only convenience for the symlinked workflow used in the dev-app (see ../artisanpack-ui-dev/composer.json). On a fresh clone without the sibling cms-framework checkout, composer install will fail to resolve cms-framework — that's expected for now; the package's release pipeline pulls cms-framework from Packagist via the ^2.0 constraint. CI removes this entry before installing. Tracked for a permanent fix (e.g. an env-gated repository) in #434."
},
"scripts": {
"test": "./vendor/bin/pest"
Expand Down
15 changes: 13 additions & 2 deletions config/visual-editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@
'artisanpack/search',
'artisanpack/latest-posts',
// Comments family — Pass 1 forks (#519): wrapper + template +
// per-comment display blocks. Post-level comments metadata and
// pagination blocks are deferred to Pass 2.
// per-comment display blocks.
'artisanpack/comments',
'artisanpack/comment-template',
'artisanpack/comment-author-avatar',
Expand All @@ -159,6 +158,18 @@
'artisanpack/comment-date',
'artisanpack/comment-edit-link',
'artisanpack/comment-reply-link',
// Comments family — Pass 2 forks (#519): post-level comments
// metadata + pagination cluster. Post-level display blocks
// resolve through PostResolver; pagination blocks render
// against request-time state.
'artisanpack/post-comments-form',
'artisanpack/post-comments-count',
'artisanpack/post-comments-link',
'artisanpack/post-comments-title',
'artisanpack/comments-pagination',
'artisanpack/comments-pagination-next',
'artisanpack/comments-pagination-numbers',
'artisanpack/comments-pagination-previous',
],

'disabled_blocks' => [
Expand Down
18 changes: 17 additions & 1 deletion packages/renderer-parity.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@
"artisanpack/site-logo",
"artisanpack/navigation",
"artisanpack/query",
"artisanpack/post-template"
"artisanpack/post-template",
"artisanpack/comments",
"artisanpack/comment-template",
"artisanpack/comment-author-avatar",
"artisanpack/comment-author-name",
"artisanpack/comment-content",
"artisanpack/comment-date",
"artisanpack/comment-edit-link",
"artisanpack/comment-reply-link",
"artisanpack/post-comments-form",
"artisanpack/post-comments-count",
"artisanpack/post-comments-link",
"artisanpack/post-comments-title",
"artisanpack/comments-pagination",
"artisanpack/comments-pagination-next",
"artisanpack/comments-pagination-numbers",
"artisanpack/comments-pagination-previous"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$url = UrlSanitizer::safe( isset( $attributes['_resolvedAvatarUrl'] ) && is_string( $attributes['_resolvedAvatarUrl'] ) ? $attributes['_resolvedAvatarUrl'] : '' );
$alt = isset( $attributes['_resolvedAvatarAlt'] ) && is_string( $attributes['_resolvedAvatarAlt'] ) ? $attributes['_resolvedAvatarAlt'] : '';

$width = isset( $attributes['width'] ) && is_numeric( $attributes['width'] ) ? (int) $attributes['width'] : 96;
$height = isset( $attributes['height'] ) && is_numeric( $attributes['height'] ) ? (int) $attributes['height'] : 96;
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comment-author-avatar' ] ) !!}>
@if ( '' !== $url )
<img src="{{ $url }}" alt="{{ $alt }}" width="{{ $width }}" height="{{ $height }}" loading="lazy" />
@endif
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$isLink = ! empty( $attributes['isLink'] );
$linkTarget = isset( $attributes['linkTarget'] ) && is_string( $attributes['linkTarget'] ) ? $attributes['linkTarget'] : '_self';

$name = isset( $attributes['_resolvedAuthorName'] ) && is_string( $attributes['_resolvedAuthorName'] ) ? $attributes['_resolvedAuthorName'] : '';
$authorUrl = UrlSanitizer::safe( isset( $attributes['_resolvedAuthorUrl'] ) && is_string( $attributes['_resolvedAuthorUrl'] ) ? $attributes['_resolvedAuthorUrl'] : '' );

$linkAttrs = 'href="' . e( $authorUrl ) . '"';
if ( '_blank' === $linkTarget ) {
$linkAttrs .= ' target="_blank" rel="noopener noreferrer"';
}
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comment-author-name' ] ) !!}>
@if ( $isLink && '' !== $authorUrl )
<a {!! $linkAttrs !!}>{{ $name }}</a>
@else
{{ $name }}
@endif
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;

$content = isset( $attributes['_resolvedContent'] ) && is_string( $attributes['_resolvedContent'] ) ? $attributes['_resolvedContent'] : '';
$align = isset( $attributes['textAlign'] ) && is_string( $attributes['textAlign'] ) ? $attributes['textAlign'] : '';

$classes = [ 'wp-block-comment-content' ];
if ( '' !== $align ) {
$classes[] = 'has-text-align-' . $align;
}
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, $classes ) !!}>
{!! $content !!}
</div>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$dateIso = isset( $attributes['_resolvedDate'] ) && is_string( $attributes['_resolvedDate'] ) ? $attributes['_resolvedDate'] : '';
$date = isset( $attributes['_resolvedDateFormatted'] ) && is_string( $attributes['_resolvedDateFormatted'] ) ? $attributes['_resolvedDateFormatted'] : '';
$url = UrlSanitizer::safe( isset( $attributes['_resolvedPermalink'] ) && is_string( $attributes['_resolvedPermalink'] ) ? $attributes['_resolvedPermalink'] : '' );

$isLink = ! empty( $attributes['isLink'] );
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comment-date' ] ) !!}>
@if ( $isLink && '' !== $url )
<a href="{{ $url }}">
@if ( '' !== $dateIso )
<time datetime="{{ $dateIso }}">{{ $date }}</time>
@else
{{ $date }}
@endif
</a>
@elseif ( '' !== $dateIso )
<time datetime="{{ $dateIso }}">{{ $date }}</time>
@else
{{ $date }}
@endif
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$url = UrlSanitizer::safe( isset( $attributes['_resolvedEditLinkUrl'] ) && is_string( $attributes['_resolvedEditLinkUrl'] ) ? $attributes['_resolvedEditLinkUrl'] : '' );
$label = isset( $attributes['_resolvedEditLinkLabel'] ) && is_string( $attributes['_resolvedEditLinkLabel'] ) ? $attributes['_resolvedEditLinkLabel'] : __( 'Edit' );

$linkTarget = isset( $attributes['linkTarget'] ) && is_string( $attributes['linkTarget'] ) ? $attributes['linkTarget'] : '_self';
$targetAttr = '_blank' === $linkTarget ? ' target="_blank" rel="noopener noreferrer"' : '';
@endphp
@if ( '' !== $url )
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comment-edit-link' ] ) !!}>
<a href="{{ $url }}"{!! $targetAttr !!}>{{ $label }}</a>
</div>
@endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$url = UrlSanitizer::safe( isset( $attributes['_resolvedReplyLinkUrl'] ) && is_string( $attributes['_resolvedReplyLinkUrl'] ) ? $attributes['_resolvedReplyLinkUrl'] : '' );
$label = isset( $attributes['_resolvedReplyLinkLabel'] ) && is_string( $attributes['_resolvedReplyLinkLabel'] ) ? $attributes['_resolvedReplyLinkLabel'] : __( 'Reply' );
@endphp
@if ( '' !== $url )
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comment-reply-link' ] ) !!}>
<a href="{{ $url }}">{{ $label }}</a>
</div>
@endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
@endphp
{{--
comment-template wrapper.

The server-side CommentInliner clones this block's inner tree once
per resolved comment and stamps each iteration with the per-comment
`_resolved*` attributes via CommentResolver, then concatenates the
rendered iterations into `$innerBlocksHtml`. The renderer just
wraps the result in the `<ol class="wp-block-comment-template">`
scaffold WordPress uses.
--}}
<ol{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comment-template' ] ) !!}>
{!! $innerBlocksHtml !!}
</ol>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$url = UrlSanitizer::safe( isset( $attributes['_resolvedNextPageUrl'] ) && is_string( $attributes['_resolvedNextPageUrl'] ) ? $attributes['_resolvedNextPageUrl'] : '' );
$label = isset( $attributes['label'] ) && is_string( $attributes['label'] ) && '' !== $attributes['label']
? $attributes['label']
: __( 'Newer Comments' );
@endphp
@if ( '' !== $url )
<a{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments-pagination-next' ] ) !!} href="{{ $url }}">{{ $label }} &rarr;</a>
@else
<span{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments-pagination-next' ] ) !!}>{{ $label }}</span>
@endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$pages = isset( $attributes['_resolvedPageNumbers'] ) && is_array( $attributes['_resolvedPageNumbers'] ) ? $attributes['_resolvedPageNumbers'] : [];
$current = isset( $attributes['_resolvedCurrentPage'] ) && is_numeric( $attributes['_resolvedCurrentPage'] ) ? (int) $attributes['_resolvedCurrentPage'] : 1;
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments-pagination-numbers' ] ) !!}>
@foreach ( $pages as $page )
@php
$number = isset( $page['number'] ) && is_numeric( $page['number'] ) ? (int) $page['number'] : 0;
$href = UrlSanitizer::safe( isset( $page['url'] ) && is_string( $page['url'] ) ? $page['url'] : '' );
@endphp
@if ( 0 !== $number )
@if ( $number === $current || '' === $href )
<span class="page-numbers current" aria-current="page">{{ $number }}</span>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
@else
<a class="page-numbers" href="{{ $href }}">{{ $number }}</a>
@endif
@endif
@endforeach
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$url = UrlSanitizer::safe( isset( $attributes['_resolvedPreviousPageUrl'] ) && is_string( $attributes['_resolvedPreviousPageUrl'] ) ? $attributes['_resolvedPreviousPageUrl'] : '' );
$label = isset( $attributes['label'] ) && is_string( $attributes['label'] ) && '' !== $attributes['label']
? $attributes['label']
: __( 'Older Comments' );
@endphp
@if ( '' !== $url )
<a{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments-pagination-previous' ] ) !!} href="{{ $url }}">&larr; {{ $label }}</a>
@else
<span{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments-pagination-previous' ] ) !!}>{{ $label }}</span>
@endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
@endphp
<nav{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments-pagination' ] ) !!} aria-label="{{ __( 'Comments pagination' ) }}">
{!! $innerBlocksHtml !!}
</nav>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;

$tagName = isset( $attributes['tagName'] ) && is_string( $attributes['tagName'] ) ? $attributes['tagName'] : 'div';
$tagName = in_array( strtolower( $tagName ), [ 'div', 'section', 'article', 'aside', 'footer' ], true ) ? strtolower( $tagName ) : 'div';
@endphp
<{!! $tagName !!}{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-comments' ] ) !!}>
{!! $innerBlocksHtml !!}
</{!! $tagName !!}>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;

$count = isset( $attributes['_resolvedCommentCount'] ) && is_numeric( $attributes['_resolvedCommentCount'] ) ? (int) $attributes['_resolvedCommentCount'] : 0;
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-post-comments-count' ] ) !!}>{{ $count }}</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

// Default form target is the cms-framework comments REST endpoint
// (`POST /api/v1/comments`). That route returns 201 + JSON though,
// which is great for SPAs but not for a plain HTML form submit —
// the browser navigates to the JSON. Host apps that want a
// classic form-post UX should override this via the
// `comments.form.action` filter (artisanpack-ui/hooks) and point
// it at a controller that creates the comment and redirects back.
$defaultAction = isset( $attributes['_resolvedFormAction'] ) && is_string( $attributes['_resolvedFormAction'] )
? $attributes['_resolvedFormAction']
: '/api/v1/comments';
if ( function_exists( 'applyFilters' ) ) {
$defaultAction = ( string ) applyFilters( 'comments.form.action', $defaultAction );
}
$formAction = UrlSanitizer::safe( $defaultAction );
@endphp
{{--
post-comments-form

Renders a minimal, semantically-correct comment form. The default
`action` posts to cms-framework's `/api/v1/comments` endpoint; the
`comments.form.action` filter lets host apps redirect submissions
to their own controller so they can validate, persist, and redirect
back to the post with a flash message — the standard browser-form
UX the API endpoint can't provide on its own.
--}}
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-post-comments-form', 'comment-respond' ] ) !!}>
<h3 class="comment-reply-title">{{ __( 'Leave a Comment' ) }}</h3>
<form action="{{ $formAction }}" method="post" class="comment-form">
@if ( function_exists( 'csrf_field' ) )
{!! csrf_field() !!}
@endif
@isset( $attributes['_resolvedPostId'] )
<input type="hidden" name="post_id" value="{{ (int) $attributes['_resolvedPostId'] }}" />
@endisset
<p class="comment-form-author">
<label for="comment-author">{{ __( 'Name' ) }} <span aria-hidden="true">*</span></label>
<input id="comment-author" name="author_name" type="text" autocomplete="name" required />
</p>
<p class="comment-form-email">
<label for="comment-email">{{ __( 'Email' ) }} <span aria-hidden="true">*</span></label>
<input id="comment-email" name="author_email" type="email" autocomplete="email" required />
</p>
<p class="comment-form-url">
<label for="comment-url">{{ __( 'Website' ) }}</label>
<input id="comment-url" name="author_url" type="url" autocomplete="url" />
</p>
<p class="comment-form-comment">
<label for="comment-content">{{ __( 'Comment' ) }} <span aria-hidden="true">*</span></label>
<textarea id="comment-content" name="content" rows="6" required></textarea>
</p>
<p class="form-submit">
{{-- Deliberately no `name="submit"` on the input — that
attribute shadows the form's `.submit` property in
the DOM and breaks any JS that hooks the form
(analytics, validation libraries, etc.). The
value isn't read server-side either. --}}
<input type="submit" class="submit" value="{{ __( 'Post Comment' ) }}" />
</p>
</form>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;
use ArtisanPackUI\VisualEditorRendererBlade\Support\UrlSanitizer;

$count = isset( $attributes['_resolvedCommentCount'] ) && is_numeric( $attributes['_resolvedCommentCount'] ) ? (int) $attributes['_resolvedCommentCount'] : 0;
$url = UrlSanitizer::safe( isset( $attributes['_resolvedCommentsUrl'] ) && is_string( $attributes['_resolvedCommentsUrl'] ) ? $attributes['_resolvedCommentsUrl'] : '' );
$label = isset( $attributes['_resolvedCommentsLabel'] ) && is_string( $attributes['_resolvedCommentsLabel'] )
? $attributes['_resolvedCommentsLabel']
: trans_choice( '{0} :count Comments|{1} :count Comment|[2,*] :count Comments', $count, [ 'count' => $count ] );
@endphp
<div{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-post-comments-link' ] ) !!}>
@if ( '' !== $url )
<a href="{{ $url }}">{{ $label }}</a>
@else
{{ $label }}
@endif
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@php
use ArtisanPackUI\VisualEditorRendererBlade\Support\BlockSupports;

$level = isset( $attributes['level'] ) && is_numeric( $attributes['level'] ) ? (int) $attributes['level'] : 2;
$level = max( 1, min( 6, $level ) );
$tag = 'h' . $level;

$showCount = ! isset( $attributes['showCommentsCount'] ) || ! empty( $attributes['showCommentsCount'] );
$count = isset( $attributes['_resolvedCommentCount'] ) && is_numeric( $attributes['_resolvedCommentCount'] ) ? (int) $attributes['_resolvedCommentCount'] : 0;
$title = isset( $attributes['_resolvedCommentsTitle'] ) && is_string( $attributes['_resolvedCommentsTitle'] )
? $attributes['_resolvedCommentsTitle']
: ( 0 === $count ? 'No Comments' : ( 1 === $count ? '1 Comment' : $count . ' Comments' ) );

if ( ! $showCount ) {
$title = 'Comments';
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

$align = isset( $attributes['textAlign'] ) && is_string( $attributes['textAlign'] ) ? $attributes['textAlign'] : '';
$classes = [ 'wp-block-post-comments-title' ];
if ( '' !== $align ) {
$classes[] = 'has-text-align-' . $align;
}
@endphp
<{!! $tag !!}{!! BlockSupports::wrapperAttrs( $attributes, $classes ) !!}>{{ $title }}</{!! $tag !!}>
Loading
Loading