Lucide (https://lucide.dev) replaces the hand-rolled Tabler paths. Lucide
is more compact and consistent, and ships under the ISC license (more
permissive than Tabler's MIT and equally fine for plugin redistribution).
Lucide has no brand icons for Reddit/WhatsApp/Pinterest, so we use
generic substitutes that preserve the visual intent:
- reddit.svg <- lucide 'share-2' (community share metaphor)
- whatsapp.svg <- lucide 'message-circle'
- pinterest.svg<- lucide 'pin'
Avatar: shrunk to 40x40 per user testing — sizes above 41x41 were being
clipped inside the round border on this host.
The 'cover' keyword was producing fallback 'auto auto' rendering in some
environments (likely a kses/CSS shorthand quirk). Switching to explicit
pixel values matching the container size has the same visual effect
for the 270x270 source image and works reliably across all browsers.
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.