<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>

CC BY-SA 4.0
2023-08-21T03:02:07.637Z
2023-08-21T03:02:07.637Z
aodihis
<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>

<modules><queue>
Add to an asset field from a queue job
# 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.


---

