|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Production blog deploy — run on server as root: |
| 3 | +# WP_ROOT=/var/www/html/blog bash deploy-blog-share-stories-inline.sh |
| 4 | + |
| 5 | +set -euo pipefail |
| 6 | + |
| 7 | +WP_ROOT="${WP_ROOT:-/var/www/html/blog}" |
| 8 | +THEME="${THEME:-$WP_ROOT/wp-content/themes/eucodewe-1389}" |
| 9 | + |
| 10 | +if [[ ! -d "$THEME" ]]; then |
| 11 | + THEME=$(find /var/www -maxdepth 8 -type d -name 'eucodewe-1389' 2>/dev/null | head -1 || true) |
| 12 | + if [[ -n "${THEME:-}" ]]; then |
| 13 | + WP_ROOT="$(dirname "$(dirname "$(dirname "$THEME")")")" |
| 14 | + fi |
| 15 | +fi |
| 16 | + |
| 17 | +SHARE_URL="https://forms.office.com/Pages/ResponsePage.aspx?id=18F13DIal06vkB3AGRHqbCnyIKB_vXdLsUgagfjd7DRUN1dZTVYxSkJNQ1VWSlVZNlpBOFAyN0g4UC4u&embed=true" |
| 18 | +SHARE_TEXT="Share your stories" |
| 19 | +HERO_DESCRIPTION="Have a story, activity, or inspiring EU Code Week experience to share? We'd love to hear from you! Submit your experiences, highlights, and initiatives through the form and help us showcase the amazing work happening across the EU Code Week community." |
| 20 | + |
| 21 | +[[ -d "$THEME" ]] || { echo "Theme eucodewe-1389 not found under /var/www"; find /var/www -maxdepth 6 -name wp-config.php 2>/dev/null; exit 1; } |
| 22 | +echo "Using WP_ROOT=$WP_ROOT" |
| 23 | +cd "$THEME" |
| 24 | +echo "Using THEME=$THEME" |
| 25 | + |
| 26 | +chmod u+w new.css front-page.php functions.php acf-json/group_5efc9e8719cc2.json 2>/dev/null || true |
| 27 | +cp -a new.css "new.css.bak.$(date +%Y%m%d%H%M%S)" |
| 28 | +cp -a front-page.php "front-page.php.bak.$(date +%Y%m%d%H%M%S)" |
| 29 | + |
| 30 | +# --- 1) Enlarge hero so description + CTA fit comfortably --- |
| 31 | +python3 <<'PY' |
| 32 | +from pathlib import Path |
| 33 | +import re |
| 34 | +
|
| 35 | +css = Path("new.css") |
| 36 | +text = css.read_text() |
| 37 | +
|
| 38 | +# Desktop hero section |
| 39 | +text = re.sub( |
| 40 | + r"(\.hero-section\s*\{[^}]*?)min-height:\s*\d+px;", |
| 41 | + r"\1min-height: 580px;", |
| 42 | + text, |
| 43 | + count=1, |
| 44 | + flags=re.S, |
| 45 | +) |
| 46 | +text = re.sub( |
| 47 | + r"(\.hero-section\s*\{[^}]*?)height:\s*250px;", |
| 48 | + r"\1min-height: 580px;\n height: auto;", |
| 49 | + text, |
| 50 | + count=1, |
| 51 | + flags=re.S, |
| 52 | +) |
| 53 | +text = re.sub( |
| 54 | + r"(\.hero-section\s*\{[^}]*?)padding:\s*[^;]+;", |
| 55 | + r"\1padding: 3rem 0;", |
| 56 | + text, |
| 57 | + count=1, |
| 58 | + flags=re.S, |
| 59 | +) |
| 60 | +
|
| 61 | +# Hero white card — more room for description + button |
| 62 | +text = re.sub( |
| 63 | + r"(\.hero-content\s*\{[^}]*?)padding:\s*2rem;", |
| 64 | + r"\1padding: 2.5rem 3rem 3rem;", |
| 65 | + text, |
| 66 | + count=1, |
| 67 | + flags=re.S, |
| 68 | +) |
| 69 | +
|
| 70 | +if ".hero-description {" in text and "margin-bottom:" not in text.split(".hero-description {", 1)[1].split("}", 1)[0]: |
| 71 | + text = text.replace( |
| 72 | + ".hero-description {\n color: var(--Slate-500, #333E48);", |
| 73 | + ".hero-description {\n margin-bottom: 1.25rem;\n color: var(--Slate-500, #333E48);", |
| 74 | + 1, |
| 75 | + ) |
| 76 | +
|
| 77 | +# Tablet breakpoint |
| 78 | +text = re.sub( |
| 79 | + r"(\t\.hero-section\s*\{[^}]*?)min-height:\s*\d+px;", |
| 80 | + r"\1min-height: 520px;", |
| 81 | + text, |
| 82 | + count=1, |
| 83 | + flags=re.S, |
| 84 | +) |
| 85 | +text = re.sub( |
| 86 | + r"(\t\.hero-section\s*\{[^}]*?)height:\s*330px;", |
| 87 | + r"\1min-height: 520px;\n\t\theight: auto;", |
| 88 | + text, |
| 89 | + count=1, |
| 90 | + flags=re.S, |
| 91 | +) |
| 92 | +
|
| 93 | +# Mobile breakpoint — stack layout |
| 94 | +text = re.sub( |
| 95 | + r"(\t\.hero-section\s*\{\n flex-direction: column-reverse;[^}]*?)padding:\s*[^;]+;", |
| 96 | + r"\1padding: 0 0 3rem;\n min-height: 520px;", |
| 97 | + text, |
| 98 | + count=1, |
| 99 | + flags=re.S, |
| 100 | +) |
| 101 | +
|
| 102 | +if ".hero-button {" in text and "margin-top:" not in text.split(".hero-button {", 1)[1].split("}", 1)[0]: |
| 103 | + text = text.replace( |
| 104 | + ".hero-button {\n background-color: #F95C22;", |
| 105 | + ".hero-button {\n display: inline-block;\n margin-top: 1.5rem;\n background-color: #F95C22;", |
| 106 | + 1, |
| 107 | + ) |
| 108 | +elif ".hero-button {" in text: |
| 109 | + text = re.sub( |
| 110 | + r"(\.hero-button\s*\{[^}]*?)margin-top:\s*[^;]+;", |
| 111 | + r"\1margin-top: 1.5rem;", |
| 112 | + text, |
| 113 | + count=1, |
| 114 | + flags=re.S, |
| 115 | + ) |
| 116 | +
|
| 117 | +css.write_text(text) |
| 118 | +print("Updated new.css hero sizing (580px desktop)") |
| 119 | +PY |
| 120 | + |
| 121 | +# --- 2) ACF JSON: add cta_button to hero_section --- |
| 122 | +python3 <<'PY' |
| 123 | +import json |
| 124 | +from pathlib import Path |
| 125 | +path = Path("acf-json/group_5efc9e8719cc2.json") |
| 126 | +data = json.loads(path.read_text()) |
| 127 | +for field in data.get("fields", []): |
| 128 | + if field.get("name") != "hero_section": |
| 129 | + continue |
| 130 | + subs = field.setdefault("sub_fields", []) |
| 131 | + if any(s.get("name") == "cta_button" for s in subs): |
| 132 | + print("ACF JSON already has cta_button") |
| 133 | + break |
| 134 | + subs.append({ |
| 135 | + "key": "field_codeweek_hero_cta_button", |
| 136 | + "label": "Button", |
| 137 | + "name": "cta_button", |
| 138 | + "type": "link", |
| 139 | + "instructions": "", |
| 140 | + "required": 0, |
| 141 | + "conditional_logic": 0, |
| 142 | + "wrapper": {"width": "", "class": "", "id": ""}, |
| 143 | + "return_format": "array", |
| 144 | + }) |
| 145 | + path.write_text(json.dumps(data, indent=4) + "\n") |
| 146 | + print("Added cta_button to ACF JSON") |
| 147 | + break |
| 148 | +else: |
| 149 | + raise SystemExit("hero_section not found in ACF JSON") |
| 150 | +PY |
| 151 | + |
| 152 | +# --- 3) front-page.php: render hero CTA (mirror info section button) --- |
| 153 | +python3 <<'PY' |
| 154 | +import re |
| 155 | +from pathlib import Path |
| 156 | +path = Path("front-page.php") |
| 157 | +content = path.read_text() |
| 158 | +snippet = """ |
| 159 | + <?php if (! empty($hero['cta_button'])) : $cta = $hero['cta_button']; ?> |
| 160 | + <a href="<?php echo esc_url($cta['url']); ?>" class="hero-button" target="<?php echo esc_attr($cta['target'] ?: '_self'); ?>" rel="noopener noreferrer"><?php echo esc_html($cta['title']); ?></a> |
| 161 | + <?php endif; ?>""" |
| 162 | +
|
| 163 | +if "cta_button" in content: |
| 164 | + print("front-page.php already references cta_button") |
| 165 | +else: |
| 166 | + match = re.search(r'(<p[^>]*class="hero-description"[^>]*>.*?</p>)', content, re.S) |
| 167 | + if not match: |
| 168 | + raise SystemExit("Could not find hero-description in front-page.php") |
| 169 | + content = content[: match.end()] + snippet + content[match.end() :] |
| 170 | + path.write_text(content) |
| 171 | + print("Patched front-page.php") |
| 172 | +PY |
| 173 | + |
| 174 | +# --- 4) WP-CLI: defaults + menu --- |
| 175 | +if command -v wp >/dev/null 2>&1; then |
| 176 | + cd "$WP_ROOT" |
| 177 | + wp acf sync --allow-root 2>/dev/null || true |
| 178 | + |
| 179 | + HERO_DESC_JSON=$(HERO_DESCRIPTION="$HERO_DESCRIPTION" python3 -c 'import json,os; print(json.dumps(os.environ["HERO_DESCRIPTION"]))') |
| 180 | + wp eval --allow-root " |
| 181 | + \$hero = get_field('hero_section', 2) ?: []; |
| 182 | + \$hero['description'] = ${HERO_DESC_JSON}; |
| 183 | + \$hero['cta_button'] = ['title' => '$SHARE_TEXT', 'url' => '$SHARE_URL', 'target' => '_blank']; |
| 184 | + update_field('hero_section', \$hero, 2); |
| 185 | + " 2>/dev/null || true |
| 186 | + |
| 187 | + ARROW_HTML='<img src="https://codeweek.eu/blog/wp-content/uploads/2025/02/arrow.png" alt="arrow right" />' |
| 188 | + SHARE_ID="" |
| 189 | + for menu in primary header main "Menu 1" 2; do |
| 190 | + SHARE_ID=$(wp menu item list "$menu" --fields=db_id,title --format=csv --allow-root 2>/dev/null \ |
| 191 | + | awk -F, -v t="$SHARE_TEXT" '$2 ~ t {print $1; exit}') || true |
| 192 | + if [[ -n "${SHARE_ID:-}" ]]; then |
| 193 | + echo "Share your stories already in $menu (ID $SHARE_ID)" |
| 194 | + break |
| 195 | + fi |
| 196 | + BLOG_PARENT=$(wp menu item list "$menu" --fields=db_id,title --format=csv --allow-root 2>/dev/null | awk -F, '$2 ~ /Blog/ {print $1; exit}') |
| 197 | + if [[ -n "${BLOG_PARENT:-}" ]]; then |
| 198 | + SHARE_ID=$(wp menu item add-custom "$menu" "$SHARE_TEXT" "$SHARE_URL" --parent-id="$BLOG_PARENT" --porcelain --allow-root 2>/dev/null || true) |
| 199 | + [[ -n "${SHARE_ID:-}" ]] && echo "Added menu item to $menu (ID $SHARE_ID)" && break |
| 200 | + fi |
| 201 | + done |
| 202 | + |
| 203 | + if [[ -n "${SHARE_ID:-}" ]]; then |
| 204 | + wp eval --allow-root " |
| 205 | + \$id = (int) ${SHARE_ID}; |
| 206 | + update_post_meta(\$id, '_menu_item_url', '${SHARE_URL}'); |
| 207 | + update_post_meta(\$id, 'rt-wp-menu-custom-fields', [ |
| 208 | + 'selected-feature' => 'html', |
| 209 | + 'html' => ['custom-html' => '${ARROW_HTML}'], |
| 210 | + ]); |
| 211 | + delete_transient('rt-wp-menu-custom-fields-' . \$id); |
| 212 | + echo \"Menu item \$id: URL + arrow icon meta set\n\"; |
| 213 | + " 2>/dev/null || true |
| 214 | + fi |
| 215 | + |
| 216 | + wp cache flush --allow-root 2>/dev/null || true |
| 217 | + echo "WP-CLI done" |
| 218 | +fi |
| 219 | + |
| 220 | +echo "Done. Verify https://codeweek.eu/blog/" |
0 commit comments