Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 247 additions & 4 deletions mage
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ function mage_help() {
mage_help_cmd "add hyva" "Add Hyva Theme"
mage_help_cmd "add checkout" "Add Hyva Checkout"
mage_help_cmd "add baldr" "Add Siteation Baldr"
mage_help_cmd "add store" "Create a new store view (interactive)"
mage_help_cmd "add stores" "Create all stores from dev/tools/stores.json"
mage_help_cmd "add [PKG]" "Add composer package"
mage_help_cmd "upd/update [PKG]" "Update composer package(s)"
mage_help_cmd "del/remove [PKG]" "Remove composer package(s)"
Expand Down Expand Up @@ -557,6 +559,206 @@ function convert_to_mage_os() {
$MAGENTO_CLI s:up
}

# ---------------------------------------------------------------------------
# Multistore helpers
# ---------------------------------------------------------------------------

# Append a store entry to .valet-env.php (preserving all existing entries)
function mage_valet_env_add_entry() {
local domain="$1"
local code="$2"

python3 - "$domain" "$code" <<'PYEOF'
import sys, re

domain, code = sys.argv[1], sys.argv[2]
entry = (
f"\t'{domain}' => [\n"
f"\t\t'MAGE_RUN_CODE' => '{code}',\n"
f"\t\t'MAGE_RUN_TYPE' => 'store',\n"
f"\t],\n"
)

with open('.valet-env.php', 'r') as f:
content = f.read()

# Skip if domain already present
if f"'{domain}'" in content:
print(f".valet-env.php already contains '{domain}', skipping.")
sys.exit(0)

# Insert before the closing ];
content = re.sub(r'^(\];)', entry + r'\1', content, flags=re.MULTILINE)

with open('.valet-env.php', 'w') as f:
f.write(content)

print(f"Updated .valet-env.php: added '{domain}' → '{code}'")
PYEOF
}

# Add a single store view (interactive)
function mage_add_store() {
echo ""
read -e -p "Store code (e.g. nl_nl): " store_code && echo ""
read -e -p "Store name (e.g. Dutch Store): " store_name && echo ""
read -e -p "Domain name (e.g. myproject-nl, without .test): " store_domain && echo ""
read -e -p "Locale code (e.g. nl_NL, leave empty to skip): " store_locale && echo ""

if [[ -z "$store_code" || -z "$store_name" || -z "$store_domain" ]]; then
echo "Error: store code, name and domain are required."
return 1
fi

# Auto-lowercase the store code
store_code=$(echo "$store_code" | tr '[:upper:]' '[:lower:]')

if [[ ! "$store_code" =~ ^[a-z][a-z0-9_]*$ ]]; then
echo "Error: store code must be letters, digits and underscores, starting with a letter (got: ${store_code})."
return 1
fi

echo "Creating store group and store view in Magento..."
local php_args="--code=${store_code} --name=${store_name}"
if [[ -n "$store_locale" ]]; then
php_args="${php_args} --locale=${store_locale}"
fi

if ! $PHP_CLI dev/tools/create-store.php $php_args; then
echo "Error: failed to create store entities."
return 1
fi

echo "Setting base URLs..."
$MAGENTO_CLI config:set --scope=stores --scope-code="$store_code" web/unsecure/base_url "https://${store_domain}.test/"
$MAGENTO_CLI config:set --scope=stores --scope-code="$store_code" web/secure/base_url "https://${store_domain}.test/"
$MAGENTO_CLI config:set --scope=stores --scope-code="$store_code" web/secure/use_in_frontend 1

echo "Flushing cache..."
$MAGENTO_CLI cache:flush

echo "Updating .valet-env.php..."
mage_valet_env_add_entry "$store_domain" "$store_code"

echo ""
echo "Store '${store_code}' created."

if [[ $VALET == 1 ]]; then
echo ""
echo "Linking and securing Valet domain..."
valet link "${store_domain}"
valet secure "${store_domain}"
fi
echo ""
}

# Add all stores defined in dev/tools/stores.json (batch, non-interactive)
# Schema: { "stores": [ { "code": "nl_nl", "name": "Dutch", "suffix": "nl", "locale": "nl_NL" } ] }
# The domain is computed as <project-name>-<suffix> so stores.json stays project-agnostic.
function mage_add_stores_from_file() {
local stores_file="${1:-}"

# Resolve file: dev/tools/ → project root → mage bin dir
if [[ -z "$stores_file" ]]; then
if [[ -f "dev/tools/stores.json" ]]; then
stores_file="dev/tools/stores.json"
elif [[ -f "stores.json" ]]; then
stores_file="stores.json"
elif [[ -f "$(dirname "$0")/stores.json" ]]; then
stores_file="$(dirname "$0")/stores.json"
fi
fi

if [[ -z "$stores_file" || ! -f "$stores_file" ]]; then
echo "No stores.json found (checked dev/tools/, project root, and mage bin dir)."
return 0
fi

echo "Reading stores from ${stores_file}..."

local project_name
project_name=$(basename "$(pwd)")

# Parse JSON with Python 3 — output one line per store: code|name|suffix|locale
local stores_data
stores_data=$(python3 - "$stores_file" <<'PYEOF'
import json, sys
path = sys.argv[1]
data = json.load(open(path))
stores = data.get("stores", [])
if not stores:
print("__empty__")
sys.exit(0)
for s in stores:
code = s.get("code", "")
name = s.get("name", "")
suffix = s.get("suffix", "")
locale = s.get("locale", "")
if not code or not name or not suffix:
print(f"__skip__: missing field in entry: {s}", file=__import__('sys').stderr)
continue
print(f"{code}|{name}|{suffix}|{locale}")
PYEOF
)

if [[ "$stores_data" == "__empty__" ]]; then
echo "No stores defined in ${stores_file}."
return 0
fi

local created=0
local new_domains=()
while IFS='|' read -r s_code s_name s_suffix s_locale; do
[[ -z "$s_code" ]] && continue

local s_domain="${project_name}-${s_suffix}"

echo ""
echo "→ Creating store: ${s_code} (${s_name}) at ${s_domain}.test"

local php_args="--code=${s_code} --name=${s_name}"
if [[ -n "$s_locale" ]]; then
php_args="${php_args} --locale=${s_locale}"
fi

if ! $PHP_CLI dev/tools/create-store.php $php_args; then
echo " Skipping ${s_code} due to error."
continue
fi

$MAGENTO_CLI config:set --scope=stores --scope-code="$s_code" web/unsecure/base_url "https://${s_domain}.test/"
$MAGENTO_CLI config:set --scope=stores --scope-code="$s_code" web/secure/base_url "https://${s_domain}.test/"
$MAGENTO_CLI config:set --scope=stores --scope-code="$s_code" web/secure/use_in_frontend 1

mage_valet_env_add_entry "$s_domain" "$s_code"

new_domains+=("$s_domain")
(( created++ ))
done <<< "$stores_data"

if [[ "$created" -gt 0 ]]; then
echo ""
echo "Flushing cache..."
$MAGENTO_CLI cache:flush

if [[ $VALET == 1 && ${#new_domains[@]} -gt 0 ]]; then
echo ""
echo "Linking Valet domains..."
for d in "${new_domains[@]}"; do
valet link "$d"
done
echo ""
echo "Securing Valet domains..."
for d in "${new_domains[@]}"; do
valet secure "$d"
done
fi

echo ""
echo "${created} store(s) created."
fi
}

function mage_new_in_folder() {
if [[ ! -d package-source ]]; then
mkdir package-source
Expand Down Expand Up @@ -871,9 +1073,6 @@ function mage_add_sample() {
touch README.md
php -f $HOME/.magento-sampledata/$mversion/dev/tools/build-sample-data.php -- --ce-source="$PWD"

# Unset default styles from sample data
$MAGENTO_CLI config:set design/head/includes "" &> /dev/null

$MAGENTO_CLI setup:upgrade

# Set theme to Hyva if present
Expand All @@ -883,6 +1082,9 @@ function mage_add_sample() {
fi
fi

# Unset default styles from sample data
$MAGENTO_CLI config:set design/head/includes "" &> /dev/null

$MAGENTO_CLI indexer:reindex
$MAGENTO_CLI cache:flush
}
Expand Down Expand Up @@ -1010,11 +1212,44 @@ function mage_setup() {
{
echo -e '<?php declare(strict_types=1);\n\nreturn ['
mage_add_valet_store "$name" "default"
mage_add_valet_store "store-2" "default2" true
echo '];'
} > .valet-env.php
fi

# Scaffold dev/tools/ with multistore helpers from mage bin dir
local _bin_dir
_bin_dir="$(dirname "$0")"
if [[ -f "${_bin_dir}/create-store.php" ]]; then
mkdir -p dev/tools
cp "${_bin_dir}/create-store.php" dev/tools/create-store.php
fi
if [[ ! -f "dev/tools/stores.json" ]] && [[ -f "${_bin_dir}/stores.json" ]]; then
mkdir -p dev/tools
cp "${_bin_dir}/stores.json" dev/tools/stores.json
fi

# Create extra stores from stores.json (if present and non-empty)
if [[ $VALET == 1 ]]; then
_stores_file=""
if [[ -f "dev/tools/stores.json" ]]; then
_stores_file="dev/tools/stores.json"
elif [[ -f "stores.json" ]]; then
_stores_file="stores.json"
elif [[ -f "$(dirname "$0")/stores.json" ]]; then
_stores_file="$(dirname "$0")/stores.json"
fi

if [[ -n "$_stores_file" ]]; then
_count=$(python3 -c "import json; d=json.load(open('${_stores_file}')); print(len(d.get('stores',[])))" 2>/dev/null || echo 0)
if [[ "$_count" -gt 0 ]]; then
read -p "Create ${_count} store(s) from ${_stores_file}? [Y/n] " _ADD && echo ""
if [[ ! $_ADD =~ ^[nN] ]]; then
mage_add_stores_from_file "$_stores_file"
fi
fi
fi
fi

# Cleanup root sample files
mage_cleanup_sample_files
}
Expand Down Expand Up @@ -1245,6 +1480,14 @@ case "${@}" in
$COMPOSER_CLI require siteation/magento2-theme-baldr
;;

"add store")
mage_add_store
;;

"add stores")
mage_add_stores_from_file
;;

"add "*)
$COMPOSER_CLI require "${@:2}"
;;
Expand Down
2 changes: 2 additions & 0 deletions src/_info.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ function mage_help() {
mage_help_cmd "add hyva" "Add Hyva Theme"
mage_help_cmd "add checkout" "Add Hyva Checkout"
mage_help_cmd "add baldr" "Add Siteation Baldr"
mage_help_cmd "add store" "Create a new store view (interactive)"
mage_help_cmd "add stores" "Create all stores from dev/tools/stores.json"
mage_help_cmd "add [PKG]" "Add composer package"
mage_help_cmd "upd/update [PKG]" "Update composer package(s)"
mage_help_cmd "del/remove [PKG]" "Remove composer package(s)"
Expand Down
8 changes: 8 additions & 0 deletions src/_mage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ case "${@}" in
$COMPOSER_CLI require siteation/magento2-theme-baldr
;;

"add store")
mage_add_store
;;

"add stores")
mage_add_stores_from_file
;;

"add "*)
$COMPOSER_CLI require "${@:2}"
;;
Expand Down
Loading