Get default theme manifest contents Sage 10

Hi there,

I’m stuck with a particular issue, and I can’t seem to find the right Acorn class/function to resolve this;

I have a few multi-color svg images that I copy to the public folder with webpack mix:

mix
	.copyDirectory('resources/images', 'public/images')
	.copyDirectory('resources/fonts', 'public/fonts')
	.copyDirectory('resources/icons/duotone/svg', 'public/icons/duotone');

They end up correctly in the public folder: /public/icons/duotone/ and in the mix-manifest.json:

{
    "/icons/duotone/battery.svg": "/icons/duotone/battery.svg?id=a08ad5be4ab4157914e7",
    "/icons/duotone/chain-drive.svg": "/icons/duotone/chain-drive.svg?id=c637f8686ca158e457db",
    "/icons/duotone/lcd-display.svg": "/icons/duotone/lcd-display.svg?id=35ca930969e7447cefa1"
}

I want to use these svg’s to pre-populate an ACF select field with acf-composer:

namespace App\Fields\Partials;
use Log1x\AcfComposer\Partial;
use StoutLogic\AcfBuilder\FieldsBuilder;
use function Roots\asset;

class SelectDuoIcons extends Partial
{
	/**
	 * The icons choices
	 *
	 * @return array
	 */
	public function loadIcons() {
		$choices = [];
		// $manifest   = manifest(); ?

		return $choices;
	}

	/**
	 * The partial field group.
	 *
	 * @return array
	 */
	public function fields() {
		$partial = new FieldsBuilder('icons');
		$partial
			->addSelect('icon', [
				'label'        => 'Select Duotone Icon',
				'instructions' => 'Select an Duotone icon',
				'allow_null'   => 1
			])
				->addChoices($this->loadIcons());

		return $partial;
	}
}

I know how to get a specific asset from the manifest, but I don’t know the filename upfront, so I want to get ALL the icons from the folder /public/icons/duotone/ in the manifest.

So somehow I need to get the JSON content of the manifest itself and filter the keys, but what function would I need to use for that? I can’t seem to find it…

Thanks!

Here’s a stepping stone to solving your problem, perhaps.

Sage Docs: Theme Assets suggests you might try something like:

$asset = \Roots\asset('mix-manifest.json');        
        // The public URI of the asset
        echo $asset;
        echo $asset->uri();

I think there’s a better way, but I don’t know enough about Root’s guts to tell you what that is, exactly . Looking at the code for Roots\helpers.php, it would appear that it might be possible to directly query a manifest asset. See Manifest.php and JsonAsset.php too.

I’m not sure how to put this together towards what you’re trying to accomplish, but hopefully this can help you along the way.

Update:
This should get you halfway towards what you want. Not sure if it is the best way or if there is a better way, though.

        $manifest = \Roots\asset('mix-manifest.json', true);                
        $json_asset = new \Roots\Acorn\Assets\Asset\JsonAsset($manifest->path(), $manifest->uri());
        echo $json_asset->contents();
1 Like

I may be missing something but what about scanning the source directory to get the image names since I guess those are the ones you want as values for the choices anyways?

Philosophically I would be opposed to this: Asset source files should be considered to not exist in a production environment. While there may not be anything technically preventing you from doing this, you can easily put yourself in a confusing situation where it becomes unclear what assets are being used where.

Note that Asset source files is a distinct concept from assets in general. You might have “asset-type content” (i.e. SVGs) that don’t need to pass through your build process (i.e. they are pre-optimized and need no additional optimization; they aren’t used in your CSS/JS; etc) and as such aren’t really source files (in this context). In that case I would store in a different location in my filesystem, depending on what I intended to do with them. In this case, your suggestion (iterate over the filesystem) would work great.

Unless I’m misunderstanding you, I believe you could do something like this (completely untested):

$manifest = json_decode( file_get_contents( config( 'assets.manifests.theme.assets' ) ) );
$icons = array_filter( $manifest, function( $item ) {
  return 0 === strpos( '/icons/duotone', $item );
} );

See:

2 Likes

Thanks @roygbyte!
I never really thought about using the asset manager itself to get the asset that holds the other assets :slight_smile:

Thanks @alwaysblank, I think I’ll go for this approach:
config( 'assets.manifests.theme.assets' )

You got it almost in 1 go :slight_smile:
My final implementation:

public function loadIcons() {
	$choices  = [];
	$assets   = config('assets.manifests.theme.assets');
	$manifest = $assets ? json_decode(file_get_contents($assets), TRUE) : null;

	if (!$manifest) {
		return $choices;
	}

	// Filter assets
	$icons = array_filter($manifest, function($key) {
		return strpos($key, '/icons/duotone') === 0;
	}, ARRAY_FILTER_USE_KEY);

	if (!$icons) {
		return $choices;
	}

	// Get icon assets
	foreach ($icons as $key => $icon) {
		$svg   = asset($key)->contents();
		$parts = pathinfo($key);
		$name  = $parts['filename'] ?: $key;

		if ($svg) {
			$choices[] = [
				$name => '<span class="svg-icon">'. $svg .'</span>'. $name
			];
		}
	}

	return $choices;
}

Thanks for your help!