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

Nova Flexible Content Laravel Package

whitecube/nova-flexible-content

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require whitecube/nova-flexible-content
    php artisan vendor:publish --provider="Whitecube\\NovaFlexibleContent\\NovaFlexibleContentServiceProvider" --tag="nova-flexible-content-config"
    php artisan nova:publish
    
  2. First Use Case: Define a flexible content field in your Nova resource:

    use Whitecube\\NovaFlexibleContent\\FlexibleContent;
    
    public static $fields = [
        FlexibleContent::make('Content Blocks')
            ->items([
                // Define your repeatable field groups here
                FlexibleContent\Items\Item::make('Hero Section', 'hero')
                    ->fields([
                        Text::make('Title'),
                        Textarea::make('Subtitle'),
                    ]),
                FlexibleContent\Items\Item::make('Features', 'features')
                    ->fields([
                        Text::make('Feature Title'),
                        Textarea::make('Description'),
                    ]),
            ]),
    ];
    
  3. Where to Look First:

    • Official Documentation (especially the "Getting Started" and "Field Types" sections)
    • resources/js/tools/FlexibleContent (for custom JS/CSS overrides)
    • config/nova-flexible-content.php (for configuration options)

Implementation Patterns

Core Workflows

  1. Defining Flexible Content:

    • Use FlexibleContent::make() to create a container for repeatable content blocks.
    • Define Item::make() for each unique content type (e.g., "Hero", "Testimonial").
    • Nest standard Nova fields (Text, Textarea, BelongsTo, etc.) inside each Item.
  2. Repeater Fields:

    FlexibleContent::make('FAQs')
        ->items([
            FlexibleContent\Items\Item::make('FAQ Item', 'faq')
                ->fields([
                    Text::make('Question'),
                    Textarea::make('Answer'),
                    Boolean::make('Is Featured'),
                ]),
        ])
        ->minItems(1) // Optional: enforce minimum items
        ->maxItems(10) // Optional: enforce maximum items
    
  3. Dynamic Field Logic:

    • Use when() to conditionally show/hide items based on other fields:
      FlexibleContent::make('Product Options')
          ->items([
              Item::make('Color Options', 'colors')
                  ->fields([...])
                  ->when(fn ($resource) => $resource->isPhysicalProduct),
          ])
      
  4. Integration with Nova Tools:

    • Combine with Nova Media Library for image uploads:
      Item::make('Image Block', 'image')
          ->fields([
              BelongsTo::make('Image', 'image', Media::class),
              Text::make('Caption'),
          ])
      
  5. Resource-Specific Logic:

    • Override the resolveFlexibleContentItems() method in your resource to dynamically fetch or transform data:
      public function resolveFlexibleContentItems($request, $model, $attribute, $requestAttribute)
      {
          return $model->{$attribute}->map(function ($item) {
              return collect($item)->merge(['custom_key' => 'dynamic_value']);
          });
      }
      

Gotchas and Tips

Common Pitfalls

  1. Field Validation:

    • Ensure your model has a morphTo relationship for the flexible content:
      public function flexibleContent()
      {
          return $this->morphMany(FlexibleContentItem::class, 'flexible_contentable');
      }
      
    • Validate nested fields explicitly in your model:
      public static $rules = [
          'content_blocks.*.title' => 'required|max:255',
          'content_blocks.*.hero.title' => 'sometimes|required_if:content_blocks.*.type,hero',
      ];
      
  2. Performance:

    • Avoid eager loading all flexible content in lists/details views. Use lazy loading or query scopes:
      public function scopeWithFlexibleContent($query)
      {
          $query->with(['flexibleContent' => function ($query) {
              $query->with(['items']);
          }]);
      }
      
    • For large datasets, consider caching resolved flexible content:
      protected static $cache = true;
      
  3. Ordering Issues:

    • If items reorder incorrectly, ensure your database column for ordering is named order (default) or override:
      FlexibleContent::make('Blocks')->orderColumn('custom_order_column');
      
    • Use sortable() on the Item level for drag-and-drop:
      Item::make('Section')->sortable();
      
  4. CSRF Token Conflicts:

    • If you encounter CSRF errors with nested forms, add this to your Nova tool:
      // resources/js/tools/FlexibleContent/Tool.js
      this.handleFormEvents = () => {
          this.container.on('submit', 'form', (e) => {
              e.preventDefault();
              const form = e.target;
              form.querySelector('input[name="_token"]').value = this.token;
              form.submit();
          });
      };
      

Pro Tips

  1. Custom Item Templates:

    • Override the item template in your Nova tool:
      // resources/js/tools/FlexibleContent/ItemTemplate.js
      export default class extends ItemTemplate {
          template() {
              return `
                  <div class="flexible-content-item">
                      <h3>{{ this.item.title }}</h3>
                      <div class="fields">
                          {{ this.fields }}
                      </div>
                      <button class="delete-item">Delete</button>
                  </div>
              `;
          }
      }
      
  2. Dynamic Item Types:

    • Fetch item types dynamically from a database table:
      public static function flexibleContentItemTypes()
      {
          return \App\Models\ContentType::all()->pluck('name', 'slug');
      }
      
  3. Localization:

    • Translate item labels and placeholders:
      Item::make('Hero', 'hero')
          ->title(__('nova-flexible-content::items.hero.title'))
          ->fields([
              Text::make(__('nova-flexible-content::fields.title'), 'title'),
          ]);
      
    • Publish the language files:
      php artisan vendor:publish --tag="nova-flexible-content-lang"
      
  4. Testing:

    • Use NovaTestCase to test flexible content:
      public function testFlexibleContent()
      {
          $resource = new YourResource();
          $this->actingAs($this->admin)
               ->call('POST', '/nova/v1/resources/your-resource', [
                   'flexible_content' => [
                       [
                           'type' => 'hero',
                           'title' => 'Test Hero',
                       ],
                   ],
               ]);
      }
      
  5. Extending Core Functionality:

    • Add custom actions to items:
      Item::make('Gallery', 'gallery')
          ->actions([
              new PublishAction(),
          ]);
      
    • Create a custom field type for flexible content:
      class CustomField extends Field
      {
          public function field()
          {
              return FlexibleContent::make('Custom Content')
                  ->items([...]);
          }
      }
      
  6. Debugging:

    • Enable debug mode in config:
      'debug' => env('NOVA_FLEXIBLE_CONTENT_DEBUG', false),
      
    • Check the Nova logs for flexible content-related errors:
      tail -f storage/logs/nova.log | grep "FlexibleContent"
      
    • Use browser dev tools to inspect the data attribute on flexible content containers for raw payloads.
  7. Migration Quirks:

    • If migrating from another package, ensure your database schema matches:
      Schema::table('flexible_content_items', function (Blueprint $table) {
          $table->json('data')->nullable()->change();
          $table->string('type')->nullable()->change();
      });
      

```markdown
## Maintenance and Contribution
- **Open Issues**: Prioritize bugs related to:
  - Drag-and-drop reordering
  - Nested form validation
  - PHP 8.2+ compatibility
- **Testing**: Add tests for edge cases like:
  - Empty flexible content arrays
  - Circular references in nested fields
  - Concurrent saves
- **Documentation**: Update the [official docs](https://whitecube.github.io/nova-flexible-content) with:
  - Real-world examples (e.g., CMS page builder)
  - Performance benchmarks
  - Integration guides (e.g., with Nova Filament, Nova Media Library)
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.
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky