Root cause of social icons rendering as alt text: wp_kses() stripped
the 'data:' prefix from data: URIs in img.src, leaving a relative URL
that 404s. Switched to real .svg files under assets/icons/ referenced
via plugins_url() — kses passes img tags with relative URLs cleanly,
and the icons load as standard images.
Root cause of avatar still being cropped: layout-side issues with
inline-styled <img> in a flex layout. Switched to a <span> with
inline background-image, background-size: cover, background-position:
center — no <img> element, no object-fit reliance, no way to crop wrong.
Also removed the outer <a> wrapper around the .project-owner div
(block-level element inside inline <a> is invalid HTML and was likely
contributing to layout weirdness). The owner name is now an explicit
<a> inside its own span.
Reverted kses to the default wp_kses_post() since we're back to
standard HTML elements only — no SVG, no data URIs, no inline styles
that need a custom allowed list.
Inline <svg> elements render with their default width/height in browsers
even when 'style' and width/height attributes are set (a known quirk
in mixed HTML5/SVG content with some CSS specificity scenarios). Switched
to <img src='data:image/svg+xml,...'> instead. This is universally well-
supported, sizes via standard <img> CSS rules (no namespace/parser edge
cases), and the inline 'width=20 height=20 style=width:20px;height:20px'
on <img> reliably applies.
Added 'img' and 'style' to the kses allowed list so wp_kses() preserves
the data: URI src and the inline styles.
- Add inline width/height attributes AND style='width:20px;height:20px;
display:block' to each social-share SVG. Inline styles have higher
specificity than any CSS rule, so the icons should now size correctly
regardless of theme CSS or specificity quirks.
- Bump PROJECTS_PORTFOLIO_VERSION to 1.1.9 (and plugin header) so
WordPress invalidates the cached stylesheet URL.
- Removed the <rect x='0' y='0' width='24' height='24' fill='none'> viewport
markers from each social-share SVG. With 'fill=none' the rect was
still visible if any inherited stroke wasn't suppressed (which turned
out to be unreliable across themes/CSS specificity).
- Removed redundant width='24' height='24' attributes from each SVG so
the CSS .project-social-sharing svg { width:20px; height:20px } can
size them unambiguously.
- Inlined avatar <img> styles (width:50px; height:50px; border-radius:50%;
object-fit:cover; flex-shrink:0; display:block) so the avatar is
guaranteed to render as a 50x50 circle regardless of theme CSS.
- Switched .project-owner-avatar to inline-flex so the span shrinks to
the image's natural size within the flex parent.
wp_kses_post() strips <svg> tags by default (the 'post' context doesn't
allow them), so the icons were being silently removed from the rendered
HTML. Extend the allowed list to include svg/path/rect/circle/line with
the attributes the Tabler-style icons actually use.
- .project-github-button renamed to .project-repo-button (added 1px border
for proper outline style; the old class is gone so the button was rendering
as unstyled <a>).
- Suppress inherited stroke on the Tabler SVG <rect> viewport marker — without
this it draws a square outline inside the round social-share button.
- Move owner avatar inline styles into CSS with object-fit: cover, explicit
width/height, and border-radius: 50%; add flex shrink/grow rules for the
owner row's three spans so the avatar isn't squashed by the flex layout.
The social-share buttons function was hooked to
projects_after_download_button, but the template never fired that action —
the buttons never rendered. Added a do_action() call after the View Repo
button.
The Follow button hardcoded a GitHub URL and used the GitHub-specific
github-button class (which only acts on github.com). Replaced with a
plain styled link pointing at the owner's actual URL (works for any
provider). Removed the assets/js/buttons.js enqueue since nothing uses
the github-button class anymore.
Renamed the project-github-button CSS class on the View Repo link to
project-repo-button since it's provider-neutral now.
wp_safe_redirect() rejects external hosts not in WP's allowed list and
silently falls back to admin_url() — which is why /download/{id}/ was
redirecting to /wp-admin/ on a clean install. Switch to wp_redirect()
since the URL is explicitly user-configured.
The bundled PUC was missing the setBranch() method on the main UpdateChecker
class (it's only on Vcs\PluginUpdateChecker via the VcsCheckerMethods trait).
When called with a non-VCS URL like the Gitea update URL, this caused a fatal
error at plugin activation.
Updating to PUC v5.7 (May 2026) which is the latest upstream release. The
setBranch() call is removed because PUC doesn't recognize Gitea as a VCS host;
the plugin falls back to PUC's plain JSON metadata mode, which is fine for a
plugin hosted on a self-managed repo.
Single workflow file at .github/workflows/release.yml that triggers
on v* tag pushes, assembles projects-portfolio-v<version>.zip from
an allowlist of runtime files, uploads as a workflow artifact, and
attaches to a matching GitHub release.
15-task plan with TDD-style steps, WP PHPUnit tests, and a
provider-interface architecture. Tasks cover scaffolding, both
adapters, factory, settings, metabox, template, REST, download
redirect, version bump, README, translations, and final smoke
testing.
Adds a provider interface with GitHub and Gitea adapters so each
project can link to either provider. Preserves existing GitHub
behavior bit-for-bit, adds lazy migration from legacy meta, and
ships WP PHPUnit tests.