Skip to content

Generate custom social images from SVG templates via Linkable entities#235

Draft
Copilot wants to merge 18 commits intomainfrom
copilot/generate-custom-social-images
Draft

Generate custom social images from SVG templates via Linkable entities#235
Copilot wants to merge 18 commits intomainfrom
copilot/generate-custom-social-images

Conversation

Copy link
Contributor

Copilot AI commented Dec 18, 2025

  • Refactor to use yassg_svg_url() from LinkableExtension
  • Fix fragile block check by defining empty fallback
  • Update demo templates to use new approach
  • Move SVG templates to correct location (pages/ not social/)
  • Update documentation
  • Fix hardcoded URL and malformed README examples
Original prompt

This section details on the original issue you should resolve

<issue_title>Generate custom social images</issue_title>
<issue_description>Example https://opengraph.githubassets.com/ffc3f988f382ffd8f6ed506138a96127ea9c75c723a84985a6cb9a2d22ca6142/sigwinhq/yassg

Project is using ImgProxy internally, idea is to allow specifying (an optionally overriding per article, category, etc) a SVG which we can render and it would get served via ImgProxy which dumps it into a WebP or whatever and then it's served as the social image.

The override could in theory work by us having a dedicated (overrideable in the downstream project) Twig template which we inject the current article into when rendering, it gets processed via ImgProxy when building like any asset.</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 6 commits December 18, 2025 19:50
Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Copilot AI changed the title [WIP] Add functionality to generate custom social images Generate custom social images from SVG templates via ImgProxy Dec 18, 2025
Copilot AI requested a review from dkarlovi December 18, 2025 20:01
@dkarlovi
Copy link
Collaborator

@copilot good start, but I think we can start like this:

  1. let's think of the social image like "the Accept: application/svg for the article / page etc in question, like a SVG representation of it
  2. we can then use the same url + .svg (instead of .html or nothing) for this SVG
  3. the route knows which thing it needs to render and that it needs to produce a SVG,
  4. it injects these things into the Twig template which produces a valid SVG
  5. we then use that SVG URL with yassg_thumbnail() function which by default passes it through ImgProxy and dumps it during build, just like any other asset

We could probably tweak the route loader which creates the routes or we might not even need to, it supports passing extensions already (just .html, needs examination).

TLDR:

  1. /some/article - HTML
  2. /some/article.svg, that same article, but rendered as a SVG
  3. yassg_thumbnail("/some/article.svg"), should already work as expected

…umbnail

- Simplified yassg_social_image() to return SVG URL (e.g., /article/slug.svg)
- Updated RouteLoader to support .svg extension alongside .html
- Modified DefaultController to render social/{route}.svg.twig templates
- Removed configuration for social_image_template (no longer needed)
- Updated templates to use yassg_thumbnail(yassg_social_image(entity))
- SVG templates now receive same context as HTML templates
- Images processed through ImgProxy at build time via existing AssetQueue

Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 18, 2025

@copilot good start, but I think we can start like this:

  1. let's think of the social image like "the Accept: application/svg for the article / page etc in question, like a SVG representation of it...

Implemented in eb55c8b. The approach now works as follows:

  1. /article/slug renders HTML from pages/article.html.twig
  2. /article/slug.svg renders SVG from social/article.svg.twig
  3. yassg_social_image(article) returns /article/slug.svg
  4. yassg_thumbnail(yassg_social_image(article)) processes it through ImgProxy

The RouteLoader supports .svg extension and DefaultController detects it to render the appropriate SVG template. The SVG template receives the same context (article, etc.) as the HTML template.

- Fixed RouteLoader regex to properly match index.html or .svg
- Changed yassg_social_image to use _filename parameter instead of _format
- Simplified DefaultController SVG detection to check _filename === '.svg'

Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Copilot AI changed the title Generate custom social images from SVG templates via ImgProxy Generate custom social images from SVG templates via route-based rendering Dec 18, 2025
Copilot AI requested a review from dkarlovi December 18, 2025 20:54
Copy link
Collaborator

@dkarlovi dkarlovi left a comment

Choose a reason for hiding this comment

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

@copilot I've vastly simplified your approach since we already had the Linkable extension, this just expanded on it.

See how can we handle the block check not working, maybe we define an empty one like for title and then only use it if redefined?

- Define empty social_image block in layouts to prevent errors when block is not defined
- Update demo Page model to implement Linkable interface
- Move SVG templates from social/ to pages/ directory to match controller expectations
- Update demo templates to use yassg_svg_url() with block pattern
- Update README with simplified approach using yassg_svg_url() and blocks

Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements dynamic social image generation by allowing routes to render SVG variants that can be processed through ImgProxy. The implementation adds a new Twig function yassg_svg_url() to generate SVG URLs for entities, updates the routing layer to support .svg extensions, and modifies the controller to render SVG templates with appropriate content types.

