Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tinyeditor Picture Tag Laravel Package

isapp/tinyeditor-picture-tag

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup Steps

  1. Install Dependencies

    composer require isapp/tinyeditor-picture-tag spatie/laravel-medialibrary
    

    Ensure spatie/laravel-medialibrary is properly configured (follow Spatie’s docs).

  2. Publish Config

    php artisan vendor:publish --provider="Isapp\TinyEditorPictureTag\TinyEditorPictureTagServiceProvider"
    

    Configure config/tinyeditor-picture-tag.php with:

    • picture_tag_config (e.g., ['webp', 'avif'] for formats)
    • model_observers (array of observed models)
    • tiny_mce_content_field (default: content)
  3. Register Observer Add the observer to your model (e.g., Post.php):

    use Isapp\TinyEditorPictureTag\Observers\PictureTagObserver;
    
    class Post extends Model
    {
        protected static function booted()
        {
            static::observe(PictureTagObserver::class);
        }
    }
    
  4. First Use Case Insert an <img> via TinyMCE into a model’s content field. After saving, the observer converts it to a <picture> tag with responsive sources (e.g., WebP/AVIF fallbacks).


Implementation Patterns

Core Workflow

  1. TinyMCE Integration

    • Use TinyMCE’s default image plugin to insert <img> tags (e.g., src="/storage/123.jpg").
    • The observer triggers after model saved() or updated().
  2. Observer Logic

    • Extracts <img> tags from the content field (configurable).
    • Replaces them with <picture> tags using Spatie’s media library to generate responsive sources:
      <picture>
        <source srcset="/storage/123.webp" type="image/webp">
        <source srcset="/storage/123.avif" type="image/avif">
        <img src="/storage/123.jpg" alt="...">
      </picture>
      
    • Preserves TinyMCE’s alt, title, and class attributes.
  3. Configuration-Driven

    • Define supported formats in picture_tag_config (e.g., ['webp', 'avif', 'jpg']).
    • Customize the <picture> structure via picture_tag_template in config.
  4. Bulk Processing

    • Use the PictureTagHelper facade to manually process content:
      use Isapp\TinyEditorPictureTag\Facades\PictureTagHelper;
      
      $processedContent = PictureTagHelper::process($content);
      

Integration Tips

  • Spatie Media Library: Ensure images are registered as media (e.g., hasMany(Media::class)).
  • TinyMCE Setup: Configure TinyMCE to output src paths compatible with Spatie’s storage (e.g., /storage/filename.jpg).
  • Caching: Disable observer for bulk imports to avoid performance hits:
    static::observe(PictureTagObserver::class)->unless(fn () => app()->environment('import'));
    
  • Fallback Handling: Add a default <img> fallback in picture_tag_template if formats fail to load.

Gotchas and Tips

Pitfalls

  1. Observer Timing

    • The observer runs after the model is saved. If you need to process content before saving (e.g., validation), use creating/updating events with manual processing:
      protected static function booted()
      {
          static::saving(function ($model) {
              $model->content = PictureTagHelper::process($model->content);
          });
      }
      
  2. Media Library Paths

    • Error: srcset paths break if Spatie’s storage disk isn’t configured correctly.
    • Fix: Verify config/filesystems.php and config/medialibrary.php match TinyMCE’s output paths.
  3. HTML Sanitization

    • TinyMCE may escape attributes (e.g., srcset). Use PictureTagHelper::process() with htmlspecialchars_decode() if needed:
      $content = htmlspecialchars_decode($content);
      $content = PictureTagHelper::process($content);
      
  4. Performance

    • Issue: Large content fields with many <img> tags may slow down saves.
    • Solution: Limit observer scope (e.g., only run on specific models) or use queue jobs:
      static::saved(function ($model) {
          PictureTagHelper::process($model->content)->later();
      });
      

Debugging

  • Log Output: Enable debug mode in config to log transformations:
    'debug' => env('APP_DEBUG', false),
    
  • Test Locally: Use php artisan tinyeditor-picture-tag:test (if provided) or manually test with:
    $content = '<img src="/storage/test.jpg" alt="Test">';
    dd(PictureTagHelper::process($content));
    

Extension Points

  1. Custom Templates Override the <picture> template in config:

    'picture_tag_template' => '<picture class="custom-class">
        <source srcset="{{ srcset }}" type="{{ type }}">
        <img src="{{ src }}" alt="{{ alt }}" class="{{ class }}">
      </picture>',
    
  2. Dynamic Formats Fetch formats dynamically (e.g., from browser Accept header):

    use Isapp\TinyEditorPictureTag\PictureTagHelper;
    
    $formats = request()->header('Accept') ? ['webp', 'avif'] : ['jpg'];
    $content = PictureTagHelper::process($content, $formats);
    
  3. Exclude Fields Skip processing for specific fields by extending the observer:

    class CustomPictureTagObserver extends PictureTagObserver
    {
        protected $skipFields = ['content', 'excerpt'];
    }
    
  4. WebP Fallback Add a <img> fallback for unsupported browsers:

    'picture_tag_template' => '<picture>
        <source srcset="{{ srcset }}" type="{{ type }}">
        <img src="{{ src }}" alt="{{ alt }}" class="{{ class }}">
        <img src="{{ src }}" alt="{{ alt }}" class="fallback" style="display: none;">
      </picture>',
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope