feat: add automated Printify mockup generation & POD sample content
Printify Integration:
- Add Printify API client module with full HTTP wrapper
- Add mockup generator with dynamic "cover" scaling algorithm
- Create Mix task (mix generate_mockups) for automated mockup generation
- Support --cleanup flag to delete products after downloading mockups
- Calculate optimal scale factor based on artwork/placeholder aspect ratios
- Handle landscape artwork on portrait print areas without white space
Sample Content (16 products across 5 POD categories):
- Art Prints: Mountain Sunrise, Ocean Waves, Wildflower Meadow, Geometric Abstract, Botanical Illustration
- Apparel: Forest Silhouette T-Shirt, Forest Light Hoodie
- Tote Bags: Wildflower Meadow, Sunset Gradient
- Homewares: Fern Leaf Mug, Ocean Waves Cushion, Night Sky Blanket
- Stationery: Autumn Leaves Notebook, Monstera Leaf Notebook
- Accessories: Monstera Leaf Phone Case, Blue Waves Laptop Sleeve
Preview Data Updates:
- Replace generic e-commerce products with POD-focused items
- Update categories to POD-relevant: Art Prints, Apparel, Homewares, Stationery, Accessories
- Update cart drawer items to match new product range
- Refresh testimonials with POD-appropriate reviews
Theme Content Updates:
- Update hero section for "Wildprint Studio" brand identity
- Rewrite about page narrative with humble, British, personal tone
- Update search hints to nature/POD relevant terms
- Add mockups directory to static paths
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 23:35:18 +00:00
|
|
|
defmodule Mix.Tasks.GenerateMockups do
|
|
|
|
|
@moduledoc """
|
|
|
|
|
Generates product mockups using the Printify API.
|
|
|
|
|
|
|
|
|
|
This task automates the creation of product mockups for the SimpleshopTheme
|
|
|
|
|
sample content. It downloads artwork from Unsplash, uploads it to Printify,
|
|
|
|
|
creates products, and downloads the generated mockups.
|
|
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
|
|
|
- A Printify account with API access
|
|
|
|
|
- The PRINTIFY_API_TOKEN environment variable must be set
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
# Generate mockups (keeps products in Printify)
|
|
|
|
|
mix generate_mockups
|
|
|
|
|
|
|
|
|
|
# Generate mockups and delete products afterwards
|
|
|
|
|
mix generate_mockups --cleanup
|
|
|
|
|
|
|
|
|
|
# Search for available blueprints
|
|
|
|
|
mix generate_mockups --search "poster"
|
|
|
|
|
|
|
|
|
|
# List all blueprints
|
|
|
|
|
mix generate_mockups --list-blueprints
|
|
|
|
|
|
|
|
|
|
## Output
|
|
|
|
|
|
|
|
|
|
Mockup images are saved to: priv/static/mockups/
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
use Mix.Task
|
|
|
|
|
|
2026-01-29 08:32:24 +00:00
|
|
|
alias SimpleshopTheme.Mockups.Generator, as: MockupGenerator
|
feat: add automated Printify mockup generation & POD sample content
Printify Integration:
- Add Printify API client module with full HTTP wrapper
- Add mockup generator with dynamic "cover" scaling algorithm
- Create Mix task (mix generate_mockups) for automated mockup generation
- Support --cleanup flag to delete products after downloading mockups
- Calculate optimal scale factor based on artwork/placeholder aspect ratios
- Handle landscape artwork on portrait print areas without white space
Sample Content (16 products across 5 POD categories):
- Art Prints: Mountain Sunrise, Ocean Waves, Wildflower Meadow, Geometric Abstract, Botanical Illustration
- Apparel: Forest Silhouette T-Shirt, Forest Light Hoodie
- Tote Bags: Wildflower Meadow, Sunset Gradient
- Homewares: Fern Leaf Mug, Ocean Waves Cushion, Night Sky Blanket
- Stationery: Autumn Leaves Notebook, Monstera Leaf Notebook
- Accessories: Monstera Leaf Phone Case, Blue Waves Laptop Sleeve
Preview Data Updates:
- Replace generic e-commerce products with POD-focused items
- Update categories to POD-relevant: Art Prints, Apparel, Homewares, Stationery, Accessories
- Update cart drawer items to match new product range
- Refresh testimonials with POD-appropriate reviews
Theme Content Updates:
- Update hero section for "Wildprint Studio" brand identity
- Rewrite about page narrative with humble, British, personal tone
- Update search hints to nature/POD relevant terms
- Add mockups directory to static paths
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 23:35:18 +00:00
|
|
|
|
|
|
|
|
@shortdoc "Generates product mockups using Printify API"
|
|
|
|
|
|
|
|
|
|
@impl Mix.Task
|
|
|
|
|
def run(args) do
|
|
|
|
|
# Start required applications
|
|
|
|
|
Mix.Task.run("app.start")
|
|
|
|
|
|
|
|
|
|
{opts, _, _} =
|
|
|
|
|
OptionParser.parse(args,
|
|
|
|
|
switches: [
|
|
|
|
|
cleanup: :boolean,
|
|
|
|
|
search: :string,
|
|
|
|
|
list_blueprints: :boolean,
|
|
|
|
|
help: :boolean
|
|
|
|
|
],
|
|
|
|
|
aliases: [
|
|
|
|
|
c: :cleanup,
|
|
|
|
|
s: :search,
|
|
|
|
|
l: :list_blueprints,
|
|
|
|
|
h: :help
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
cond do
|
|
|
|
|
opts[:help] ->
|
|
|
|
|
print_help()
|
|
|
|
|
|
|
|
|
|
opts[:list_blueprints] ->
|
|
|
|
|
list_blueprints()
|
|
|
|
|
|
|
|
|
|
opts[:search] ->
|
|
|
|
|
search_blueprints(opts[:search])
|
|
|
|
|
|
|
|
|
|
true ->
|
|
|
|
|
generate_mockups(opts)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp print_help do
|
|
|
|
|
Mix.shell().info("""
|
|
|
|
|
|
|
|
|
|
Printify Mockup Generator
|
|
|
|
|
=========================
|
|
|
|
|
|
|
|
|
|
Generates product mockups using the Printify API.
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
mix generate_mockups [options]
|
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
--cleanup, -c Delete created products from Printify after downloading mockups
|
|
|
|
|
--search, -s TERM Search for blueprints by name
|
|
|
|
|
--list-blueprints List all available blueprint IDs and names
|
|
|
|
|
--help, -h Show this help message
|
|
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
|
PRINTIFY_API_TOKEN Required. Your Printify API token.
|
|
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
# Generate all mockups
|
|
|
|
|
export PRINTIFY_API_TOKEN="your-token"
|
|
|
|
|
mix generate_mockups
|
|
|
|
|
|
|
|
|
|
# Generate and cleanup
|
|
|
|
|
mix generate_mockups --cleanup
|
|
|
|
|
|
|
|
|
|
# Find blueprint IDs
|
|
|
|
|
mix generate_mockups --search "poster"
|
|
|
|
|
""")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp list_blueprints do
|
|
|
|
|
Mix.shell().info("Fetching blueprints from Printify...")
|
|
|
|
|
|
|
|
|
|
case MockupGenerator.list_blueprints() do
|
|
|
|
|
blueprints when is_list(blueprints) ->
|
|
|
|
|
Mix.shell().info("\nAvailable Blueprints:\n")
|
|
|
|
|
|
|
|
|
|
blueprints
|
|
|
|
|
|> Enum.each(fn {id, title} ->
|
|
|
|
|
Mix.shell().info(" #{id}: #{title}")
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
Mix.shell().info("\nTotal: #{length(blueprints)} blueprints")
|
|
|
|
|
|
|
|
|
|
{:error, reason} ->
|
|
|
|
|
Mix.shell().error("Error fetching blueprints: #{inspect(reason)}")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp search_blueprints(term) do
|
|
|
|
|
Mix.shell().info("Searching for blueprints matching '#{term}'...")
|
|
|
|
|
|
|
|
|
|
case MockupGenerator.search_blueprints(term) do
|
|
|
|
|
results when is_list(results) ->
|
|
|
|
|
if length(results) == 0 do
|
|
|
|
|
Mix.shell().info("No blueprints found matching '#{term}'")
|
|
|
|
|
else
|
|
|
|
|
Mix.shell().info("\nMatching Blueprints:\n")
|
|
|
|
|
|
|
|
|
|
results
|
|
|
|
|
|> Enum.each(fn {id, title} ->
|
|
|
|
|
Mix.shell().info(" #{id}: #{title}")
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
Mix.shell().info("\nFound: #{length(results)} blueprints")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
{:error, reason} ->
|
|
|
|
|
Mix.shell().error("Error searching blueprints: #{inspect(reason)}")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_mockups(opts) do
|
|
|
|
|
cleanup = Keyword.get(opts, :cleanup, false)
|
|
|
|
|
|
|
|
|
|
Mix.shell().info("""
|
|
|
|
|
|
|
|
|
|
╔═══════════════════════════════════════════╗
|
|
|
|
|
║ Printify Mockup Generator ║
|
|
|
|
|
╠═══════════════════════════════════════════╣
|
|
|
|
|
║ Cleanup mode: #{if cleanup, do: "ON ", else: "OFF"} ║
|
|
|
|
|
╚═══════════════════════════════════════════╝
|
|
|
|
|
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
# Verify API token is set
|
|
|
|
|
case System.get_env("PRINTIFY_API_TOKEN") do
|
|
|
|
|
nil ->
|
|
|
|
|
Mix.shell().error("""
|
|
|
|
|
Error: PRINTIFY_API_TOKEN environment variable is not set.
|
|
|
|
|
|
|
|
|
|
To get your API token:
|
|
|
|
|
1. Log in to Printify
|
|
|
|
|
2. Go to Settings > API tokens
|
|
|
|
|
3. Create a new token with required permissions
|
|
|
|
|
|
|
|
|
|
Then run:
|
|
|
|
|
export PRINTIFY_API_TOKEN="your-token"
|
|
|
|
|
mix generate_mockups
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
_token ->
|
|
|
|
|
results = MockupGenerator.generate_all(cleanup: cleanup)
|
|
|
|
|
|
|
|
|
|
# Summary
|
|
|
|
|
successful = Enum.count(results, &match?({:ok, _, _, _}, &1))
|
|
|
|
|
failed = Enum.count(results, &match?({:error, _, _}, &1))
|
|
|
|
|
|
|
|
|
|
Mix.shell().info("""
|
|
|
|
|
|
|
|
|
|
═══════════════════════════════════════════
|
|
|
|
|
Summary
|
|
|
|
|
═══════════════════════════════════════════
|
|
|
|
|
Successful: #{successful}
|
|
|
|
|
Failed: #{failed}
|
|
|
|
|
═══════════════════════════════════════════
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
if failed > 0 do
|
|
|
|
|
Mix.shell().error("Some products failed to generate. Check the output above for details.")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|