Key changes:

  • Route system now supports .svg extension alongside .html for any route
  • New yassg_svg_url() Twig function generates SVG URLs from Linkable entities
  • Controller detects SVG requests and renders SVG templates with proper content type headers

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/Bridge/Twig/Extension/LinkableExtension.php Adds yassg_svg_url() function to generate SVG URLs by appending _filename: 'index.svg' parameter
src/Bridge/Symfony/Routing/Loader/RouteLoader.php Updates route requirement regex to allow both index.html and index.svg extensions
src/Bridge/Symfony/Controller/DefaultController.php Adds SVG detection logic and renders appropriate template with image/svg+xml content type
tests/functional/site/templates/pages/article.svg.twig Adds SVG template for article pages with dynamic content from article entity
tests/functional/site/templates/pages/article.html.twig Uses yassg_svg_url() in social_image block
tests/functional/site/templates/layout.html.twig Integrates social image URL into Open Graph and Twitter Card meta tags
resources/init/demo/templates/social/demo.svg.twig Provides demo SVG template with gradient background and dynamic text
resources/init/demo/templates/layout.html.twig Demonstrates social image integration in demo layout
composer.json Explicitly adds symfony/dependency-injection to requirements
README.md Documents the social image generation feature with usage examples

{% block body %}
{# ... #}
{% endblock %}
```
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The README documentation states that SVG templates should be created in templates/social/{route}.svg.twig, but the actual controller implementation in DefaultController.php line 47 looks for templates in pages/{route}.svg.twig. This mismatch will cause the documented approach to fail with template not found errors. Either the documentation should be updated to reflect the actual pages/ directory, or the controller should be modified to look in the social/ directory for SVG templates.

Copilot uses AI. Check for mistakes.

<title>{{ demo_page.title }}</title>

{% block social_image %}{% endblock %}
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

Type error: The yassg_svg_url() function requires a Linkable parameter, but demo_page is of type App\Model\Page which does not implement the Linkable interface (see resources/init/demo/src/Model/Page.php). This will cause a TypeError at runtime. The Page class needs to implement the Linkable interface with getLinkRouteName() and getLinkRouteParameters() methods.

Copilot uses AI. Check for mistakes.

<title>{{ demo_page.title }}</title>

{% block social_image %}{% endblock %}
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The function yassg_social_image() does not exist in the codebase. The actual function added in LinkableExtension.php is yassg_svg_url(). This will cause a runtime error when the template is rendered. The function call should be changed to yassg_svg_url(demo_page).

Suggested change
{% block social_image %}{% endblock %}
{% set social_image_url = yassg_thumbnail(yassg_svg_url(demo_page), {width: 1200, height: 630, format: 'webp'}) %}

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +111
```

The SVG template receives the same variables as the HTML template (article, page, etc.).

Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The code example is malformed with incomplete syntax. Lines 107-110 contain a closing code block with dangling code that appears to be leftover from editing. The example should either be removed or completed properly. The fragment "format: 'png'" and closing braces/backticks don't belong to any coherent code example.

Suggested change
```
The SVG template receives the same variables as the HTML template (article, page, etc.).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in daf3ca2. Removed the malformed code fragment (format: 'png' and extra closing braces/backticks).

Copy link
Contributor Author

Copilot AI commented Dec 18, 2025

@copilot I've vastly simplified your approach since we already had the Linkable extension, this just expanded on it.

See how can we handle the block check not working, maybe we define an empty one ...

Fixed in 90dd6f2. Added an empty {% block social_image %}{% endblock %} definition in the layout templates before calling block('social_image'). This provides a fallback so templates that don't define the block won't cause build failures. Child templates can override it when they have a Linkable entity to generate social images.

Copilot AI changed the title Generate custom social images from SVG templates via route-based rendering Generate custom social images from SVG templates via Linkable entities Dec 18, 2025
Copilot AI requested a review from dkarlovi December 18, 2025 21:46

Revamp when we have a full Docker build setup
#}
{% set social_image_url = "http://app:9988"~block('social_image') %}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hardcoded here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in daf3ca2. Removed the hardcoded URL and now using absolute_url() properly, consistent with the demo layout.

- Remove hardcoded "http://app:9988" URL and use absolute_url() properly
- Fix malformed code block in README (remove dangling format: 'png' fragment)
- Makes test layout consistent with demo layout approach

Co-authored-by: dkarlovi <209225+dkarlovi@users.noreply.github.com>
Copilot AI requested a review from dkarlovi January 15, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Generate custom social images

3 participants