Answers.Body: <p>The return of <code>Browsershot::url()</code> is not the asset path, so you cannot put it like this:</p>
  <pre><code>$asset-&gt;tempFilePath = $image;
  </code></pre>
  <p>You can just pass the path where you put on save arguments directly :</p>
  <pre><code>getcwd() . '/social-images/' . $this-&gt;type . '/' . $this-&gt;elementId . '.png'  
  </code></pre>
  <p>but probably it will cause that file will be deleted, so the better way is to copy your file to craft temp path</p>
  <pre><code>$craftTemp  = Craft::$app-&gt;path-&gt;getTempAssetUploadsPath(true);
  $path       = $craftTemp .'/' . '/sc-' . $this-&gt;elementId;
  copy('getcwd() . '/social-images/' . $this-&gt;type . '/' . $this-&gt;elementId . '.png', $path);
  </code></pre>
  <p>then you can put it on temp path :</p>
  <pre><code>$asset-&gt;tempFilePath = $path;
  </code></pre>
  <p>Another thing is even this work, to save the asset field you need to save the asset first and push the element id as array in setFieldValue().</p>
  <pre><code>class GenerateSocialCard extends BaseJob
  {
    public $element;
    public $type;
    public function execute($queue): void
    {
      $filePath = getcwd() . '/social-images/' . $this-&gt;type . '/' . $this-&gt;elementId . '.png';
      $image = Browsershot::url(getenv('PRIMARY_SITE_URL') . '/social-images/' . $this-&gt;type . '/' . $this-&gt;element-&gt;id)
        -&gt;windowSize(1200, 675)
        -&gt;waitUntilNetworkIdle()
        -&gt;save(filePath);
      
    $craftTemp  = Craft::$app-&gt;path-&gt;getTempAssetUploadsPath(true);
    $path       = $craftTemp .'/' . '/sc-' . $this-&gt;elementId . 'png';
    copy(filePath, $path)
    $asset = new Asset();
    $asset-&gt;newFolderId = 1;
    $asset-&gt;filename = $this-&gt;elementId . '.png';
    $asset-&gt;volumeId = 1;
    $asset-&gt;tempFilePath = $path;
    $asset-&gt;setScenario(Asset::SCENARIO_CREATE);
    Craft::$app-&gt;getElements()-&gt;saveElement($asset);
    $element-&gt;setFieldValue('seoImage', [$asset-&gt;id]);
    Craft::$app-&gt;getElements()-&gt;saveElement($element);
  
    }
  
    protected function defaultDescription(): ?string
    {
      return Craft::t('app', 'Generating Social Image');
    }
  }
  </code></pre>
  <p>PS: I didn't test the code.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-08-21T03:02:07.637Z
Answers.LastActivityDate: 2023-08-21T03:02:07.637Z
Answers.UserDisplayName: aodihis
Body: <p>I'm following this to generate social share images from entries: <a href="https://ghijk.co.uk/blog/generate-dynamic-social-share-images-in-craft-cms" rel="nofollow noreferrer">https://ghijk.co.uk/blog/generate-dynamic-social-share-images-in-craft-cms</a></p>
  <p>It's working well. But I'd like to add the generated image to an asset field on the entry, for better visibility. Is it possible to do that from a queue job?</p>
  <p>Here's what I have so far:</p>
  <pre><code>Event::on(Entry::class, Entry::EVENT_AFTER_SAVE, function (ModelEvent $event) {
    if (!ElementHelper::isDraft($event-&gt;sender) &amp;&amp; !ElementHelper::isRevision($event-&gt;sender)) {
      $element = $event-&gt;sender;
      Craft::$app-&gt;queue-&gt;push(new GenerateSocialCard([
        'element' =&gt; $element,
        'type' =&gt; $element-&gt;type-&gt;handle,
      ]));
    }
  });
  </code></pre>
  <pre><code>class GenerateSocialCard extends BaseJob
  {
    public $element;
    public $type;
    public function execute($queue): void
    {
      $image = Browsershot::url(getenv('PRIMARY_SITE_URL') . '/social-images/' . $this-&gt;type . '/' . $this-&gt;element-&gt;id)
        -&gt;windowSize(1200, 675)
        -&gt;waitUntilNetworkIdle()
        -&gt;save(getcwd() . '/social-images/' . $this-&gt;type . '/' . $this-&gt;elementId . '.png');
      
    $asset = new Asset();
    $asset-&gt;newFolderId = 1;
    $asset-&gt;filename = 'test';
    $asset-&gt;volumeId = 1;
    $asset-&gt;tempFilePath = $image;
    $asset-&gt;setScenario(Asset::SCENARIO_CREATE);
  
    $element-&gt;setFieldValue('seoImage', $asset);
    Craft::$app-&gt;getElements()-&gt;saveElement($element);
  
    }
  
    protected function defaultDescription(): ?string
    {
      return Craft::t('app', 'Generating Social Image');
    }
  }
  </code></pre>
  <p>With this I get a <code>Serialization of 'Closure' is not allowed</code> error so I'm not sure if I should be trying to update the field as part of the queue job or somewhere else.</p>
  <p>Also not sure the asset creation part is right, but I can get to that next.</p>
  <p>Appreciate any pointers!</p>
  
Tags: <modules><queue>
Title: Add to an asset field from a queue job
ThreadText: # Add to an asset field from a queue job
  
  (Asked by: username_0 on 2023-08-19)
  
  I'm following this to generate social share images from entries: <https://ghijk.co.uk/blog/generate-dynamic-social-share-images-in-craft-cms>
  
  It's working well. But I'd like to add the generated image to an asset field on the entry, for better visibility. Is it possible to do that from a queue job?
  
  Here's what I have so far:
  
  ```
  Event::on(Entry::class, Entry::EVENT_AFTER_SAVE, function (ModelEvent $event) {
    if (!ElementHelper::isDraft($event->sender) && !ElementHelper::isRevision($event->sender)) {
      $element = $event->sender;
      Craft::$app->queue->push(new GenerateSocialCard([
        'element' => $element,
        'type' => $element->type->handle,
      ]));
    }
  });
  
  ```
  
  ```
  class GenerateSocialCard extends BaseJob
  {
    public $element;
    public $type;
    public function execute($queue): void
    {
      $image = Browsershot::url(getenv('PRIMARY_SITE_URL') . '/social-images/' . $this->type . '/' . $this->element->id)
        ->windowSize(1200, 675)
        ->waitUntilNetworkIdle()
        ->save(getcwd() . '/social-images/' . $this->type . '/' . $this->elementId . '.png');
      
    $asset = new Asset();
    $asset->newFolderId = 1;
    $asset->filename = 'test';
    $asset->volumeId = 1;
    $asset->tempFilePath = $image;
    $asset->setScenario(Asset::SCENARIO_CREATE);
  
    $element->setFieldValue('seoImage', $asset);
    Craft::$app->getElements()->saveElement($element);
  
    }
  
    protected function defaultDescription(): ?string
    {
      return Craft::t('app', 'Generating Social Image');
    }
  }
  
  ```
  
  With this I get a `Serialization of 'Closure' is not allowed` error so I'm not sure if I should be trying to update the field as part of the queue job or somewhere else.
  
  Also not sure the asset creation part is right, but I can get to that next.
  
  Appreciate any pointers!
  
  **Tags:** modules, queue
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2023-08-21. Score: 1
  
  The return of `Browsershot::url()` is not the asset path, so you cannot put it like this:
  
  ```
  $asset->tempFilePath = $image;
  
  ```
  
  You can just pass the path where you put on save arguments directly :
  
  ```
  getcwd() . '/social-images/' . $this->type . '/' . $this->elementId . '.png'  
  
  ```
  
  but probably it will cause that file will be deleted, so the better way is to copy your file to craft temp path
  
  ```
  $craftTemp  = Craft::$app->path->getTempAssetUploadsPath(true);
  $path       = $craftTemp .'/' . '/sc-' . $this->elementId;
  copy('getcwd() . '/social-images/' . $this->type . '/' . $this->elementId . '.png', $path);
  
  ```
  
  then you can put it on temp path :
  
  ```
  $asset->tempFilePath = $path;
  
  ```
  
  Another thing is even this work, to save the asset field you need to save the asset first and push the element id as array in setFieldValue().
  
  ```
  class GenerateSocialCard extends BaseJob
  {
    public $element;
    public $type;
    public function execute($queue): void
    {
      $filePath = getcwd() . '/social-images/' . $this->type . '/' . $this->elementId . '.png';
      $image = Browsershot::url(getenv('PRIMARY_SITE_URL') . '/social-images/' . $this->type . '/' . $this->element->id)
        ->windowSize(1200, 675)
        ->waitUntilNetworkIdle()
        ->save(filePath);
      
    $craftTemp  = Craft::$app->path->getTempAssetUploadsPath(true);
    $path       = $craftTemp .'/' . '/sc-' . $this->elementId . 'png';
    copy(filePath, $path)
    $asset = new Asset();
    $asset->newFolderId = 1;
    $asset->filename = $this->elementId . '.png';
    $asset->volumeId = 1;
    $asset->tempFilePath = $path;
    $asset->setScenario(Asset::SCENARIO_CREATE);
    Craft::$app->getElements()->saveElement($asset);
    $element->setFieldValue('seoImage', [$asset->id]);
    Craft::$app->getElements()->saveElement($element);
  
    }
  
    protected function defaultDescription(): ?string
    {
      return Craft::t('app', 'Generating Social Image');
    }
  }
  
  ```
  
  PS: I didn't test the code.
  
  
  ---
  
  