diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b72aefee7..ea928b36b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -79,9 +79,11 @@ jobs:
working-directory: dev/docker
- name: Setup node
- uses: actions/setup-node@v1
+ id: nvm
+ run: echo ::set-output name=NODE_VERSION::$(cat .nvmrc)
+ - uses: actions/setup-node@v2
with:
- node-version: '14.15.1'
+ node-version: ${{ steps.nvm.outputs.NODE_VERSION }}
- name: Install gulp-cli
run: npm install gulp-cli -g
diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml
index 138ac4c48..1c05df238 100644
--- a/.github/workflows/deploy-dev.yml
+++ b/.github/workflows/deploy-dev.yml
@@ -45,9 +45,11 @@ jobs:
# Setup node version
- name: Setup node version
- uses: actions/setup-node@v1
+ id: nvm
+ run: echo ::set-output name=NODE_VERSION::$(cat .nvmrc)
+ - uses: actions/setup-node@v2
with:
- node-version: '14.15.1'
+ node-version: ${{ steps.nvm.outputs.NODE_VERSION }}
# Cache node_modules TODO
diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml
index 4775849ca..c2aebceb4 100644
--- a/.github/workflows/deploy-prod.yml
+++ b/.github/workflows/deploy-prod.yml
@@ -48,9 +48,11 @@ jobs:
# Setup node version
- name: Setup node version
- uses: actions/setup-node@v1
+ id: nvm
+ run: echo ::set-output name=NODE_VERSION::$(cat .nvmrc)
+ - uses: actions/setup-node@v2
with:
- node-version: '14.15.1'
+ node-version: ${{ steps.nvm.outputs.NODE_VERSION }}
# Cache node_modules TODO
diff --git a/.github/workflows/deploy-stage.yml b/.github/workflows/deploy-stage.yml
index 618a1549d..66d1da662 100644
--- a/.github/workflows/deploy-stage.yml
+++ b/.github/workflows/deploy-stage.yml
@@ -48,9 +48,11 @@ jobs:
# Setup node version
- name: Setup node version
- uses: actions/setup-node@v1
+ id: nvm
+ run: echo ::set-output name=NODE_VERSION::$(cat .nvmrc)
+ - uses: actions/setup-node@v2
with:
- node-version: '14.15.1'
+ node-version: ${{ steps.nvm.outputs.NODE_VERSION }}
# Cache node_modules TODO
diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 2f5babb6e..1c0301af5 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -1,9 +1,10 @@
name: 'ESLint'
on:
+ push:
+ branches:
+ - main
pull_request:
- paths:
- - 'wp-content/plugins/core/**.js'
- - 'wp-content/themes/core/**.js'
+
jobs:
eslint:
runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index e42be9d40..307eb0a9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -140,3 +140,7 @@ dev/tests/tests/_support/_generated/
phpcs.xml
.phpcs-cache
+
+
+# Added by so cli
+*.local.php
\ No newline at end of file
diff --git a/.lefthook/prepare-commit-msg/prefix_with_jira_ticket b/.lefthook/prepare-commit-msg/prefix_with_jira_ticket
index 11ca9038e..0f3e525c6 100755
--- a/.lefthook/prepare-commit-msg/prefix_with_jira_ticket
+++ b/.lefthook/prepare-commit-msg/prefix_with_jira_ticket
@@ -7,8 +7,11 @@
FILE=$1
MESSAGE=$(cat $FILE)
IFS=/ read -a parts <<< $(git rev-parse --abbrev-ref HEAD)
+
+IS_SPECIAL_BRANCH=$(echo ${parts[0]} | grep -i 'release/\|sprint/')
+[[ ! -z "$IS_SPECIAL_BRANCH" ]] || exit 0
+
TICKET=[$(echo ${parts[1]} | grep -Eo '(\w+[-])?[0-9]+')]
-if [[ $TICKET == "[]" || "$MESSAGE" == "$TICKET"* ]]; then
- exit 0
-fi
+[[ $TICKET == "[]" || "$MESSAGE" == "$TICKET"* ]] || exit 0
+
echo "$TICKET $MESSAGE" > $FILE
diff --git a/.nvmrc b/.nvmrc
index 2f5ee741e..07c142ffe 100755
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-14.15.1
+16.13.1
diff --git a/README.md b/README.md
index 1290160d1..6d1f0bb5b 100644
--- a/README.md
+++ b/README.md
@@ -8,11 +8,11 @@ SquareOne is a development framework lovingly maintained by Modern Tribe used fo
## Documentation
* [Overview](/docs/README.md)
+ * [Getting Started](/docs/getting-started)
* [Basics](/docs/basics)
* [Concepts](/docs/concepts)
* [Tooling ](/docs/tooling)
* [Tests](/docs/tests)
- * [Getting Started](/docs/getting-started)
## Changelog
diff --git a/babel.config.js b/babel.config.js
index 281c4b50c..1e3924302 100755
--- a/babel.config.js
+++ b/babel.config.js
@@ -32,6 +32,7 @@ module.exports = {
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-regenerator',
+ '@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-object-assign',
],
diff --git a/changelog.md b/changelog.md
index 123395343..62c5f0d97 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,12 +2,24 @@
All notable changes to this project will be documented in this file.
+## 2021.12
+* Fixed: docker compose (v2) support: `WARN[0000] network proxy: network.external.name is deprecated in favor of network.name`
+* Added: Section Nav component & block.
+* Added: generic navigation component.
+* Updated: Node & NPM to latest LTS (v16.13.1), updated node package versions where supported.
+* Fixed: A posible PHP fatal when a anv menu is cached, but empty and the cache layer returns an unexpected boolean instead of an empty string.
+* Fixed: Several minor deprecation warnings in the webpack config.
+* Fixed: prevented preloading of current document when a dependency alias is enqueued in the footer
+* Added: support to preload dependencies of aliases
+
## 2021.11
* Removed: monolog. This dependency will be managed by tribe-libs.
* Updated: tribe libs to 3.4.8.
+* Fixed: Lefthook - Don't prefix commits for sprint or release branches
* Updated: docker image to 74-3.0, composer v2 support (requires `so` v5.3.0+)
* Added: Entrypoint for component scripts to run in the block editor.
* Added: Slider component JS behaviors in the block editor.
+* Added: check that `theme_location` parameter of `wp_nav_menu()` is populated before adding classes
## 2021.10
* Fixed: Misc small repairs to common blocks per QA on other projects.
diff --git a/composer.json b/composer.json
index 6570b8a13..8b8665073 100644
--- a/composer.json
+++ b/composer.json
@@ -34,6 +34,10 @@
"type": "vcs",
"url": "git@github.com:moderntribe/ACF-Image-Select.git"
},
+ {
+ "type": "vcs",
+ "url": "git@github.com:msawicki/acf-menu-chooser.git"
+ },
{
"type": "vcs",
"url": "git@github.com:moderntribe/tribe-acf-post-list-field.git"
@@ -88,6 +92,7 @@
"johnpbloch/wordpress-core": "5.7.3",
"johnpbloch/wordpress-core-installer": "2.0.*",
"mailgun/mailgun-php": "^2.8",
+ "msawicki/acf-menu-chooser": "dev-master",
"moderntribe/acf-image-select": "dev-master",
"moderntribe/tribe-acf-post-list-field": "^2.0",
"moderntribe/tribe-libs": "^3.4",
diff --git a/composer.lock b/composer.lock
index 82d83aed6..d4ee6df3f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "565a23c34f485628a2075897f5b7646f",
+ "content-hash": "e2c262dbcfe2b387d07473e6e69ab7ce",
"packages": [
{
"name": "advanced-custom-fields/advanced-custom-fields-pro",
@@ -70,16 +70,16 @@
},
{
"name": "aws/aws-sdk-php",
- "version": "3.206.0",
+ "version": "3.208.1",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "ade6621f709261097a0fd2ca0cad7a15ba899b76"
+ "reference": "d497414c1c4ae55145493f720f7b4d12afe92c02"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ade6621f709261097a0fd2ca0cad7a15ba899b76",
- "reference": "ade6621f709261097a0fd2ca0cad7a15ba899b76",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d497414c1c4ae55145493f720f7b4d12afe92c02",
+ "reference": "d497414c1c4ae55145493f720f7b4d12afe92c02",
"shasum": ""
},
"require": {
@@ -155,9 +155,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
- "source": "https://github.com/aws/aws-sdk-php/tree/3.206.0"
+ "source": "https://github.com/aws/aws-sdk-php/tree/3.208.1"
},
- "time": "2021-11-29T23:46:23+00:00"
+ "time": "2021-12-03T19:16:12+00:00"
},
{
"name": "clue/stream-filter",
@@ -1219,60 +1219,6 @@
},
"time": "2019-02-02T07:14:32+00:00"
},
- {
- "name": "mhcg/monolog-wp-cli",
- "version": "v1.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/mhcg/monolog-wp-cli.git",
- "reference": "33cd515fa7e5eac2ebca8aac995aa97a4ab2b77b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/mhcg/monolog-wp-cli/zipball/33cd515fa7e5eac2ebca8aac995aa97a4ab2b77b",
- "reference": "33cd515fa7e5eac2ebca8aac995aa97a4ab2b77b",
- "shasum": ""
- },
- "require": {
- "monolog/monolog": "^2.0",
- "php": "^7.2"
- },
- "require-dev": {
- "phpunit/phpunit": "8.5.* || 9.0.*",
- "squizlabs/php_codesniffer": "^3.5",
- "wp-cli/wp-cli": "^2.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "MHCG\\Monolog\\": "src/Monolog"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mark Heydon",
- "email": "contact@mhcg.co.uk",
- "role": "Developer"
- }
- ],
- "description": "Extension for Monolog to support outputting to WP-CLI (The WordPress command line interface) when running wp command lines.",
- "keywords": [
- "log",
- "logging",
- "psr-3",
- "wp-cli"
- ],
- "support": {
- "issues": "https://github.com/mhcg/monolog-wp-cli/issues",
- "source": "https://github.com/mhcg/monolog-wp-cli",
- "wiki": "https://github.com/mhcg/monolog-wp-cli/wiki"
- },
- "time": "2020-03-23T20:17:57+00:00"
- },
{
"name": "moderntribe/acf-image-select",
"version": "dev-master",
@@ -1340,27 +1286,23 @@
},
{
"name": "moderntribe/tribe-libs",
- "version": "3.4.8",
+ "version": "3.4.7",
"source": {
"type": "git",
"url": "https://github.com/moderntribe/tribe-libs.git",
- "reference": "a4ce17df08bc9b65b1c17ceae522fde367a5a66c"
+ "reference": "d9c630379a9657359a624133e5a00385486a7d18"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/moderntribe/tribe-libs/zipball/a4ce17df08bc9b65b1c17ceae522fde367a5a66c",
- "reference": "a4ce17df08bc9b65b1c17ceae522fde367a5a66c",
+ "url": "https://api.github.com/repos/moderntribe/tribe-libs/zipball/d9c630379a9657359a624133e5a00385486a7d18",
+ "reference": "d9c630379a9657359a624133e5a00385486a7d18",
"shasum": ""
},
"require": {
- "composer-plugin-api": "^1.0 || ^2.0",
"enshrined/svg-sanitize": "^0.13.3",
"filp/whoops": "^2.2@dev",
- "mhcg/monolog-wp-cli": "^1.0",
- "monolog/monolog": "^2.0",
"php": "^7.2",
"php-di/php-di": "^6.0",
- "psr/log": "^1.1 || ^2.0 || ^3.0",
"twig/twig": "^3.0"
},
"replace": {
@@ -1371,13 +1313,11 @@
"moderntribe/square1-cli": "self.version",
"moderntribe/square1-container": "self.version",
"moderntribe/square1-generators": "self.version",
- "moderntribe/square1-log": "self.version",
"moderntribe/square1-media": "self.version",
"moderntribe/square1-nav": "self.version",
"moderntribe/square1-object-meta": "self.version",
"moderntribe/square1-oembed": "self.version",
"moderntribe/square1-p2p": "self.version",
- "moderntribe/square1-pipeline": "self.version",
"moderntribe/square1-post-meta": "self.version",
"moderntribe/square1-post-type": "self.version",
"moderntribe/square1-queues": "self.version",
@@ -1396,8 +1336,7 @@
"require-dev": {
"automattic/phpcs-neutron-standard": "^1.5",
"automattic/vipwpcs": "^2.0.0",
- "composer/composer": "^1.0 || ^2.0",
- "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || ^0.7.0",
+ "dealerdirect/phpcodesniffer-composer-installer": "0.7.1",
"lucatume/wp-browser": "^3.0.9",
"phpcompatibility/php-compatibility": "*",
"phpcompatibility/phpcompatibility-wp": "^2.0",
@@ -1428,13 +1367,11 @@
"Tribe\\Libs\\Cache\\": "src/Cache/",
"Tribe\\Libs\\Container\\": "src/Container/",
"Tribe\\Libs\\Generators\\": "src/Generators/",
- "Tribe\\Libs\\Log\\": "src/Log/",
"Tribe\\Libs\\Media\\": "src/Media/",
"Tribe\\Libs\\Nav\\": "src/Nav/",
"Tribe\\Libs\\Object_Meta\\": "src/Object_Meta/",
"Tribe\\Libs\\Oembed\\": "src/Oembed/",
"Tribe\\Libs\\P2P\\": "src/P2P/",
- "Tribe\\Libs\\Pipeline\\": "src/Pipeline/",
"Tribe\\Libs\\Post_Meta\\": "src/Post_Meta/",
"Tribe\\Libs\\Post_Type\\": "src/Post_Type/",
"Tribe\\Libs\\Queues\\": "src/Queues/",
@@ -1458,68 +1395,61 @@
"description": "A library for use on Modern Tribe service projects.",
"support": {
"issues": "https://github.com/moderntribe/tribe-libs/issues",
- "source": "https://github.com/moderntribe/tribe-libs/tree/3.4.8"
+ "source": "https://github.com/moderntribe/tribe-libs/tree/3.4.7"
},
- "time": "2021-11-29T23:46:08+00:00"
+ "time": "2021-11-22T23:01:47+00:00"
},
{
"name": "monolog/monolog",
- "version": "2.3.5",
+ "version": "1.23.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "fd4380d6fc37626e2f799f29d91195040137eba9"
+ "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9",
- "reference": "fd4380d6fc37626e2f799f29d91195040137eba9",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
+ "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
"shasum": ""
},
"require": {
- "php": ">=7.2",
- "psr/log": "^1.0.1 || ^2.0 || ^3.0"
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
},
"provide": {
- "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
+ "psr/log-implementation": "1.0.0"
},
"require-dev": {
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
"doctrine/couchdb": "~1.0@dev",
- "elasticsearch/elasticsearch": "^7",
- "graylog2/gelf-php": "^1.4.2",
- "mongodb/mongodb": "^1.8",
- "php-amqplib/php-amqplib": "~2.4 || ^3",
+ "graylog2/gelf-php": "~1.0",
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "php-amqplib/php-amqplib": "~2.4",
"php-console/php-console": "^3.1.3",
- "phpspec/prophecy": "^1.6.1",
- "phpstan/phpstan": "^0.12.91",
- "phpunit/phpunit": "^8.5",
- "predis/predis": "^1.1",
- "rollbar/rollbar": "^1.3",
- "ruflin/elastica": ">=0.90@dev",
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "2.3.0",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "sentry/sentry": "^0.13",
"swiftmailer/swiftmailer": "^5.3|^6.0"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
- "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
- "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
- "ext-mbstring": "Allow to work properly with unicode symbols",
- "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
- "ext-openssl": "Required to send log messages using SSL",
- "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
- "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
+ "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
"php-console/php-console": "Allow sending log messages to Google Chrome",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
- "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "sentry/sentry": "Allow sending log messages to a Sentry server"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
@@ -1535,11 +1465,11 @@
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
- "homepage": "https://seld.be"
+ "homepage": "http://seld.be"
}
],
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
- "homepage": "https://github.com/Seldaek/monolog",
+ "homepage": "http://github.com/Seldaek/monolog",
"keywords": [
"log",
"logging",
@@ -1547,19 +1477,31 @@
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
- "source": "https://github.com/Seldaek/monolog/tree/2.3.5"
+ "source": "https://github.com/Seldaek/monolog/tree/1.23.0"
},
- "funding": [
- {
- "url": "https://github.com/Seldaek",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
- "type": "tidelift"
- }
- ],
- "time": "2021-10-01T21:08:31+00:00"
+ "time": "2017-06-19T01:22:40+00:00"
+ },
+ {
+ "name": "msawicki/acf-menu-chooser",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/msawicki/acf-menu-chooser.git",
+ "reference": "c8a879390df7ec8c2929715d19792d76fc62ac2e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/msawicki/acf-menu-chooser/zipball/c8a879390df7ec8c2929715d19792d76fc62ac2e",
+ "reference": "c8a879390df7ec8c2929715d19792d76fc62ac2e",
+ "shasum": ""
+ },
+ "default-branch": true,
+ "type": "wordpress-plugin",
+ "description": "A fork of acf-menu-chooser by reyhoun/acf-menu-chooser. Original can be found at https://github.com/reyhoun/acf-menu-chooser",
+ "support": {
+ "source": "https://github.com/msawicki/acf-menu-chooser/tree/master"
+ },
+ "time": "2020-01-08T20:06:07+00:00"
},
{
"name": "mtdowling/jmespath.php",
@@ -4960,16 +4902,16 @@
},
{
"name": "illuminate/collections",
- "version": "v8.73.2",
+ "version": "v8.74.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/collections.git",
- "reference": "bfb57bc1863689058706eb41287b7ad523d74403"
+ "reference": "f292b77824b42cd28decc7327e7c2e24c3806371"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/collections/zipball/bfb57bc1863689058706eb41287b7ad523d74403",
- "reference": "bfb57bc1863689058706eb41287b7ad523d74403",
+ "url": "https://api.github.com/repos/illuminate/collections/zipball/f292b77824b42cd28decc7327e7c2e24c3806371",
+ "reference": "f292b77824b42cd28decc7327e7c2e24c3806371",
"shasum": ""
},
"require": {
@@ -4978,7 +4920,7 @@
"php": "^7.3|^8.0"
},
"suggest": {
- "symfony/var-dumper": "Required to use the dump method (^5.1.4)."
+ "symfony/var-dumper": "Required to use the dump method (^5.4)."
},
"type": "library",
"extra": {
@@ -5010,11 +4952,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2021-11-15T14:44:56+00:00"
+ "time": "2021-11-30T14:29:03+00:00"
},
{
"name": "illuminate/contracts",
- "version": "v8.73.2",
+ "version": "v8.74.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
@@ -5062,7 +5004,7 @@
},
{
"name": "illuminate/macroable",
- "version": "v8.73.2",
+ "version": "v8.74.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/macroable.git",
@@ -5108,16 +5050,16 @@
},
{
"name": "illuminate/support",
- "version": "v8.73.2",
+ "version": "v8.74.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
- "reference": "ecb4d4fb01f9716b2decbb1bf584ea8164c3b222"
+ "reference": "79bb5570274d6abbfaac736992c6b5f5cbcc17c1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/support/zipball/ecb4d4fb01f9716b2decbb1bf584ea8164c3b222",
- "reference": "ecb4d4fb01f9716b2decbb1bf584ea8164c3b222",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/79bb5570274d6abbfaac736992c6b5f5cbcc17c1",
+ "reference": "79bb5570274d6abbfaac736992c6b5f5cbcc17c1",
"shasum": ""
},
"require": {
@@ -5138,8 +5080,8 @@
"illuminate/filesystem": "Required to use the composer class (^8.0).",
"league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^1.3|^2.0.2).",
"ramsey/uuid": "Required to use Str::uuid() (^4.2.2).",
- "symfony/process": "Required to use the composer class (^5.1.4).",
- "symfony/var-dumper": "Required to use the dd function (^5.1.4).",
+ "symfony/process": "Required to use the composer class (^5.4).",
+ "symfony/var-dumper": "Required to use the dd function (^5.4).",
"vlucas/phpdotenv": "Required to use the Env class and env helper (^5.2)."
},
"type": "library",
@@ -5172,7 +5114,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2021-11-23T14:10:18+00:00"
+ "time": "2021-11-30T14:13:40+00:00"
},
{
"name": "larapack/dd",
@@ -5742,16 +5684,16 @@
},
{
"name": "nesbot/carbon",
- "version": "2.54.0",
+ "version": "2.55.2",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
- "reference": "eed83939f1aed3eee517d03a33f5ec587ac529b5"
+ "reference": "8c2a18ce3e67c34efc1b29f64fe61304368259a2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/eed83939f1aed3eee517d03a33f5ec587ac529b5",
- "reference": "eed83939f1aed3eee517d03a33f5ec587ac529b5",
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8c2a18ce3e67c34efc1b29f64fe61304368259a2",
+ "reference": "8c2a18ce3e67c34efc1b29f64fe61304368259a2",
"shasum": ""
},
"require": {
@@ -5759,7 +5701,7 @@
"php": "^7.1.8 || ^8.0",
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
- "symfony/translation": "^3.4 || ^4.0 || ^5.0"
+ "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
},
"require-dev": {
"doctrine/dbal": "^2.0 || ^3.0",
@@ -5820,6 +5762,7 @@
"time"
],
"support": {
+ "docs": "https://carbon.nesbot.com/docs",
"issues": "https://github.com/briannesbitt/Carbon/issues",
"source": "https://github.com/briannesbitt/Carbon"
},
@@ -5833,20 +5776,20 @@
"type": "tidelift"
}
],
- "time": "2021-11-01T21:22:20+00:00"
+ "time": "2021-12-03T14:59:52+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v4.13.1",
+ "version": "v4.13.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd"
+ "reference": "210577fe3cf7badcc5814d99455df46564f3c077"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd",
- "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
+ "reference": "210577fe3cf7badcc5814d99455df46564f3c077",
"shasum": ""
},
"require": {
@@ -5887,9 +5830,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
},
- "time": "2021-11-03T20:52:16+00:00"
+ "time": "2021-11-30T19:35:32+00:00"
},
{
"name": "phar-io/manifest",
@@ -6594,16 +6537,16 @@
},
{
"name": "phpunit/php-file-iterator",
- "version": "3.0.5",
+ "version": "3.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8"
+ "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8",
- "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+ "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
"shasum": ""
},
"require": {
@@ -6642,7 +6585,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5"
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
},
"funding": [
{
@@ -6650,7 +6593,7 @@
"type": "github"
}
],
- "time": "2020-09-28T05:57:25+00:00"
+ "time": "2021-12-02T12:48:52+00:00"
},
{
"name": "phpunit/php-invoker",
@@ -10004,6 +9947,7 @@
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
+ "msawicki/acf-menu-chooser": 20,
"moderntribe/acf-image-select": 20,
"roots/wp-password-bcrypt": 20,
"filp/whoops": 20
diff --git a/dev/docker/docker-compose.yml b/dev/docker/docker-compose.yml
index d71c5d6b3..4579dd19f 100644
--- a/dev/docker/docker-compose.yml
+++ b/dev/docker/docker-compose.yml
@@ -122,5 +122,5 @@ services:
networks:
proxy:
- external:
- name: global_proxy
+ external: true
+ name: global_proxy
diff --git a/docs/concepts/accessibility.md b/docs/concepts/accessibility.md
index 44493c4b6..953b7441e 100644
--- a/docs/concepts/accessibility.md
+++ b/docs/concepts/accessibility.md
@@ -1,7 +1,7 @@
# Accessibility
SquareOne does it's best to lay a foundation for building themes that are accessible to all. Here are
-the guidelines we follow, which are are focused on building sites that are reachable and maintain
+the guidelines we follow, which are focused on building sites that are reachable and maintain
the same level of functionality whether interacted with by screen reader or through the use of a keyboard:
## What Is Accessibility?
@@ -21,7 +21,8 @@ For us this means building sites that are accessible by ensuring:
## Validating Code
-You should not only actively be building accessibility into your code and features, but also verifying and testing as well. Currently we utilize [tota11y](http://khan.github.io/tota11y/) for testing our theme's accessibility while we work.
+You should not only actively be building accessibility into your code and features, but also verifying and testing as well.
+Currently we utilize [tota11y](http://khan.github.io/tota11y/) for testing our theme's accessibility while we work.
## Resources
diff --git a/docs/concepts/container.md b/docs/concepts/container.md
index a326c0b58..e73888504 100644
--- a/docs/concepts/container.md
+++ b/docs/concepts/container.md
@@ -1,35 +1,21 @@
# Container / Core.php
-This plugin uses a container based framework. In particular we use the [PHP-DI](http://php-di.org/)
-dependency injection container that implements the [PSR-11 container interface](https://www.php-fig.org/psr/psr-11/).
+This plugin uses a container based framework called [PHP-DI](http://php-di.org/).
+This is a container implements the [PSR-11 container interface](https://www.php-fig.org/psr/psr-11/).
-Containers are used for dependency injection. Containers allow objects to be instantiated as
-needed and can be used to set default behaviors and properties.
+Containers are used for [dependency injection](https://php-di.org/doc/understanding-di.html). Containers allow objects
+to be instantiated as needed and can be used to set default behaviors and properties. This is beneficial because it will
+only run code that is used.
The container uses [definition files](http://php-di.org/doc/definition.html),
[autowiring](http://php-di.org/doc/autowiring.html), and callback functions to instantiate
on an as-needed basis.
-The core container is created in `Core.php` and is a singleton. Only one instance will exist,
+The core container is created in `plugins/core/src/Core.php` and is a singleton. Only one instance will exist,
no matter where it's accessed. The data and objects being passed and generated affect only the
core container.
-To access the core container, call `tribe_project()->container()`
-
----
-
-## Factory Method
-
-Many classes—including all post types classes (which extend `Post_Object`) and taxonomy classes
-(which extend `Term_Object` )—contain a static `factory()` method. This is used to retrieve
-a specific instance of a class. Typically an id is passed to retrieve it.
-
-```php
-$story = Feed_Story::factory( $post_id );
-echo $story->get_source_name();
-```
-
----
+To access the core container from anywhere, call `tribe_project()->container()`
## Configuring the Container
diff --git a/docs/concepts/php-conventions.md b/docs/concepts/php-conventions.md
index 6e0ce2a82..aeb6a8fbb 100644
--- a/docs/concepts/php-conventions.md
+++ b/docs/concepts/php-conventions.md
@@ -1 +1,13 @@
# PHP Conventions
+
+
+## Factory Method
+
+Many classes—including all post types classes (which extend `Post_Object`) and taxonomy classes
+(which extend `Term_Object` )—contain a static `factory()` method. This is used to retrieve
+a specific instance of a class. Typically, an id is passed to retrieve it.
+
+```php
+$story = Feed_Story::factory( $post_id );
+echo $story->get_source_name();
+```
diff --git a/docs/getting-started/01_installation.md b/docs/getting-started/01_installation.md
index 7e8d51dfb..58fa79aa8 100644
--- a/docs/getting-started/01_installation.md
+++ b/docs/getting-started/01_installation.md
@@ -1,111 +1,130 @@
# Installation
-## Server Requirements
-SquareOne has the same baseline requirements as WordPress, with some exceptions. Note, all these requirements are met by the SquareOne Local setup, so it's highly recommended you use SquareOne Local as you development environment.
+SquareOne has the same baseline [requirements as WordPress](https://wordpress.org/about/requirements/) with some additional requirements.
+
+> Note, all these requirements are met by the [SquareOne Global Docker](https://github.com/moderntribe/square1-global-docker) setup, so it's highly recommended you use SquareOne Global Docker as your development environment.
-However, if prefer to not use SquareOne Local, you will need to make sure your dev setup meets the following requirements:
+## Server Requirements
-HTTP Server
+#### HTTP Server
* Nginx or Apache
-* PHP 7+, 7.2 recommended
-* TODO PHP Packages?
+* PHP 7.4+
+* HTTPS Support
-SQL Server
+#### SQL Server
* MySql 5.7+ or MariaDB 10.1+, latest recommended
-Redis Server
+#### Memcached Server
* Latest recommended
## Development Requirements
+
* Git
+
+#### PHP
* Composer
-* Node (8.9.3)
+
+#### Nodejs
+* Node Version Manager (nvm)
+* Node
* Yarn
* Gulp
-* Docker
-## Installing an existing SquareOne Project
+## Included Development Environment, SquareOne Global Docker
+[SquareOne Global Docker](https://github.com/moderntribe/square1-global-docker) is a Docker CLI tool and configuration. The CLI tool will orchestrate the local development environment. It runs two sets of containers, Global Containers (DNS, SSL, SQL management for all SquareOne Projects) and the Local containers for this specific project (HTTP, Cache, Search, etc.). We've built in everything you need for a distributable development environment.
-There should be an existing repository for the project that is based off SquareOne. Get access to that repository from your project lead.
+## Creating a *NEW* SquareOne Project with SquareOne Global Docker
-### Clone Project
+1. [Install Docker for your platform](https://www.docker.com/get-started)
+1. [Install SquareOne Global Docker CLI](https://github.com/moderntribe/square1-global-docker#installation)
+1. Create a new empty repository for your project.
+1. run `so create` in a new folder. This will create a brand new Sq1 Project and provide prompts for configuration.
+1. run `so start`.
+1. [Build SquareOne](docs/getting-started/02_build.md)
+1. That's it!
-Clone a copy of the project into a working root folder. `git clone git@github.com:moderntribe/project-name.git .`
+## Installing an *EXISTING* SquareOne Project with SquareOne Global Docker
-### Environment Install Variables
+### Install SquareOne Global Docker
-SquareOne uses .env files for managing secrets. You can see an `.env.sample` file in the root. Before installation some keys are required.
-
-1. Copy the `.env.sample` file and name it `.env`
-2. Fill in the two required plugins keys
+1. [Install Docker for your platform](https://www.docker.com/get-started)
+1. [Install SquareOne Global Docker CLI](https://github.com/moderntribe/square1-global-docker#installation)
+1. Clone a copy of the project into a working root folder. `git clone git@github.com:moderntribe/project-name.git .`
+1. Run `so boostrap` or `so boostrap --multisite`. This will create a DB and automatically configure SquareOne.
+1. Ask for an existing DB from a colleague or get a production export.
+1. Using a MySQL client, connect to `mysql.tribe` with user `root` and password `password`.
+1. Import the DB to the `tribe_projectid` database.
+1. Run `so migrate-domain`.
+1. [Build SquareOne](docs/getting-started/02_build.md)
+1. That's it!
-Notes
-* Never commit a .env file to the repository. They are only for storing env secrets and should not be saved to the codebase.
-* Some licensed plugins are required for SquareOne projects (ACF, GravityForms). Removing them is possible, but is not covered here.
+## SquareOne with an Alternative Local Development Environment
+As noted, SquareOne in all intents and purposes, is WordPress. So it can be run on any local development environment
+that supports WordPress assuming you address these two additional requirements:
-## SquareOne Local
+1. WordPress is installed in a sub-folder as a dependency. We've bundled a custom Nginx file that handles this nicely here `dev/docker/nginx/nginx.conf`.
+2. All configuration and build steps must be completed.
-SquareOne Local is a Docker based development environment and is broken into two parts, Global Containers (DNS, SSL, SQL management for all SquareOne Projects) and the Local containers for this specific project (HTTP, Cache, Search, etc.). We've built in everything you need for a distributable development environment.
+### LocalWP
+For those who want to use [LocalWP](https://localwp.com/), a popular local development environment, we provide a plugin that handles the Nginx config for you [here](https://github.com/moderntribe/square-one-localwp-addon).
-Notes:
-* Local containers will NOT work if the Global containers are not running.
-* It's recommended you clone a second copy of SquareOne and run and manage your Global containers from there.
-* You can start the global containers from ANY squareOne install, but it's recommended to have a separate squareOne installation for starting/stopping the global containers. This way your SSL certs are all installed in the same installation.
+## Manually Setup and Configure SquareOne
-### Configure Dev Domain & SSL
+### Clone Project
-1. Lookup dev domain that is configured in the `/dev/docker/docker-compose.yml` for `VIRTUAL_HOST=`.
-2. Configure SSL: Run `npm run docker:global:cert DOMAIN.tribe`, where `DOMAIN` is the dev domain.
-3. Copy `local-config-sample.json` to `local-config.json` and set the `proxy` value to your domain
+Clone a copy of the project into a working root folder. `git clone git@github.com:moderntribe/project-name.git .`
-Notes:
-* As noted before, its recommended to have a "global" install of SquareOne and installing every projects certs there. Otherwise, you'll need to start and stop the global containers from each individual project.
+### Environment Install Variables
-### Spin up containers.
+SquareOne uses .env files for managing secrets required at build time. You can see an `.env.sample` file in the root. Before installation,
+some secrets are required.
-1. Run `npm run docker:global:start` (Turns on the global containers. If you are running multiple projects, this only needs to be run once)
-2. Run `npm run docker:start` (Turns on the local project containers. Recommended you start and stop as needed)
+1. Copy the `.env.sample` file and name it `.env`
+2. Fill in the required secrets from [1Password](https://start.1password.com/open/i?a=MTSABMIBDJF4PHQCMXYNWKAL4U&v=k2qbci5enqpfc4am7uvlwt6w4m&i=v67do7z62rd5nb7nrfkeih2uxa&h=moderntribe.1password.com).
-Notes:
-* Local containers will NOT work if the Global containers are not running.
+> NOTE:
+> * Never commit a .env file to the repository. They are only for storing env secrets and should not be saved to the codebase.
+> * Some licensed plugins are required for SquareOne projects (specifically ACF & GravityForms). Removing them is possible, but is not covered here.
## Build SquareOne
-When you spin up the containers for the first time, some of the build process is completed for you. If for any reason you need to run them again, here are the commands:
+1. `composer install` - This builds the PHP app and installs WordPress and plugin. (Note, if you are using `so` you can run `so composer install`)
+2. `nvm use && yarn install` - This will change to the correct node version and install node dependencies.
+3. `gulp` - This will build the CSS/JS bundles for the app.
-1. Composer: Run `bash ./dev/docker/composer.sh`. This will run inside the php container. You can run composer on the host machine, but you need to make sure you have the proper dependencies.
-2. NPM: Run `yarn install`. This will install any node dependencies.
-3. Gulp: Run `gulp`. This will build the CSS/JS bundles.
+> NOTE: [See more complete build documentation here.](docs/getting-started/02_build.md)
## Configuration
-### Create a Database
+### Configure SquareOne (WordPress)
-1. Using a MySQL client, connect to `mysql.tribe` with user `root` and password `password`
-2. Create a db of your naming
-3. Go add these credentials to the `.env` file
+Look at the `wp-config.php` and you'll see it's not standard. In addition, look at the `wp-config-enviroment.php` file. This is where we handle a lot of the configuration for you.
+Any existing project all the defaults will be added to the `wp-config-enviroment.php` file. Then on any environment, you can set or override any setting in the `local-config.php`.
+The `local-config.php` is not tracked in git, so it will be generated for each environment specifically based off the `local-config-sample.php`.
-### Configure WordPress
+1. Copy the `local-config-sample.php` to `local-config.php`, and add your configuration there.
-By default, everything will work at this point, but you might want to tweak the wordpress config like turning on multisite. Look at the `wp-config.php` and you'll see it's not standard. It's a bit overwhelming actually, but it's where all the configuration is initiated. You'll see that it parses the .env file, loads a local-config file, and checks for any defined constants. So you have your choice of how to override the defaults in two places:
+> NOTE:
+>* IF you are configuring secrets only needed at build time, the `.env` file is the best place.
+>* IF you need to add custom configuration or environment secrets, the `local-config.php` is the best place.
+>* IF you need to share configuration, you can modify the `wp-config-enviroment.php` and commit.
-1. Add a config constant to the `.env` file
-2. Copy the `local-config-sample.php` to `local-config.php`, and add your configuration there.
+### Choose a local dev toolset
-NOTE:
-* IF you are configuring secrets, the `.env` file is the best place.
-* IF you need to add custom configuration, the `local-config.php` is the best place.
-* IF you need to share configuration, you can modify the `wp-config.php` directly.
+If you are not using [SquareOne Global Docker](https://github.com/moderntribe/square1-global-docker),
+you need some other Local Development Environment that is WordPress compatible and can meet SquareOne requirments.
-### Import Seed Database
+### Create a Database
-If the team has an existing dev environment, you should import the seed data into your local as a starting point. If there is no DB, you may need to pull a backup from an existing environment. Contact your lead for help.
+1. Using a MySQL client, connect to your local mysql
+2. Create a db of your naming
+3. Add the standard WordPress database credentials to the `local-config.php`
-### Success
+### Import Seed Database
-If you can navigate to `https://DOMAIN.tribe` and see your site, huzzah! Next steps, work with your team to make sure all the proper configuration is in place.
+If the team has an existing dev environment, you should import a database into your local as a starting point. If there is no DB yet, follow the standard WordPress install process.
-If you can't load the site or have any issues along the way, reference the [full docker setup documentation](/docs/tooling/docker.md) – there are some quirks depending on your local setup it covers in detail. If you are still stuck, ping a Lead for help.
+### That's all!
diff --git a/docs/getting-started/02_build.md b/docs/getting-started/02_build.md
new file mode 100644
index 000000000..2ec19c0e8
--- /dev/null
+++ b/docs/getting-started/02_build.md
@@ -0,0 +1,72 @@
+# Build Process
+
+## Quick Start
+
+1. Required tools to be installed
+ 1. [nvm](https://github.com/creationix/nvm)
+ 1. [yarn](https://yarnpkg.com/en/docs/install).
+ 1. [gulp-cli](https://www.npmjs.com/package/gulp-cli)
+1. Build frontend development assets
+ 1. `nvm use`
+ 1. `yarn install`
+ 1. `gulp dist`
+1. Install backend development dependencies
+ 1. `composer install` or `so composer install` if using SquareOne Global Docker
+
+> Note: Make sure your composer version matches the project requirements. As of Oct 2021, Composer v2.
+
+## Building Frontend Assets
+
+### Node
+
+This system uses NPM for dependency management for front end assets.
+
+Each SquareOne project tracks the version you should be using in the .nvmrc file. We recommend
+the version manager [nvm](https://github.com/creationix/nvm) to manage your node versions. With this installed,
+all you need to do is run `nvm use` and it will automatically switch to the correct version.
+
+To install your dependencies SquareOne uses yarn: [install yarn](https://yarnpkg.com/en/docs/install).
+
+Then simply `yarn install` in the root of this project.
+
+### Gulp
+
+This system uses gulp to run tasks.
+
+If you don't already have the [gulp-cli](https://www.npmjs.com/package/gulp-cli) installed globally on that node version do so now.
+
+During dev you have two choices for gulp tasks to run when editing any pcss or javascript files.
+
+* `gulp watch` will watch pcss and js for changes
+* `yarn dev` will watch pcss and js for changes and launch [Browsersync](https://www.browsersync.io/). It will proxy through the dev url you can define in `local-config.json` at root. Check the local-config-sample.json for more information. Also set your path to the certs you generated for your docker domain.
+
+Before you push code back upstream, you must run `yarn validate`. This will lint your js and css. If you code does not lint please correct the issues then run again before pushing upstream.
+
+You should also run `yarn dist` when you pull new work, to make sure you have built the latest files from other peoples work.
+
+
+## Installing PHP dependencies
+
+### Composer
+We use [Composer](https://getcomposer.org/) to maintain PHP dependencies. This allows us to **not** version
+control stuff that is already version controlled elsewhere.
+
+### Installing Dependencies via Composer
+
+On host machine:
+`composer install`
+
+If using SquareOne Global Docker:
+`so composer install`
+
+> Note: Make sure your composer version matches the project requirements. As of Oct 2021, Composer v2.
+
+## Production Builds
+
+Production builds are not committed to the repository and are handled as part of deployments through CI tools. The commands run during a production deployment are:
+
+```shell
+composer install --optimize-autoloader --ignore-platform-reqs --no-dev
+nvm use && yarn install
+gulp server_dist
+```
diff --git a/docs/getting-started/02_local-env.md b/docs/getting-started/02_local-env.md
deleted file mode 100644
index 6772337f6..000000000
--- a/docs/getting-started/02_local-env.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Local Dev Environment
-
-TODO: guide to setting up a local dev environment using SquareOne Global Docker
-
-## SquareOne Global Docker
-
-## Build Tools
-
-## OS-Specific Considerations
-
-* [Installation guide for Ubuntu](/docs/getting-started/linux/install-guide-for-ubuntu.md)
diff --git a/docs/getting-started/03_build.md b/docs/getting-started/03_build.md
deleted file mode 100644
index d4ad9df00..000000000
--- a/docs/getting-started/03_build.md
+++ /dev/null
@@ -1,80 +0,0 @@
-# Build Process
-
-## Quick Start
-
-1. Install global build tools
- 1. nvm
- 1. yarn
- 1. gulp-cli
-1. Build frontend assets
- 1. `nvm use`
- 1. `yarn install:theme`
- 1. `gulp dist`
-1. Install backend dependencies
- 1. `so composer install`
-
-## Building Frontend Assets
-
-### Node
-
-This system uses npm for dependency management for front end assets.
-
-To find out which version you should be using, check the .nvmrc file at root. We recommend
-the version manager [nvm](https://github.com/creationix/nvm) to manage your node versions.
-
-With that installed you can just `nvm use` in the root of this folder before beginning dev
-tasks that involve node and it will put you on the correct version, after it has been installed
-by you initially.
-
-To install your dependencies it is recommended you use Yarn, a global cli tool you install that
-fetches deps from npm, bower or other repos. First install globally in your currently required
-version of node if not already in place: [install yarn](https://yarnpkg.com/en/docs/install).
-
-Then simply `yarn install` in the root of this project.
-
-### Gulp
-
-This system uses gulp to run tasks. Make sure you have installed `node_modules` at root or theme with `yarn install:theme` using the correct version of node for the project (check the .nvmrc file at root to determine that).
-
-If you don't already have the [gulp-cli](https://www.npmjs.com/package/gulp-cli) installed globally on that node version do so.
-
-If you have gulp installed globally as well, use this projects gulp version when running tasks by using `./node_modules/gulp/bin/gulp.js` instead of `gulp`
-
-During dev you have 2 choices for gulp tasks to run when editing any pcss or javascript files.
-
-* `gulp watch` will watch pcss and js for changes
-* `yarn dev` will watch pcss and js for changes and launch [Browsersync](https://www.browsersync.io/). It will proxy through the dev url you can define in `local-config.json` at root. Check the local-config-sample.json for more information. Also set your path to the certs you generated for your docker domain.
-
-Before you push code back upstream, you must run `yarn validate`. This will lint your js and css. If you code does not lint please correct the issues then run again before pushing upstream.
-
-You should also run `yarn dist` when you pull new work, to make sure you have built the latest files from other peoples work.
-
-
-## Installing PHP dependencies
-
-### Composer
-We use [Composer](https://getcomposer.org/) to maintain PHP dependencies. This allows us to **not** version
-control stuff that is already version controlled elsewhere.
-
-### Composer in Docker
-Traditionally, composer projects use the native `composer` command (e.g. `composer install`,
-`composer update`). Because SquareOne operates in Docker containers, we cannot rely on composer
-to behave appropriately in all environments because *composer runs on the host machine, and not
-in the docker container that has all the expected system requirements such as the appropriate PHP version.*
-
-As such, SquareOne Global provides the `so composer` command that mirrors the native `composer` command.
-The only difference is that it runs *inside* the docker php-fpm container.
-
-### Setting Up SquareOne
-When you initially start your docker containers using the
-`so start` command, composer will look for a `composer/auth.json` file
-in your `dev/docker` directory. This is a specially formatted JSON file used to authenticate
-against Github for private repo access. If it doesn't exist, you will be prompted to visit
-a URL on Github that will grant an oAuth token. Copy this token and paste it onto the command
-line at the prompt, which will then create the `auth.json` file.
-
-After the containers launch, the `so start` command will automatically also run
-`composer install` and setup SquareOne. However, there may be times where, say, a version of
-WordPress needs to be bumped or a plugin needs updating. Make the change in `composer.json`
-and run `so composer update`. This will download the updated packages and install
-in place. It will also upddate the `composer.lock` file which should be committed.
diff --git a/docs/getting-started/05_structure.md b/docs/getting-started/03_structure.md
similarity index 65%
rename from docs/getting-started/05_structure.md
rename to docs/getting-started/03_structure.md
index c9f2d8d29..3c2dd99bc 100644
--- a/docs/getting-started/05_structure.md
+++ b/docs/getting-started/03_structure.md
@@ -12,8 +12,7 @@ The `Core` class is responsible for initializing the [DI container](/docs/concep
all of the [Subscribers](/docs/concepts/subscribers.md) to register their hooks with WordPress. From here, things become
much less linear, so we'll need to branch out in a few different directions.
-* `\Tribe\Project\Assets`: Theme assets for the front end and admin are registered and enqueued in
- `\Tribe\Project\Assets`.
+* `\Tribe\Project\Assets`: Where Theme assets for the front end and admin are registered and enqueued.
* `\Tribe\Project\Blocks`: [Block types](/docs/basics/blocks.md) for the block editor are defined by classes in the
`\Tribe\Project\Blocks\Types` namespace and registered by adding to the list in
@@ -35,24 +34,23 @@ much less linear, so we'll need to branch out in a few different directions.
new relationship types are registered using classes in the `\Tribe\Project\P2P` namespace.
* `\Tribe\Project\Post_Types`: All of the [post types](/docs/basics/post-types.md) we interact with have classes in
- the `\Tribe\Project\Post_Types` namespace. `Config` files will configure custom post types that we register.
+ this namespace. `Config` files will configure custom post types that we register.
Classes extending `\Tribe\Libs\Post_Type\Post_Object` for each post type provide access to post meta and other
helpful methods relating to those post types.
-* `\Tribe\Project\Settings`: New [admin settings](/docs/basics/settings.md) pages are registered with classes in the
- `\Tribe\Project\Settings` namespace.
+* `\Tribe\Project\Settings`: New [admin settings](/docs/basics/settings.md) pages are registered in this namespace.
-* `\Tribe\Project\Shortcodes`: Shortcodes are registered with classes in the `\Tribe\Project\Shortcodes` namespace.
+* `\Tribe\Project\Shortcodes`: Shortcodes are registered with classes in this` namespace.
* `\Tribe\Project\Taxonomies`: All of the [taxonomies](/docs/basics/taxonomies.md) we interact with have classes in
- the `\Tribe\Project\Taxonomies` namespace. `Config` files will configure custom taxonomies that we register.
+ this namespace. `Config` files will configure custom taxonomies that we register.
Classes extending `\Tribe\Libs\Taxonomy\Term_Object` for each taxonomy provide access to term meta and other
helpful methods relating to those taxonomies.
* `\Tribe\Project\Templates`: The Controllers under the `\Tribe\Project\Templates\Controllers` namespace are responsible
for loading the [template components](/docs/basics/components.md) with appropriate data.
-* `\Tribe\Project\Theme`: To configure various theme settings, explore the `\Tribe\Project\Theme` namespace. Of
+* `\Tribe\Project\Theme`: To configure various theme settings, explore this namespace. Of
particular note are the configuration options for colors, gradients, and fonts available in
`\Tribe\Project\Theme\Theme_Definer`, as well as the image sizes defined in `\Tribe\Project\Theme\Config\Image_Sizes`.
@@ -62,30 +60,63 @@ The Core theme is found in `wp-content/themes/core`.
In the root of the theme, you will find the traditional files of the [WordPress template
hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/). While all of the files are loaded by
-WordPress just as one would expect, inside the files you will find a single call to `tribe_template()`, the function
-responsible for loading the template controllers and, ultimately, the theme components found, ironically enough,
+WordPress just as one would expect, inside the files you will find a single call to `get_template_part()`, the function
+responsible for loading the templates, which are found in the `routes` directory. Then Routes, themselves use components
in the theme's `components` directory.
-The components themselves are arranged in a largely flat structure, with a few deviations for components that may
-be naturally grouped together (e.g., page templates). Each component's directory contains its own JS and CSS, which
-are compiled into the `assets` directory by the [build system](/docs/tooling/build-system.md).
+#### Theme Structure:
+* `themes/core/`
+ * Root theme folder
+* `themes/core/assets/`
+ * CSS and JS source files grouped by `Theme` and `Admin`.
+
+* `themes/core/routes`
+ * Main templates that match the WordPress template hierarchy. (index, page, single, etc)
+
+* `themes/core/components`
+ * All the building blocks of views. [Read more about components here.](/docs/basics/components.md)
+
+* `themes/core/blocks`
+ * ACF block template entrypoint. This is a middle-man file that passes ACF registered block data to a component.
+
+* `theme/core/integrations`
+ * Any third party integration CSS or JS source files
+
+* `themes/core/page-templates`
+ * Folder for placing any [WordPress page-templates](https://developer.wordpress.org/themes/template-files-section/page-template-files/#creating-custom-page-templates-for-global-use).
+
+
+### Components
+This core theme is build component first, meaning they are arranged in a largely flat structure, with a few deviations for components that may
+be naturally grouped together (e.g., Blocks). Each component's directory contains its own JS and CSS, which
+are compiled into the `assets` directory by the [build system](/docs/tooling/build-system.md).
+
+### Global Assets
Assets that are globally relevant are also contained in the `assets` directory and compiled into the same `dist` files.
+### 3rd party
+
As with the Core plugin, components to integrate the theme with 3rd-party plugins and services should be contained
within the `integrations` directory. These components, too, will be compiled into the `dist` assets.
-## Dev Tools
+## Other stuff
-Outside of the Core plugin and Core theme, most of the project consists of development tools. Some notable places to
+Outside the Core plugin and Core theme, most of the project consists of development tools. Some notable places to
mention:
-* `dev/deploy`: Scripts to deploy the project from Jenkins.
+* `.github`: Github actions workflows
+
+* `.lefthook`: Git hook action runner scripts
* `dev/docker`: Configures the Docker container for running the project.
* `dev/tests`: Contains the codeception test suites.
-* `dev_componetns`: Resources for theme development.
+* `gulp-tasks`: Contains the build system Gulp tasks
+
+* `webpack`: Contains the build system webpack configuration
* `docs`: This documentation.
+
+* Various other root files that are all google-able for what they do.
diff --git a/docs/getting-started/04_configuration.md b/docs/getting-started/04_configuration.md
deleted file mode 100644
index 24105cfe6..000000000
--- a/docs/getting-started/04_configuration.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Configuration
-
-TODO
diff --git a/docs/getting-started/04_deployment.md b/docs/getting-started/04_deployment.md
new file mode 100644
index 000000000..541d4727a
--- /dev/null
+++ b/docs/getting-started/04_deployment.md
@@ -0,0 +1,34 @@
+# Deployment
+
+SquareOne has built in orchestration for deployments using GitHub Actions located in the `.github/workflows/` folder.
+
+> Note: How deployments work will depend on server environments, but the process to deploy will be the same.
+
+## Overview
+
+GitHub Actions is a CI/CD platform that can be used for all sorts of automation.
+When using a Git based Managed Host, we often configure SquareOne for deploys with GitHub actions.
+The following instructions will show how to configure GitHub actions to support manual or GitOps flow deployments.
+It will also show how to deploy to a standard WordPress Managed Host, or a Herokiush Host.
+
+## Requirements
+
+* A SquareOne based repository on GitHub.
+* GitHub Account with GitHub Actions activated. For public repositories this is free, for private you require a
+ paid organization account.
+
+## Git Based Deployments
+
+> IMPORTANT - Always back up critical environments prior to a deploy
+
+### General Configuration
+1. Ensure Actions are enabled for your Org and for the repository
+1. Make sure any required secrets are configured. Refer to the Workflows.
+
+### How to Deploy
+
+1. Goto the GitHib Actions for the desired project. Then select the desired workflow. For example, if I want
+ to deploy to the Dev server I would choose the `deploy-dev` workflow.
+1. Click the `Run Workflow` dropdown, chose the correct server branch you wish to deploy to the selected workflow. For example, if I want
+ to deploy to the Dev server I could choose the `server/dev` branch or any other desired feature branch.
+1. Click the `Run Workflow` button. The project will now build and deploy the artifact to your selected workflow environment.
diff --git a/docs/getting-started/06_deployment.md b/docs/getting-started/06_deployment.md
deleted file mode 100644
index 692a732b9..000000000
--- a/docs/getting-started/06_deployment.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Deployment
-
-SquareOne has built in orchestration for deployments using GitHub Actions located in the `.github/workflows/` folder.
-
-## Overview
-
-GitHub Actions is a CI/CD platform that can be used for all sorts of automation.
-When using a Git based Managed Host, we often configure SquareOne for deploys with GitHub actions.
-The following instructions will show how to configure GitHub actions to support manual or GitOps flow deployments.
-It will also show how to deploy to a standard WordPress Managed Host, or a Herokiush Host.
-
-## Requirements
-
-* A SquareOne based repository on GitHub.
-* GitHub Account with GitHub Actions activated. For public repositories this is free, for private you require a
- paid organization account.
-
-## Managed Host Git Based Deployments
-
-### IMPORTANT
-* It's highly recommended setting up the Dev environment first and backing up prior to the first deploy.
-* This deployment workflow assumes WordPress is in the root folder of the project.
-* This deployment workflow assumes you have a host with Git Based deployments.
-
-### General Configuration
-1. Ensure Actions are enabled for your Org and for the repository
-1. Create a branch for each environment. Recommended `server/*`, like `server/dev`, `server/prod`, etc.
- Make sure each branches code matches what you want on the target environment.
-1. Setup Repository Secrets:
- 1. DEV_DEPLOY_REPO = The git repository address (in ssh format)
- 1. COMPOSER_ENV = License Keys required for some premium plugins installed via composer.
- 1. DEPLOY_PRIVATE_SSH_KEY = The Private SSH key configured on your target host.
-
-### How to Manually Deploy
-
-Make sure the workflow is configured for the `on.workflow_dispatch` trigger.
-
-```yaml
-on:
- workflow_dispatch:
-```
-
-1. Goto `https://github.com/{your-org}/{your-repo}}/actions/workflows/deploy-{env}.yml` for the desired environment. For example, if I want
- to deploy to the Dev server I would choose the `deploy-dev` workflow.
-1. Click the `Run Workflow` dropdown, chose the correct server branch you wish to deploy to the selected workflow. For example, if I want
- to deploy to the Dev server I would choose the `server/dev` branch.
-1. Click the `Run Workflow` button. The SquareOne project will now build and deploy the artifact to your environment.
-
-### How to GitOps Deploy
-
-Make sure the workflow is configured for the `on.branches.push` trigger.
-
-```yaml
-on:
- push:
- branches:
- - server/dev
-```
-
-1. Merge or commit to the `server/dev` branch. A deployment will now run. Example: `git commit --allow-empty -m "Deploy Dev"`
-
-## Dokku Based Deployments
-
-Heroku is very popular Hosting PaaS provider. Many "App engines" have now modeled themselves on how Heroku has configured their systems,
-hence the term Herokuish. We use Dokku (an open source alternative) in some cases, so we've built in full Herokuish support into SQ1.
-
-If you want to use a Herokuish setup, you are probably familiar with how it works, so we won't cover it in detail here.
-But in broad strokes you'll need the php and nodejs buildpacks and then reference our local install docs for any required config.
-From there, we bundle a Procfile and the needed Nginx and PHP config. If you want WP-CLI installed on your web service, add our custom [SquareOne buildpack](https://github.com/moderntribe/heroku-buildpack-sq1)
-can do that for you. Because SQ1 is WordPress it requires you set up your own DB service and optional object caching service. Then all WP config
-variables are wired to pull from Environment variables you can configure on your Herokuish provider.
-
-
diff --git a/docs/getting-started/linux/install-guide-for-ubuntu.md b/docs/getting-started/linux/install-guide-for-ubuntu.md
deleted file mode 100644
index 51afeb7ba..000000000
--- a/docs/getting-started/linux/install-guide-for-ubuntu.md
+++ /dev/null
@@ -1,274 +0,0 @@
-# SquareOne setup guide for Ubuntu
-
-This is a step by step installation guide intended to get the project up and
-running in the shortest time possible and hopefully with none or few issues in between.
-
-This guide has been tested on a clean installation of Ubuntu 18.04 using the minimal
-setup options and but it should work on previous versions of Ubuntu as well.
-
-# Steps
-
-### Prerequisites
-
-1. Get package list up to date
-```
-sudo apt-get update
-```
-
-2. Install mysql-client
-```
-sudo apt-get install mysql-client
-```
-
-3. Install Git with default packages
-```
-sudo apt-get install git
-```
-
-4. Install Python (required by some node package)
-```
-sudo apt-get install python
-```
-
-5. Install CURL (if you don't already have it). [View source](https://linuxhint.com/install-curl-on-ubuntu-18-04/)
-```
-sudo apt-get install curl
-```
-
-6. Install network tools
-```
-sudo apt-get install net-tools
-```
-
-7. Install the ca-certificates package
-```
-sudo apt-get install ca-certificates
-```
-
-8. Install certificate management tool. [View source](https://leehblue.com/add-self-signed-ssl-google-chrome-ubuntu-16-04/)
-```
-sudo apt-get install libnss3-tools
-```
-
-9. Install NVM (Node Version Manager). [View source](https://github.com/creationix/nvm) - read the
- instructions to make sure the command works. Close the terminal and open a new one after installing nvm.
-```
-curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
-```
-
-10. Install the Node version specified on the .nvmrc
-```
-nvm install {version number}
-```
-
-11. Install gulp-cli globally. [View source](https://github.com/gulpjs/gulp-cli)
-```
-npm install gulp-cli -g
-```
-
-12. Install Yarn. [View source](https://linuxize.com/post/how-to-install-yarn-on-ubuntu-18-04/)
-
- 1. The first step is to enable the Yarn repository. Start by importing the repository’s GPG key using the following curl command:
- ```
- curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
- ```
-
- 2. Add the Yarn APT repository to your system’s software repository list by typing:
- ```
- echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
- ```
-
- 3. Once the repository is added to the system, update the package list and install Yarn, with
- ```
- sudo apt-get update
- ```
-
- 4. Install yarn skipping nodejs install because we're using nvm
- ```
- sudo apt-get install --no-install-recommends yarn
- ```
-
-13. Install Docker using the repository. [View source](https://docs.docker.com/v17.09/engine/installation/linux/docker-ce/ubuntu/)
-
- 1. Install packages to allow apt to use a repository over HTTPS.
- ```
- sudo apt-get install \
- apt-transport-https \
- software-properties-common
- ```
-
- 2. Add Docker’s official GPG key.
- ```
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- ```
-
- 3. Optionally - Verify that you now have the key with the proper fingerprint 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88, by searching for the last 8 characters of the fingerprint using the following command.
- ```
- sudo apt-key fingerprint 0EBFCD88
- ```
-
- 4. Use the following command to set up the stable repository. You always need the stable repository, even if you want to install builds from the edge or test repositories as well.
- ```
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- ```
-
- 5. Update package index.
- ```
- sudo apt-get update
- ```
-
- 6. Install the latest version of Docker CE. Any existing installation of Docker is replaced.
- ```
- sudo apt-get install docker-ce
- ```
-
- 7. Verify that Docker CE is installed correctly by running the hello-world image.
- ```
- sudo docker run hello-world
- ```
-
- 8. There seems to be an issue with docker and permissions, so executing the following commands will save you from that headache. [View source](https://github.com/docker/compose/issues/4181)
- ```
- sudo usermod -aG docker $USER
- newgrp docker
- ```
-
- 10. Restart
-
-13. Install Docker Compose. [View source](https://docs.docker.com/compose/install/)
-
- 1. Download the latest version of Docker Compose.
- ```
- sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
- ```
-
- 2. Apply executable permissions to the binary.
- ```
- sudo chmod +x /usr/local/bin/docker-compose
- ```
-
- 3. Optionally - install command completion for the bash and zsh shell. [View source](https://docs.docker.com/compose/completion/)
-
- 4. Test the installation.
- ```
- docker-compose --version
- ```
-
-
-### OS Configuration
-
-1. Disable DNS Cache
-
- 1. Open Network Manager configuration file.
- ```
- sudo gedit /etc/NetworkManager/NetworkManager.conf
- ```
-
- 2. under [main] section comment the following entry by adding the # symbol to start of line like below (if the line exists), save the configuration file and close the editor.
- ```
- #dns=dnsmasq
- ```
-
- 3. Update your computer's primary DNS server through the network's graphical interface.
- ```
- 127.0.0.1, 1.1.1.1, 8.8.8.8
- ```
-
- 4. Execute following commands to restart both the network-manager and networking services.
- ```
- sudo service network-manager restart
- sudo service networking restart
- ```
-
- 1. Restart
-
-### Setup docker image
-
-Make sure you have setup your ssh keys previously
-
-1. Open a terminal and ensure that bash is installed
-```
-command -v bash # => /bin/bash
-```
-
-2. Clone the SquareOne repo to your development machine. Go to your worskpace directory,
-```
-git clone {repository url}
-```
-
-3. Open a terminal in the cloned repository's directory in order to copy the sample config files
-```
-cp local-config-sample.json local-config.json
-cp dev/docker/global/.env{.sample,}
-```
-
-4. Use ifconfig to determine your Docker service IP address. The output should include an \interface named Docker0 or Docker1 or similar. Take note of the inet addr; that IP address should replace 0.0.0.0 in your dev/docker/global/.env file.
-
-5. Install required packages
-```
-yarn install
-```
-
-6. Start your global container, it will take a while the first time since it is downloading/installing stuff. Note: there might be an error saying something like "Creating tribe-dns-external ... error" ignore it, it will go away later.
-```
-so global:start
-```
-
-7. Disable the systemd-resolved service
-```
-sudo systemctl disable systemd-resolved.service
-```
-
-8. Stop the systemd-resolved service
-```
-sudo service systemd-resolved stop
-```
-
-9. Stop your global container
-```
-so global:stop
-```
-
-10. Restart
-
-11. Start your global container. Yes, you need to start your global container before starting to work.
-```
-so global:start
-```
-
-# Troubleshooting
-
-### 1. After installing the global container, I can't access the internet at all. Or: I can only access the internet when the global container is on.
-
-1. Ensure that the resolvconf is installed.
-```
-sudo apt update && sudo apt install resolvconf
-```
-
-2. Create a resolv.conf head file. This will place any content above any auto generated `/etc/resolv.conf` content.
-```
-sudo nano /etc/resolvconf/resolv.conf.d/head
-```
-with following contents:
-```
-nameserver 127.0.0.1
-nameserver 1.1.1.1
-nameserver 1.0.0.1
-```
-Note: You can use your preferred nameservers here, as long as `127.0.0.1` is at the top. It's also possible NetworkManager will provide them automatically via DHCP.
-3. Start the service and see if it worked
-```
-sudo systemctl start resolvconf.service
-```
-4. Verify `/etc/resolv.conf` contains the proper nameservers
-
-`cat /etc/resolv.conf`
-
-Should display the following at the top of the file:
-
-nameserver 127.0.0.1
-nameserver 1.1.1.1
-nameserver 1.0.0.1
-4. Now restart your computer.
diff --git a/docs/tooling/docker.md b/docs/tooling/docker.md
index 62de46b8e..762c1363f 100644
--- a/docs/tooling/docker.md
+++ b/docs/tooling/docker.md
@@ -1,17 +1,17 @@
# Docker
This project uses Docker containers to build the local development environment. This environment
-is managed using the file `dev/docker/docker-compose.yml`.
+is managed using the CLI tool [SquareOne Global Docker](https://github.com/moderntribe/square1-global-docker).
-The Docker Compose configuration will launch all the containers necessary to run a default SquareOne project. These
+The Docker Compose configuration in the `dev/docker/` folder will launch all the containers necessary to run the project. These
services include:
-* nginx
+* Nginx
* PHP-FPM
* Memcached
* Instances of the above specific to running automated tests
* Selenium with Chrome for use in webdriver tests
-
+* Additional container services as configured
## Adding Services
@@ -200,11 +200,13 @@ Ideally, we can find containers on Docker Hub that we can use on our projects wi
`docker-compose.yml`. Sometimes, though, we need to override how the container is built, extending it with our
own `Dockerfile`. The most common scenario is a project that needs special extensions added to the PHP container.
-To extend the SquareOne container image, create a new `Dockerfile` at `dev/docker/phpdocker/php-fpm/Dockerfile`.
+To extend a SquareOne container image, create a new `Dockerfile` at `dev/docker/service-name/Dockerfile`.
This can be configured however it makes sense for the project, but typically it will look something like:
+Example of extending the squareone-php container:
+
```dockerfile
-FROM moderntribe/squareone-php:74-2.0.1
+FROM moderntribe/squareone-php:74-3.0
# Install applications/extensions required for this project
RUN apt-get update \
@@ -226,7 +228,9 @@ x-php: &php
The `image` key is used to distinguish this from images used on other projects. The revision number should increment
every time a change is committed to the `Dockerfile` to automatically trigger a fresh build when a coworker pulls your
-changes.
+changes.
+
+> Note, custom images will only be stored locally.
### Making Upstream Changes
diff --git a/package.json b/package.json
index 36343bf43..bdc58fdbb 100644
--- a/package.json
+++ b/package.json
@@ -52,8 +52,8 @@
"not op_mob <= 12.1"
],
"engines": {
- "node": "14.15.1",
- "npm": "6.14.8"
+ "node": "16.13.1",
+ "npm": "8.1.2"
},
"scripts": {
"build": "gulp server_dist",
@@ -72,9 +72,9 @@
"test": "cross-env NODE_ENV=test jest --config jest.config.json"
},
"dependencies": {
+ "@babel/runtime": "^7.16.3",
"@types/react": "^16.9.11",
"@vimeo/player": "^2.15.3",
- "caniuse-lite": "1.0.30001235",
"classnames": "^2.2.6",
"delegate": "^3.2.0",
"es6-promise": "^4.2.8",
@@ -123,6 +123,7 @@
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-transform-object-assign": "^7.0.0",
"@babel/plugin-transform-regenerator": "^7.7.0",
+ "@babel/plugin-transform-runtime": "^7.16.0",
"@babel/preset-env": "^7.7.1",
"@babel/preset-react": "^7.7.0",
"babel-eslint": "^10.0.3",
@@ -130,6 +131,7 @@
"babel-loader": "^8.0.6",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-module-resolver": "^3.2.0",
+ "babel-plugin-react-css-modules": "^5.2.6",
"browser-sync": "^2.26.7",
"concat": "^1.0.3",
"core-js": "^3.13.1",
@@ -137,6 +139,7 @@
"css-color-converter": "^1.1.0",
"css-hot-loader": "^1.4.4",
"css-loader": "^3.2.0",
+ "css-minimizer-webpack-plugin": "^3.2.0",
"cssnano": "^4.1.10",
"del": "^5.1.0",
"enhanced-resolve": "^4.1.1",
@@ -153,7 +156,6 @@
"eslint-plugin-react": "^7.16.0",
"eslint-plugin-wpcalypso": "^4.1.0",
"expect": "^24.9.0",
- "extract-text-webpack-plugin": "4.0.0-beta.0",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-cssnano": "^2.1.3",
@@ -172,13 +174,12 @@
"gulp-uglify": "^3.0.1",
"identity-obj-proxy": "^3.0.0",
"ifdef-loader": "^2.1.4",
- "jest": "^24.9.0",
- "jest-cli": "^24.9.0",
+ "jest": "^25.1.0",
+ "jest-cli": "^25.1.0",
"jest-environment-jsdom": "^24.9.0",
"jest-environment-jsdom-global": "^1.2.0",
"json2php": "0.0.4",
"mini-css-extract-plugin": "^0.9.0",
- "optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-aspect-ratio": "^1.0.0",
"postcss-assets": "^5.0.0",
"postcss-calc": "^7.0.1",
@@ -202,7 +203,6 @@
"stylelint-config-standard": "^19.0.0",
"stylelint-order": "^3.1.1",
"terser-webpack-plugin": "^2.2.1",
- "uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^5.3.2",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-cli": "^4.7.2",
diff --git a/webpack/configs/app-base.js b/webpack/configs/app-base.js
index 09da26607..456ebdc0a 100755
--- a/webpack/configs/app-base.js
+++ b/webpack/configs/app-base.js
@@ -1,26 +1,48 @@
/**
* External Dependencies
*/
+const path = require( 'path' );
const webpack = require( 'webpack' );
module.exports = {
+ resolve: {
+ extensions: [ '.js', '.jsx', '.json', '.pcss' ],
+ },
+ resolveLoader: {
+ modules: [ path.resolve( `${ __dirname }/../../`, 'node_modules' ) ],
+ },
devtool: 'eval-source-map',
devServer: {
disableHostCheck: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
+ port: 3000,
+ hot: true,
},
plugins: [
- new webpack.HashedModuleIdsPlugin(),
+ new webpack.IgnorePlugin( {
+ resourceRegExp: /^\.\/locale$/,
+ contextRegExp: /moment$/,
+ } ),
new webpack.LoaderOptionsPlugin( {
debug: true,
} ),
+ new webpack.HotModuleReplacementPlugin(),
],
module: {
rules: [
{
- test: /\.pcss$/,
+ test: /\.js$/,
+ exclude: [ /node_modules\/(?!(swiper|dom7)\/).*/ ],
+ use: [
+ {
+ loader: 'babel-loader',
+ },
+ ],
+ },
+ {
+ test: /\.p?css$/,
use: [
'style-loader',
{
@@ -43,8 +65,7 @@ module.exports = {
],
},
optimization: {
- namedModules: true, // NamedModulesPlugin()
- noEmitOnErrors: true, // NoEmitOnErrorsPlugin
concatenateModules: true, //ModuleConcatenationPlugin
+ moduleIds: 'deterministic',
},
};
diff --git a/webpack/configs/dev-base.js b/webpack/configs/dev-base.js
index 99f4873a0..49456b3d2 100644
--- a/webpack/configs/dev-base.js
+++ b/webpack/configs/dev-base.js
@@ -27,7 +27,6 @@ module.exports = merge.strategy( {
],
optimization: {
splitChunks,
- noEmitOnErrors: true, // NoEmitOnErrorsPlugin
concatenateModules: true, //ModuleConcatenationPlugin
},
} );
diff --git a/webpack/configs/prod-base.js b/webpack/configs/prod-base.js
index 4546bbf27..8b5d61f94 100644
--- a/webpack/configs/prod-base.js
+++ b/webpack/configs/prod-base.js
@@ -31,7 +31,6 @@ module.exports = merge.strategy( {
],
optimization: {
splitChunks,
- noEmitOnErrors: true, // NoEmitOnErrorsPlugin
concatenateModules: true, //ModuleConcatenationPlugin
minimizer,
},
diff --git a/webpack/example.js b/webpack/example.js
index 320644cee..9cf39b560 100644
--- a/webpack/example.js
+++ b/webpack/example.js
@@ -2,16 +2,14 @@
* External Dependencies
*/
const { resolve } = require( 'path' );
-const merge = require( 'webpack-merge' );
/**
* Internal Dependencies
*/
-const base = require( './configs/base.js' );
const appBase = require( './configs/app-base.js' );
const pkg = require( '../package.json' );
-module.exports = merge( base, {
+module.exports = {
mode: 'development',
entry: {
scripts: `./${ pkg.square1.paths.core_apps_js_src }Example/index.js`,
@@ -19,7 +17,7 @@ module.exports = merge( base, {
output: {
filename: 'app.js',
path: resolve( `${ __dirname }/../`, 'public/js/' ),
- publicPath: 'https://localhost:3000/',
+ publicPath: 'http://localhost:3000/',
},
...appBase,
-} );
+};
diff --git a/webpack/optimization/minimizer.js b/webpack/optimization/minimizer.js
index 29844b85d..8323d0f9c 100644
--- a/webpack/optimization/minimizer.js
+++ b/webpack/optimization/minimizer.js
@@ -1,5 +1,5 @@
const TerserPlugin = require( 'terser-webpack-plugin' );
-const OptimizeCSSAssetsPlugin = require( 'optimize-css-assets-webpack-plugin' );
+const CssMinimizerPlugin = require( 'css-minimizer-webpack-plugin' );
module.exports = [
new TerserPlugin( {
@@ -17,9 +17,5 @@ module.exports = [
},
},
} ),
- new OptimizeCSSAssetsPlugin( {
- cssProcessorOptions: {
- zindex: false,
- },
- } ),
+ new CssMinimizerPlugin(),
];
diff --git a/webpack/rules/styles.js b/webpack/rules/styles.js
index 1b896201a..e87ccdd3c 100644
--- a/webpack/rules/styles.js
+++ b/webpack/rules/styles.js
@@ -7,6 +7,10 @@ module.exports = {
{
loader: 'css-loader',
options: {
+ modules: {
+ localIdentName: '[name]__[local]___[hash:base64:5]',
+ },
+ importLoaders: 1,
sourceMap: true,
},
},
diff --git a/wp-content/mu-plugins/force-plugin-activation.php b/wp-content/mu-plugins/force-plugin-activation.php
index 9d1846595..4fb412970 100644
--- a/wp-content/mu-plugins/force-plugin-activation.php
+++ b/wp-content/mu-plugins/force-plugin-activation.php
@@ -25,6 +25,7 @@ class Force_Plugin_Activation {
'core/core.php',
'disable-emojis/disable-emojis.php',
'acf-image-select/acf-image-select.php',
+ 'acf-menu-chooser/acf-menu-chooser.php',
'tribe-acf-post-list-field/tribe-acf-post-list-field.php',
];
diff --git a/wp-content/plugins/core/functions/pluggable.php b/wp-content/plugins/core/functions/pluggable.php
index 0e093abdb..383e9b7ae 100644
--- a/wp-content/plugins/core/functions/pluggable.php
+++ b/wp-content/plugins/core/functions/pluggable.php
@@ -10,8 +10,7 @@
if ( ! function_exists( 'wp_mail' ) &&
! ( defined( 'WP_CLI' ) && WP_CLI ) && // phpcs:ignore -- phpcs doesn't handle spaces used for alignment
- ( defined( 'QUEUE_MAIL' ) && QUEUE_MAIL ) ) // phpcs:ignore -- https://github.com/squizlabs/PHP_CodeSniffer/issues/1586
-{
+ ( defined( 'QUEUE_MAIL' ) && QUEUE_MAIL ) ) {
/**
* @throws \Exception
*/
diff --git a/wp-content/plugins/core/src/Assets/Theme/Scripts.php b/wp-content/plugins/core/src/Assets/Theme/Scripts.php
index bcc669880..d6879b828 100644
--- a/wp-content/plugins/core/src/Assets/Theme/Scripts.php
+++ b/wp-content/plugins/core/src/Assets/Theme/Scripts.php
@@ -2,6 +2,8 @@
namespace Tribe\Project\Assets\Theme;
+use _WP_Dependency;
+
class Scripts {
private JS_Config $config;
@@ -46,6 +48,8 @@ public function maybe_inject_bugsnag(): void {
/**
* Output preload directives in head for scripts in footer
*
+ * Supports preloading dependencies of aliases (scripts with dependencies and no source URL).
+ *
* @action wp_head
*/
public function set_preloading_tags(): void {
@@ -59,14 +63,37 @@ public function set_preloading_tags(): void {
continue;
}
- //-- If version is set, append to end of source.
- $source = $script->src . ( $script->ver ? "?ver={$script->ver}" : "" );
+ // If not an alias, print preload tag.
+ if ( ! empty( $script->src ) ) {
+ $this->print_preload_tag( $script );
- //-- Spit out the tag.
- echo "\n";
+ continue;
+ }
+
+ // If source is empty and no dependencies, then not an alias: skip (nothing to preload).
+ if ( empty( $script->deps ) ) {
+ continue;
+ }
+
+ // If an alias, preload set dependencies.
+ foreach ( $script->deps as $dep_handle ) {
+ if ( ! isset( $wp_scripts->registered[ $dep_handle ] ) ) {
+ continue;
+ }
+
+ $this->print_preload_tag( $wp_scripts->registered[ $dep_handle ] );
+ }
}
}
+ protected function print_preload_tag( _WP_Dependency $script ): void {
+ //-- If version is set, append to end of source.
+ $source = $script->src . ( $script->ver ? "?ver={$script->ver}" : "" );
+
+ //-- Spit out the tag.
+ echo "\n";
+ }
+
/**
* @return void
*
@@ -100,7 +127,7 @@ public function enqueue_scripts(): void {
$this->localize_scripts( (string) reset( $handles ) );
if ( defined( 'HMR_DEV' ) && HMR_DEV === true ) {
- wp_enqueue_script( 'tribe-scripts-hmr-bundle', 'https://localhost:3000/app.js', $handles, time(), true );
+ wp_enqueue_script( 'tribe-scripts-hmr-bundle', 'http://localhost:3000/app.js', $handles, time(), true );
}
}
diff --git a/wp-content/plugins/core/src/Blocks/Blocks_Definer.php b/wp-content/plugins/core/src/Blocks/Blocks_Definer.php
index 691c8aaf9..67c2a4834 100644
--- a/wp-content/plugins/core/src/Blocks/Blocks_Definer.php
+++ b/wp-content/plugins/core/src/Blocks/Blocks_Definer.php
@@ -19,6 +19,7 @@
use Tribe\Project\Blocks\Types\Logos\Logos;
use Tribe\Project\Blocks\Types\Media_Text\Media_Text;
use Tribe\Project\Blocks\Types\Quote\Quote;
+use Tribe\Project\Blocks\Types\Section_Nav\Section_Nav;
use Tribe\Project\Blocks\Types\Spacer\Spacer;
use Tribe\Project\Blocks\Types\Stats\Stats;
use Tribe\Project\Blocks\Types\Tabs\Tabs;
@@ -48,6 +49,7 @@ public function define(): array {
DI\get( Logos::class ),
DI\get( Media_Text::class ),
DI\get( Quote::class ),
+ DI\get( Section_Nav::class ),
DI\get( Spacer::class ),
DI\get( Stats::class ),
DI\get( Tabs::class ),
diff --git a/wp-content/plugins/core/src/Blocks/Types/Section_Nav/Section_Nav.php b/wp-content/plugins/core/src/Blocks/Types/Section_Nav/Section_Nav.php
new file mode 100644
index 000000000..3ed13598a
--- /dev/null
+++ b/wp-content/plugins/core/src/Blocks/Types/Section_Nav/Section_Nav.php
@@ -0,0 +1,110 @@
+set_block( new Block( self::NAME, [
+ 'title' => __( 'Section Nav', 'tribe' ),
+ 'description' => __( 'A block to insert a nav menu within a page with several layout options.', 'tribe' ),
+ 'icon' => '',
+ 'keywords' => [ __( 'navigation', 'tribe' ), __( 'menu', 'tribe' ) ],
+ 'category' => 'layout',
+ 'supports' => [
+ 'align' => false,
+ 'anchor' => true,
+ 'html' => false,
+ ],
+ ] ) );
+ }
+
+ /**
+ * Register Fields for block
+ */
+ public function add_fields() {
+ //==========================================
+ // Content Fields
+ //==========================================
+ $this->add_section( new Field_Section( self::SECTION_CONTENT, __( 'Content', 'tribe' ), 'accordion' ) )
+ ->add_field( new Field( self::NAME . '_' . self::MENU, [
+ 'label' => __( 'Menu', 'tribe' ),
+ 'name' => self::MENU,
+ 'type' => 'menu-chooser',
+ ] )
+ )->add_field( new Field( self::NAME . '_' . self::MOBILE_LABEL, [
+ 'label' => __( 'Mobile Button Label', 'tribe' ),
+ 'name' => self::MOBILE_LABEL,
+ 'type' => 'text',
+ 'default_value' => esc_html__( 'In this section', 'tribe' ),
+ 'instructions' => esc_html__(
+ 'Label to apply to the nav open/close toggle for mobile viewports.',
+ 'tribe'
+ ),
+ ] )
+ )->add_field( new Field( self::NAME . '_' . self::MORE_LABEL, [
+ 'label' => __( 'More Button Label', 'tribe' ),
+ 'name' => self::MORE_LABEL,
+ 'type' => 'text',
+ 'default_value' => esc_html__( 'More', 'tribe' ),
+ 'instructions' => esc_html__(
+ 'Label to apply to the "more" drop-down menu toggle for desktop viewports.',
+ 'tribe'
+ ),
+ ] )
+ )->add_field( new Field( self::NAME . '_' . self::DESKTOP_LABEL, [
+ 'label' => __( 'Desktop Label', 'tribe' ),
+ 'name' => self::DESKTOP_LABEL,
+ 'type' => 'text',
+ 'instructions' => esc_html__(
+ 'An optional text label to display before the first menu item for desktop viewports.',
+ 'tribe'
+ ),
+ ] )
+ );
+
+ //==========================================
+ // Setting Fields
+ //==========================================
+ $this->add_section( new Field_Section( self::SECTION_SETTINGS, __( 'Settings', 'tribe' ), 'accordion' ) )
+ ->add_field( new Field( self::NAME . '_' . self::STICKY, [
+ 'label' => __( 'Sticky on Scroll?', 'tribe' ),
+ 'name' => self::STICKY,
+ 'type' => 'true_false',
+ 'ui' => 1,
+ ] )
+ )->add_field( new Field( self::NAME . '_' . self::MOBILE_INIT, [
+ 'label' => __( 'Default state on mobile', 'tribe' ),
+ 'name' => self::MOBILE_INIT,
+ 'type' => 'button_group',
+ 'choices' => [
+ self::MOBILE_INIT_CLOSED => esc_html__( 'Closed', 'tribe' ),
+ self::MOBILE_INIT_OPEN => esc_html__( 'Open', 'tribe' ),
+ ],
+ 'default_Value' => self::MOBILE_INIT_CLOSED,
+ ] )
+ );
+ }
+
+}
diff --git a/wp-content/plugins/core/src/Blocks/Types/Section_Nav/Section_Nav_Model.php b/wp-content/plugins/core/src/Blocks/Types/Section_Nav/Section_Nav_Model.php
new file mode 100644
index 000000000..be5805b8e
--- /dev/null
+++ b/wp-content/plugins/core/src/Blocks/Types/Section_Nav/Section_Nav_Model.php
@@ -0,0 +1,33 @@
+ $this->get_attrs(),
+ Section_Nav_Block_Controller::CLASSES => $this->get_classes(),
+ Section_Nav_Block_Controller::MENU_ID => $this->get( Section_Nav::MENU, 0 ),
+ Section_Nav_Block_Controller::MOBILE_LABEL => $this->get( Section_Nav::MOBILE_LABEL, esc_html__( 'In this section', 'tribe' ) ),
+ Section_Nav_Block_Controller::MORE_LABEL => $this->get( Section_Nav::MORE_LABEL, esc_html__( 'More', 'tribe' ) ),
+ Section_Nav_Block_Controller::DESKTOP_LABEL => $this->get( Section_Nav::DESKTOP_LABEL, '' ),
+ Section_Nav_Block_Controller::STICKY => $this->get( Section_Nav::STICKY, false ),
+ Section_Nav_Block_Controller::MOBILE_INIT_OPEN => $this->get_mobile_initial_state(),
+ ];
+ }
+
+ private function get_mobile_initial_state(): bool {
+ return $this->get( Section_Nav::MOBILE_INIT, Section_Nav::MOBILE_INIT_CLOSED ) === Section_Nav::MOBILE_INIT_OPEN;
+ }
+
+}
diff --git a/wp-content/plugins/core/src/Blocks/Types/Spacer/Spacer.php b/wp-content/plugins/core/src/Blocks/Types/Spacer/Spacer.php
index 4e01f324b..e79f3ceb5 100644
--- a/wp-content/plugins/core/src/Blocks/Types/Spacer/Spacer.php
+++ b/wp-content/plugins/core/src/Blocks/Types/Spacer/Spacer.php
@@ -10,9 +10,9 @@ class Spacer extends Block_Config {
public const NAME = 'spacer';
- public const SIZE = 'size';
- public const DEFAULT = 'default';
- public const LARGE = 'large';
+ public const SIZE = 'size';
+ public const DEFAULT = 'default';
+ public const LARGE = 'large';
public const DISPLAY_OPTIONS = 'display_options';
public const ALL_SCREENS = 'all-screens';
diff --git a/wp-content/plugins/core/src/Cache/Listener.php b/wp-content/plugins/core/src/Cache/Listener.php
index 8d240c5db..722d05f34 100644
--- a/wp-content/plugins/core/src/Cache/Listener.php
+++ b/wp-content/plugins/core/src/Cache/Listener.php
@@ -26,7 +26,7 @@ public function save_post( $post_id, $post ) {
*
* @param $p2p_id
*/
- public function p2p_created_connection($p2p_id) {
+ public function p2p_created_connection( $p2p_id ) {
$this->cache->flush_group( 'p2p_relationships' );
}
diff --git a/wp-content/plugins/core/src/Nav_Menus/Menu.php b/wp-content/plugins/core/src/Nav_Menus/Menu.php
index 653e67576..7d9fecac5 100644
--- a/wp-content/plugins/core/src/Nav_Menus/Menu.php
+++ b/wp-content/plugins/core/src/Nav_Menus/Menu.php
@@ -26,7 +26,7 @@ private function build_cache_key() {
$this->cache_key = $cache_key;
}
- private function get_html() {
+ private function get_html(): string {
$cache = new Cache();
$nav = $cache->get( $this->cache_key, 'tribe_nav_menu' );
if ( empty( $nav ) ) {
@@ -34,7 +34,7 @@ private function get_html() {
$cache->set( $this->cache_key, $nav, 'tribe_nav_menu' );
}
- return $nav;
+ return $nav ?: '';
}
/**
diff --git a/wp-content/plugins/core/src/Nav_Menus/Nav_Attribute_Filters.php b/wp-content/plugins/core/src/Nav_Menus/Nav_Attribute_Filters.php
index 2b8fa6d31..c9e23218f 100644
--- a/wp-content/plugins/core/src/Nav_Menus/Nav_Attribute_Filters.php
+++ b/wp-content/plugins/core/src/Nav_Menus/Nav_Attribute_Filters.php
@@ -42,6 +42,10 @@ public function customize_nav_item_id( string $menu_id, object $item, stdClass $
* @filter nav_menu_css_class
*/
public function customize_nav_item_classes( array $classes, object $item, stdClass $args, int $depth ): array {
+ if ( empty( $args->theme_location ) ) {
+ return $classes;
+ }
+
$theme_location = $args->theme_location;
$classes[] = $theme_location . '__list-item';
@@ -105,6 +109,10 @@ public function customize_nav_item_classes( array $classes, object $item, stdCla
* @filter nav_menu_link_attributes
*/
public function customize_nav_item_anchor_atts( array $atts, object $item, stdClass $args, int $depth ): array {
+ if ( empty( $args->theme_location ) ) {
+ return $atts;
+ }
+
$theme_location = $args->theme_location;
$classes = [
diff --git a/wp-content/plugins/core/src/Theme/Pagination_Util.php b/wp-content/plugins/core/src/Theme/Pagination_Util.php
index 4d16bfecd..5b9bc5cc9 100644
--- a/wp-content/plugins/core/src/Theme/Pagination_Util.php
+++ b/wp-content/plugins/core/src/Theme/Pagination_Util.php
@@ -107,7 +107,7 @@ public function numbers( int $links_offset = 0, bool $show_next_prev = true, boo
*
* @return array
*/
- protected function get_link_array( string $url, string $label, array $classes = [], bool $active = false, bool $next = false, bool $prev = false ): array {
+ protected function get_link_array( string $url, string $label, array $classes = [], bool $active = false, bool $next = false, bool $prev = false ): array {
return [
'url' => $url,
'label' => $label,
diff --git a/wp-content/themes/core/assets/css/src/admin/block-editor.pcss b/wp-content/themes/core/assets/css/src/admin/block-editor.pcss
index c95166c5a..c21908b36 100644
--- a/wp-content/themes/core/assets/css/src/admin/block-editor.pcss
+++ b/wp-content/themes/core/assets/css/src/admin/block-editor.pcss
@@ -25,6 +25,7 @@
@import "../theme/media/all.pcss";
@import "../theme/spacing/all.pcss";
@import "../theme/typography/all.pcss";
+
@import-glob "../theme/**/block-editor.pcss";
/* All Theme Components */
@@ -34,4 +35,3 @@
/* All Integrations */
@import-glob "../../../../integrations/**/index.pcss";
@import-glob "../../../../integrations/**/block-editor.pcss";
-
diff --git a/wp-content/themes/core/assets/css/src/theme/color/_variables.pcss b/wp-content/themes/core/assets/css/src/theme/color/_variables.pcss
index a2dfe1711..1b6314ab0 100644
--- a/wp-content/themes/core/assets/css/src/theme/color/_variables.pcss
+++ b/wp-content/themes/core/assets/css/src/theme/color/_variables.pcss
@@ -70,7 +70,7 @@
* Borders
* ----------------------------------------------------------------------------- */
- --color-border: var(--color-grey-light);
+ --color-border: var(--color-neutral-10);
/* -----------------------------------------------------------------------------
* Alerts
diff --git a/wp-content/themes/core/assets/css/src/theme/typography/anchors.pcss b/wp-content/themes/core/assets/css/src/theme/typography/anchors.pcss
index 8caf206fc..433a7d941 100644
--- a/wp-content/themes/core/assets/css/src/theme/typography/anchors.pcss
+++ b/wp-content/themes/core/assets/css/src/theme/typography/anchors.pcss
@@ -33,20 +33,16 @@ a {
.anchor,
.t-sink a {
- color: var(--color-text);
+ color: var(--color-link);
text-decoration: underline;
- font-weight: 700;
- text-decoration-color: var(--color-link-focus);
&:hover {
color: var(--color-link-hover);
- text-decoration-color: inherit;
}
&:focus {
color: var(--color-link-focus);
outline: none;
- text-decoration-color: inherit;
}
/* CASE: light theme */
diff --git a/wp-content/themes/core/assets/js/src/admin/editor/components.js b/wp-content/themes/core/assets/js/src/admin/editor/components.js
index 49ce52892..f77880e14 100644
--- a/wp-content/themes/core/assets/js/src/admin/editor/components.js
+++ b/wp-content/themes/core/assets/js/src/admin/editor/components.js
@@ -4,15 +4,23 @@
* @description Initializes theme component JS in the block editor context.
*/
-import * as tools from 'utils/tools';
+import sectionNav from 'components/section_nav';
+import slider from 'components/slider';
-const init = () => {
- if ( tools.getNodes( '[data-js="c-slider"]', false, document, true )[ 0 ] ) {
- import( 'components/slider' /* webpackChunkName:"editor-slider" */ ).then( ( module ) => {
- module.default();
- } );
+const initComponents = () => {
+ sectionNav();
+ slider();
+};
+
+const bindEvents = () => {
+ if ( window.acf ) {
+ window.acf.addAction( 'render_block_preview', initComponents );
}
+};
+const init = () => {
+ bindEvents();
+ initComponents();
console.info( 'SquareOne Admin: Initialized all components.' );
};
diff --git a/wp-content/themes/core/assets/js/src/theme/core/components.js b/wp-content/themes/core/assets/js/src/theme/core/components.js
index 594943b08..4e5e0f23c 100644
--- a/wp-content/themes/core/assets/js/src/theme/core/components.js
+++ b/wp-content/themes/core/assets/js/src/theme/core/components.js
@@ -8,6 +8,7 @@ import accordion from 'components/accordion';
import card from 'components/card';
import comments from 'components/comments';
import navigation from 'components/navigation';
+import sectionNav from 'components/section_nav';
import share from 'components/share';
import slider from 'components/slider';
import tabs from 'components/tabs';
@@ -21,6 +22,7 @@ const init = () => {
card();
comments();
navigation();
+ sectionNav();
share();
slider();
tabs();
diff --git a/wp-content/themes/core/blocks/sectionnav/sectionnav.php b/wp-content/themes/core/blocks/sectionnav/sectionnav.php
new file mode 100644
index 000000000..da86058f8
--- /dev/null
+++ b/wp-content/themes/core/blocks/sectionnav/sectionnav.php
@@ -0,0 +1,8 @@
+get_data() );
diff --git a/wp-content/themes/core/components/blocks/content_loop/Content_Loop_Controller.php b/wp-content/themes/core/components/blocks/content_loop/Content_Loop_Controller.php
index 959279559..f2afc8281 100644
--- a/wp-content/themes/core/components/blocks/content_loop/Content_Loop_Controller.php
+++ b/wp-content/themes/core/components/blocks/content_loop/Content_Loop_Controller.php
@@ -150,7 +150,7 @@ public function get_posts_card_args( string $layout = Card_Controller::STYLE_PLA
// CASE: If not Inline Card Style and is the featured layout
- if ( $layout !== Card_Controller::STYLE_INLINE || $this->layout !== 'layout_feature') {
+ if ( $layout !== Card_Controller::STYLE_INLINE || $this->layout !== 'layout_feature' ) {
$card_cta =
[
Link_Controller::CONTENT => __( 'Read More', 'tribe' ),
diff --git a/wp-content/themes/core/components/blocks/section_nav/Section_Nav_Block_Controller.php b/wp-content/themes/core/components/blocks/section_nav/Section_Nav_Block_Controller.php
new file mode 100644
index 000000000..30cefb697
--- /dev/null
+++ b/wp-content/themes/core/components/blocks/section_nav/Section_Nav_Block_Controller.php
@@ -0,0 +1,101 @@
+parse_args( $args );
+
+ $this->attrs = (array) $args[ self::ATTRS ];
+ $this->classes = (array) $args[ self::CLASSES ];
+ $this->container_classes = (array) $args[ self::CONTAINER_CLASSES ];
+ $this->menu_id = (int) $args[ self::MENU_ID ];
+ $this->mobile_label = (string) $args[ self::MOBILE_LABEL ];
+ $this->more_label = (string) $args[ self::MORE_LABEL ];
+ $this->desktop_label = (string) $args[ self::DESKTOP_LABEL ];
+ $this->sticky = (bool) $args[ self::STICKY ];
+ $this->mobile_init_open = (bool) $args[ self::MOBILE_INIT_OPEN ];
+ }
+
+ /**
+ * @return array
+ */
+ public function get_section_nav_args(): array {
+ return [
+ Section_Nav_Controller::ATTRS => $this->attrs,
+ Section_Nav_Controller::CLASSES => $this->classes,
+ Section_Nav_Controller::CONTAINER_CLASSES => $this->container_classes,
+ Section_Nav_Controller::MENU => $this->menu_id,
+ Section_Nav_Controller::MOBILE_LABEL => $this->mobile_label,
+ Section_Nav_Controller::MORE_LABEL => $this->more_label,
+ Section_Nav_Controller::DESKTOP_LABEL => $this->desktop_label,
+ Section_Nav_Controller::STICKY => $this->sticky,
+ Section_Nav_Controller::MOBILE_INIT_OPEN => $this->mobile_init_open,
+
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ protected function defaults(): array {
+ return [
+ self::ATTRS => [],
+ self::CLASSES => [],
+ self::CONTAINER_CLASSES => [],
+ self::MENU_ID => 0,
+ self::MOBILE_LABEL => esc_html__( 'In this section', 'tribe' ),
+ self::MORE_LABEL => esc_html__( 'More', 'tribe' ),
+ self::DESKTOP_LABEL => '',
+ self::STICKY => false,
+ self::MOBILE_INIT_OPEN => false,
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ protected function required(): array {
+ return [
+ self::CLASSES => [ 'c-block', 'b-section-nav' ],
+ self::CONTAINER_CLASSES => [ 'b-section-nav__container', 'l-container' ],
+ ];
+ }
+
+}
diff --git a/wp-content/themes/core/components/blocks/section_nav/css/section_nav.pcss b/wp-content/themes/core/components/blocks/section_nav/css/section_nav.pcss
new file mode 100644
index 000000000..49f8f1bc6
--- /dev/null
+++ b/wp-content/themes/core/components/blocks/section_nav/css/section_nav.pcss
@@ -0,0 +1,17 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Component: Section Nav
+ *
+ * ----------------------------------------------------------------------------- */
+
+.b-section-nav {
+ /** Dupes the width values from `l-sink`.
+ * This is b/c the section nav is both an block and sticky element.
+ */
+ width: calc(100% - 2 * var(--grid-gutter-small));
+ margin: var(--spacer-40) auto;
+
+ @media (--viewport-medium) {
+ width: calc(100% - 2 * var(--grid-gutter));
+ }
+}
diff --git a/wp-content/themes/core/components/blocks/section_nav/index.pcss b/wp-content/themes/core/components/blocks/section_nav/index.pcss
new file mode 100644
index 000000000..30f0e4aa5
--- /dev/null
+++ b/wp-content/themes/core/components/blocks/section_nav/index.pcss
@@ -0,0 +1,10 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Component: Section Nav
+ *
+ * This file is just a clearing-house, see the css directory
+ * and edit the source files found there.
+ *
+ * ----------------------------------------------------------------------------- */
+
+@import "css/section_nav.pcss";
diff --git a/wp-content/themes/core/components/blocks/section_nav/section_nav.php b/wp-content/themes/core/components/blocks/section_nav/section_nav.php
new file mode 100644
index 000000000..7e080030c
--- /dev/null
+++ b/wp-content/themes/core/components/blocks/section_nav/section_nav.php
@@ -0,0 +1,22 @@
+get_section_nav_args()
+);
diff --git a/wp-content/themes/core/components/header/subheader/Subheader_Controller.php b/wp-content/themes/core/components/header/subheader/Subheader_Controller.php
index 54089ae0a..2e2981add 100644
--- a/wp-content/themes/core/components/header/subheader/Subheader_Controller.php
+++ b/wp-content/themes/core/components/header/subheader/Subheader_Controller.php
@@ -110,7 +110,7 @@ public function get_description_args(): array {
}
public function get_image_args(): array {
- if ( empty( $this->hero_image_id ) ) {
+ if ( empty( $this->hero_image_id ) ) {
return [];
}
diff --git a/wp-content/themes/core/components/navigation/Navigation_Controller.php b/wp-content/themes/core/components/navigation/Navigation_Controller.php
index f02a586fc..1d8a31b9b 100644
--- a/wp-content/themes/core/components/navigation/Navigation_Controller.php
+++ b/wp-content/themes/core/components/navigation/Navigation_Controller.php
@@ -8,75 +8,122 @@
class Navigation_Controller extends Abstract_Controller {
- public const LOCATION = 'location';
- public const CLASSES = 'classes';
public const ATTRS = 'attrs';
+ public const CLASSES = 'classes';
+ public const MENU = 'menu';
+ public const MENU_LOCATION = 'menu_location';
+ public const NAV_LIST_ATTRS = 'nav_list_attrs';
public const NAV_LIST_CLASSES = 'nav_list_classes';
public const NAV_MENU_ARGS = 'nav_menu_args';
private const DEFAULT_NAV_MENU_ARGS = [
- 'container' => false,
- 'menu_class' => '',
- 'menu_id' => '',
- 'depth' => 1,
- 'items_wrap' => '%3$s',
- 'fallback_cb' => false,
+ 'menu' => null,
+ 'container' => false,
+ 'menu_class' => '',
+ 'menu_id' => '',
+ 'depth' => 1,
+ 'items_wrap' => '%3$s',
+ 'fallback_cb' => false,
+ 'theme_location' => '',
];
- private string $location;
- private array $classes;
+ /**
+ * @var array
+ */
private array $attrs;
+
+ /**
+ * @var array
+ */
+ private array $classes;
+
+ /**
+ * @var int|string|\WP_Term
+ */
+ private $menu;
+
+ /**
+ * @var string
+ */
+ private string $menu_location;
+
+ /**
+ * @var array
+ */
+ private array $nav_list_attrs;
+
+ /**
+ * @var array
+ */
private array $nav_list_classes;
+
+ /**
+ * @var array
+ */
private array $nav_menu_args;
public function __construct( array $args = [] ) {
$args = $this->parse_args( $args );
- $this->location = (string) $args[ self::LOCATION ];
- $this->classes = (array) $args[ self::CLASSES ];
$this->attrs = (array) $args[ self::ATTRS ];
+ $this->classes = (array) $args[ self::CLASSES ];
+ $this->menu = $args[ self::MENU ];
+ $this->menu_location = (string) $args[ self::MENU_LOCATION ];
+ $this->nav_list_attrs = (array) $args[ self::NAV_LIST_ATTRS ];
$this->nav_list_classes = (array) $args[ self::NAV_LIST_CLASSES ];
$this->nav_menu_args = $this->parse_menu_args( $args[ self::NAV_MENU_ARGS ] );
}
- protected function defaults(): array {
- return [
- self::LOCATION => '',
- self::CLASSES => [ 'c-nav' ],
- self::ATTRS => [],
- self::NAV_LIST_CLASSES => [ 'c-nav__list' ],
- self::NAV_MENU_ARGS => [],
- ];
- }
-
- private function parse_menu_args( $menu_args ): array {
- $menu_args['theme_location'] = $this->location;
-
- return wp_parse_args( $menu_args, self::DEFAULT_NAV_MENU_ARGS );
- }
-
- public function has_menu(): bool {
- return has_nav_menu( $this->location );
+ public function get_attrs(): string {
+ return Markup_Utils::concat_attrs( $this->attrs );
}
public function get_classes(): string {
return Markup_Utils::class_attribute( $this->classes );
}
- public function get_attrs(): string {
- return Markup_Utils::concat_attrs( $this->attrs );
+ public function get_nav_list_attrs(): string {
+ return Markup_Utils::concat_attrs( $this->nav_list_attrs );
}
public function get_nav_list_classes(): string {
return Markup_Utils::class_attribute( $this->nav_list_classes );
}
+ /**
+ * Returns true if either $menu_id or $menu_location are valid WordPress menus.
+ *
+ * @return bool
+ */
+ public function has_menu(): bool {
+ return is_nav_menu( $this->menu ) || has_nav_menu( $this->menu_location );
+ }
+
public function get_menu(): string {
- if ( empty( $this->location ) ) {
+ if ( ! $this->has_menu() ) {
return '';
}
return Menu::menu( $this->nav_menu_args );
}
+ protected function defaults(): array {
+ return [
+ self::ATTRS => [],
+ self::CLASSES => [ 'c-nav' ],
+ self::MENU => null,
+ self::MENU_LOCATION => '',
+ self::NAV_LIST_ATTRS => [],
+ self::NAV_LIST_CLASSES => [ 'c-nav__list' ],
+ self::NAV_MENU_ARGS => [],
+ ];
+ }
+
+ private function parse_menu_args( $menu_args ): array {
+ $menu_args['menu'] = $this->menu;
+ $menu_args['theme_location'] = $this->menu_location;
+
+ return wp_parse_args( $menu_args, self::DEFAULT_NAV_MENU_ARGS );
+ }
+
}
diff --git a/wp-content/themes/core/components/navigation/navigation.php b/wp-content/themes/core/components/navigation/navigation.php
index 2a3bb8b73..39fe6e89a 100644
--- a/wp-content/themes/core/components/navigation/navigation.php
+++ b/wp-content/themes/core/components/navigation/navigation.php
@@ -14,8 +14,7 @@
?>
-
diff --git a/wp-content/themes/core/components/section_nav/Section_Nav_Controller.php b/wp-content/themes/core/components/section_nav/Section_Nav_Controller.php
new file mode 100644
index 000000000..b7e284b9a
--- /dev/null
+++ b/wp-content/themes/core/components/section_nav/Section_Nav_Controller.php
@@ -0,0 +1,189 @@
+unique_id = uniqid();
+ $this->container_id = sprintf( 'c-section-nav__container--%s', $this->unique_id );
+ $this->more_id = sprintf( 'c-section-nav__more--%s', $this->unique_id );
+
+ $args = $this->parse_args( $args );
+
+ $this->attrs = (array) $args[ self::ATTRS ];
+ $this->classes = (array) $args[ self::CLASSES ];
+ $this->container_attrs = (array) $args[ self::CONTAINER_ATTRS ];
+ $this->container_classes = (array) $args[ self::CONTAINER_CLASSES ];
+ $this->menu = $args[ self::MENU ];
+ $this->mobile_label = (string) $args[ self::MOBILE_LABEL ];
+ $this->desktop_label = (string) $args[ self::DESKTOP_LABEL ];
+ $this->more_label = (string) $args[ self::MORE_LABEL ];
+ $this->sticky = (bool) $args[ self::STICKY ];
+ $this->mobile_init_open = (bool) $args[ self::MOBILE_INIT_OPEN ];
+ }
+
+ public function get_attrs(): string {
+ if ( $this->mobile_init_open ) {
+ $this->attrs['data-init-open'] = 'true';
+ }
+
+ return Markup_Utils::concat_attrs( $this->attrs );
+ }
+
+ public function get_classes(): string {
+ if ( $this->sticky ) {
+ $this->classes[] = 'c-section-nav--sticky';
+ }
+
+ if ( $this->mobile_init_open ) {
+ $this->classes[] = 'c-section-nav--visible';
+ }
+
+ return Markup_Utils::class_attribute( $this->classes );
+ }
+
+ public function get_container_attrs(): string {
+ return Markup_Utils::concat_attrs( $this->container_attrs );
+ }
+
+ public function get_container_classes(): string {
+ return Markup_Utils::class_attribute( $this->container_classes );
+ }
+
+ public function get_more_attrs(): string {
+ return Markup_Utils::concat_attrs( [
+ 'id' => $this->more_id,
+ 'data-js' => 'c-section-nav__more',
+ ] );
+ }
+
+ public function get_more_classes(): string {
+ return Markup_Utils::class_attribute( [ 'c-section-nav__more' ] );
+ }
+
+ public function get_more_toggle(): Deferred_Component {
+ return defer_template_part( 'components/button/button', null, [
+ Button_Controller::ATTRS => [
+ 'data-js' => 'c-section-nav__toggle--more',
+ 'aria-controls' => $this->more_id,
+ 'aria-expanded' => 'false',
+ 'aria-haspopup' => 'true',
+ ],
+ Button_Controller::CLASSES => [ 'c-section-nav__toggle', 'c-section-nav__toggle--more' ],
+ Button_Controller::CONTENT => esc_html( $this->more_label ),
+ ] );
+ }
+
+ public function get_mobile_toggle(): Deferred_Component {
+ return defer_template_part( 'components/button/button', null, [
+ Button_Controller::ATTRS => [
+ 'data-js' => 'c-section-nav__toggle--mobile',
+ 'aria-controls' => $this->container_id,
+ 'aria-expanded' => $this->mobile_init_open ? 'true' : 'false',
+ 'aria-haspopup' => 'true',
+ ],
+ Button_Controller::CLASSES => [ 'c-section-nav__toggle', 'c-section-nav__toggle--mobile' ],
+ Button_Controller::CONTENT => esc_html( $this->mobile_label ),
+ ] );
+ }
+
+ public function get_desktop_label(): Deferred_Component {
+ return defer_template_part( 'components/text/text', null, [
+ Text_Controller::CLASSES => [ 'c-section-nav__label--desktop' ],
+ Text_Controller::CONTENT => $this->desktop_label,
+ ] );
+ }
+
+ public function get_nav_menu(): Deferred_Component {
+ return defer_template_part( 'components/navigation/navigation', null, [
+ Navigation_Controller::MENU => $this->menu,
+ Navigation_Controller::MENU_LOCATION => 'section-nav',
+ Navigation_Controller::NAV_LIST_CLASSES => [ 'c-section-nav__list' ],
+ Navigation_Controller::NAV_LIST_ATTRS => [ 'data-js' => 'c-section-nav__list' ],
+ ] );
+ }
+
+ protected function defaults(): array {
+ return [
+ self::ATTRS => [],
+ self::CLASSES => [],
+ self::CONTAINER_ATTRS => [],
+ self::CONTAINER_CLASSES => [],
+ self::MENU => 0,
+ self::MOBILE_LABEL => esc_html__( 'In this section', 'tribe' ),
+ self::DESKTOP_LABEL => '',
+ self::MORE_LABEL => esc_html__( 'More', 'tribe' ),
+ self::STICKY => false,
+ self::MOBILE_INIT_OPEN => false,
+ ];
+ }
+
+ protected function required(): array {
+ return [
+ self::ATTRS => [
+ 'id' => sprintf( 'c-section-nav--%s', $this->unique_id ),
+ 'data-js' => 'c-section-nav',
+ ],
+ self::CLASSES => [ 'c-section-nav' ],
+ self::CONTAINER_ATTRS => [
+ 'id' => $this->container_id,
+ 'data-js' => 'c-section-nav__container',
+ ],
+ self::CONTAINER_CLASSES => [ 'c-section-nav__container' ],
+ ];
+ }
+
+}
diff --git a/wp-content/themes/core/components/section_nav/css/section-nav.pcss b/wp-content/themes/core/components/section_nav/css/section-nav.pcss
new file mode 100644
index 000000000..31e57ff99
--- /dev/null
+++ b/wp-content/themes/core/components/section_nav/css/section-nav.pcss
@@ -0,0 +1,266 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Component: Section Nav
+ *
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav {
+ border: 1px solid var(--color-border);
+
+ @media (--viewport-small) {
+ border: none;
+ }
+
+ /* CASE: position this section nav sticky on scroll. */
+ &.c-section-nav--sticky {
+ position: sticky;
+ top: var(--spacer-60); /* Be sure to adjust the intObserverOpts rootMargin value in `section-nav.js`. */
+ background: var(--color-bgd-content);
+
+ @media (--viewport-small) {
+ background: transparent;
+ }
+ }
+
+ /* CASE: The section nav is "stuck" while scrolling. */
+ &.c-section-nav--stuck {
+ box-shadow: var(--box-shadow-10);
+
+ @media (--viewport-small) {
+ box-shadow: none;
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav Toggles
+ *
+ * Applies base styling for both the mobile menu button and
+ * desktop "more" menu button.
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__toggle {
+ @mixin a-btn-reset;
+
+ position: relative;
+
+ &:after {
+ @mixin icon;
+
+ content: var(--icon-chevron-down);
+ position: absolute;
+ transition: var(--transition);
+ }
+
+ &:focus,
+ &:hover {
+ text-decoration: underline;
+ }
+
+ /* CASE: Toggle active */
+ &[aria-expanded="true"] {
+
+ &:after {
+ transform: rotate(180deg);
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav Mobile Toggle Button
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__toggle--mobile {
+ display: block;
+ width: 100%;
+ padding: var(--spacer-20) var(--spacer-30);
+ text-align: left;
+ line-height: 1.5;
+ letter-spacing: 0;
+
+ @media (--viewport-small) {
+ display: none;
+ }
+
+ &:after {
+ top: var(--spacer-20);
+ right: var(--spacer-30);
+ font-size: 24px;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav Container
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__container {
+ display: none;
+
+ @media (--viewport-small) {
+ overflow: hidden;
+ }
+
+ /* CASE: the more menu is in use. */
+ .c-section-nav--more-initialized & {
+ overflow: visible;
+ }
+
+ /* CASE: The mobile menu is open or it's showing the desktop layout. */
+ .c-section-nav--visible & {
+ display: block;
+ }
+
+ /* CASE: position this section nav sticky on scroll. */
+ .c-section-nav--sticky & {
+ transition: var(--transition);
+
+ @media (--viewport-small) {
+ padding: var(--spacer-20) var(--grid-gutter-small);
+ border: 1px solid var(--color-border);
+ background: var(--color-bgd-content);
+ }
+ }
+
+ /* CASE: The section nav is "stuck" while scrolling. */
+ .c-section-nav--stuck & {
+ @media (--viewport-small) {
+ box-shadow: var(--box-shadow-10);
+ }
+ }
+
+ /* CASE: Section Nav *NOT* Sticky
+ /* Remove the padding added by `l-container` to keep text justified when there's not a "sticky" wrapper. */
+ .c-section-nav:not(.c-section-nav--sticky) & {
+ @media (--viewport-small) {
+ padding-left: 0;
+ padding-right: 0;
+ }
+ }
+}
+
+.c-section-nav__inner {
+ display: flex;
+ flex-flow: row nowrap;
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav Desktop Label (optional)
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__label--desktop {
+ display: none;
+ padding-right: var(--spacer-50);
+ white-space: nowrap;
+ font-weight: 700;
+
+ @media (--viewport-small) {
+ display: block;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav List
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__list {
+ padding: 0 0 var(--spacer-20);
+
+ @media (--viewport-small) {
+ display: flex;
+ flex-flow: row nowrap;
+ padding: 0;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav List Items
+ * ----------------------------------------------------------------------------- */
+
+.section-nav__list-item {
+
+ & ~ li {
+ @media (--viewport-small) {
+ margin-left: var(--spacer-50);
+ }
+ }
+
+ /* CASE: items within the "More" menu */
+ .c-section-nav__list--more & {
+ margin: 0;
+
+ & ~ li {
+ margin-top: 12px;
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav Actions (links)
+ *
+ * `a` selector necessary to override default t-sink link styles.
+ * ----------------------------------------------------------------------------- */
+
+a.section-nav__action {
+ display: inline-block;
+ padding: 6px 0;
+ text-decoration: none;
+
+ @media (--viewport-small) {
+ padding: 0;
+ white-space: nowrap;
+ }
+
+ &:focus,
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav "More" list item
+ * ----------------------------------------------------------------------------- */
+
+.section-nav__list-item--more {
+ display: none;
+ position: relative;
+
+ /* CASE: the more menu is active. */
+ .c-section-nav--more-initialized & {
+ display: flex;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav "More" Toggle Button
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__toggle--more {
+ padding-right: 1.5em;
+ white-space: nowrap;
+
+ &:after {
+ right: 0;
+ font-size: 1.25em;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Section Nav "More" Container
+ * ----------------------------------------------------------------------------- */
+
+.c-section-nav__more {
+ display: none;
+ position: absolute;
+ z-index: 1;
+ top: calc(100% + var(--spacer-10));
+ right: calc(-1 * var(--spacer-10));
+ padding: var(--spacer-30) var(--spacer-40);
+ background: var(--color-bgd-content);
+ border: 1px solid var(--color-border);
+
+ /* CASE: More menu active */
+ .c-section-nav--more-active & {
+ display: block;
+ box-shadow: var(--box-shadow-10);
+ }
+}
diff --git a/wp-content/themes/core/components/section_nav/index.js b/wp-content/themes/core/components/section_nav/index.js
new file mode 100644
index 000000000..a3b1df2e8
--- /dev/null
+++ b/wp-content/themes/core/components/section_nav/index.js
@@ -0,0 +1,20 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Component: Section Nav
+ *
+ * This file is just a clearing-house, see the css directory
+ * and edit the source files found there.
+ *
+ * ----------------------------------------------------------------------------- */
+
+const init = () => {
+ const sectionNavs = document.querySelectorAll( '[data-js="c-section-nav"]' );
+
+ if ( sectionNavs.length ) {
+ import( './js/section-nav' /* webpackChunkName:"sectionNav" */ ).then( ( module ) => {
+ module.default( sectionNavs );
+ } );
+ }
+};
+
+export default init;
diff --git a/wp-content/themes/core/components/section_nav/index.pcss b/wp-content/themes/core/components/section_nav/index.pcss
new file mode 100644
index 000000000..c45e797d7
--- /dev/null
+++ b/wp-content/themes/core/components/section_nav/index.pcss
@@ -0,0 +1,10 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Component: Section Nav
+ *
+ * This file is just a clearing-house, see the css directory
+ * and edit the source files found there.
+ *
+ * ----------------------------------------------------------------------------- */
+
+@import "css/section-nav.pcss";
diff --git a/wp-content/themes/core/components/section_nav/js/section-nav.js b/wp-content/themes/core/components/section_nav/js/section-nav.js
new file mode 100644
index 000000000..18db8ad23
--- /dev/null
+++ b/wp-content/themes/core/components/section_nav/js/section-nav.js
@@ -0,0 +1,428 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Component: Section Nav
+ *
+ * ----------------------------------------------------------------------------- */
+
+import delegate from 'delegate';
+
+import { on } from 'utils/events';
+import state from 'config/state';
+import adminState from '../../../assets/js/src/admin/config/state';
+
+const MOBILE_BREAKPOINT = 600;
+
+const intObserverOpts = {
+ threshold: 1,
+ rootMargin: '-49px 0px 0px 0px', /* Set to 1px LESS than the `top: Npx` value applied to `.c-section-nav` when sticky. */
+};
+
+const el = {
+ container: document.querySelector( '[data-js="site-wrap"]' ) ?? document.querySelector( '.is-root-container.block-editor-block-list__layout' ),
+};
+
+const componentState = {
+ vWidth: state.v_width,
+ isMobile: state.v_width < MOBILE_BREAKPOINT,
+};
+
+/**
+ * Close a particular More menu.
+ *
+ * @param sectionNav
+ */
+const closeMoreMenu = ( sectionNav ) => {
+ const toggle = sectionNav.querySelector( '[data-js="c-section-nav__toggle--more"]' );
+
+ // Bail if no more menu.
+ if ( ! toggle ) {
+ return;
+ }
+
+ // Move focus to the sectionNav's toggle if it's currently inside the nav being closed.
+ const moreListItem = sectionNav.querySelector( '[data-js="c-section-nav__list-item--more"]' );
+
+ if ( document.activeElement.closest( '[data-js="c-section-nav__list-item--more"]' ) === moreListItem ) {
+ toggle.focus();
+ }
+
+ sectionNav.classList.remove( 'c-section-nav--more-active' );
+ toggle.setAttribute( 'aria-expanded', 'false' );
+};
+
+/**
+ * Close all the Section Nav More menus.
+ */
+const closeAllMoreMenus = () => el.sectionNavs.forEach( sectionNav => closeMoreMenu( sectionNav ) );
+
+/**
+ * Open a particular More menu.
+ *
+ * @param sectionNav
+ */
+const openMoreMenu = ( sectionNav ) => {
+ const toggle = sectionNav.querySelector( '[data-js="c-section-nav__toggle--more"]' );
+
+ closeAllMoreMenus();
+ sectionNav.classList.add( 'c-section-nav--more-active' );
+ toggle.setAttribute( 'aria-expanded', 'true' );
+};
+
+/**
+ * Handle click events for Section Nav More menus.
+ *
+ * @param e
+ */
+const toggleMoreMenu = ( e ) => {
+ const sectionNav = e.target.closest( '[data-js="c-section-nav"]' );
+ e.target.getAttribute( 'aria-expanded' ) === 'false' ? openMoreMenu( sectionNav ) : closeMoreMenu( sectionNav );
+};
+
+/**
+ * Open a particular Section Nav menu on mobile.
+ *
+ * @param sectionNav
+ */
+const openSectionNav = ( sectionNav ) => {
+ const toggle = sectionNav.querySelector( '[data-js="c-section-nav__toggle--mobile"]' );
+
+ sectionNav.classList.add( 'c-section-nav--visible' );
+ toggle.setAttribute( 'aria-expanded', 'true' );
+};
+
+/**
+ * Close a particular Section Nav menu on mobile.
+ *
+ * @param sectionNav
+ * @param useDefaultState
+ */
+const closeSectionNav = ( sectionNav, useDefaultState = true ) => {
+ // Bail early if this nav defaults to open and this close event was not a direct user action.
+ if ( useDefaultState && sectionNav.dataset.initOpen ) {
+ return;
+ }
+
+ const toggle = sectionNav.querySelector( '[data-js="c-section-nav__toggle--mobile"]' );
+
+ // Move focus to the sectionNav's toggle if it's currently inside the nav being closed.
+ if ( document.activeElement.closest( '[data-js="c-section-nav"]' ) === sectionNav ) {
+ toggle.focus();
+ }
+
+ sectionNav.classList.remove( 'c-section-nav--visible' );
+ toggle.setAttribute( 'aria-expanded', 'false' );
+};
+
+/**
+ * Toggle all section Nav menus.
+ *
+ * @param closeNavs
+ */
+const toggleAllSectionNavs = ( closeNavs = 'close' ) => {
+ el.sectionNavs.forEach( ( sectionNav ) => {
+ closeNavs === 'close' ? closeSectionNav( sectionNav ) : openSectionNav( sectionNav );
+ } );
+};
+
+/**
+ * Handle click events for Section Nav menus on mobile.
+ *
+ * @param e
+ */
+const toggleSectionNav = ( e ) => {
+ const sectionNav = e.target.closest( '[data-js="c-section-nav"]' );
+ e.target.getAttribute( 'aria-expanded' ) === 'false' ? openSectionNav( sectionNav ) : closeSectionNav( sectionNav, false );
+};
+
+/**
+ * Reset the nav to its default state
+ *
+ * @param sectionNav
+ */
+const resetNav = ( sectionNav ) => {
+ // Reset the respective classes
+ sectionNav.classList.remove( 'c-section-nav--more-initialized' );
+
+ if ( ! componentState.isMobile ) {
+ sectionNav.classList.add( 'c-section-nav--visible' );
+ }
+
+ // Bail if there's no "more" list item
+ if ( ! sectionNav.querySelector( '[data-js="c-section-nav__list-item--more"]' ) ) {
+ return;
+ }
+
+ // Close the more menu, if it's open.
+ closeMoreMenu( sectionNav );
+
+ const sectionNavList = sectionNav.querySelector( '[data-js="c-section-nav__list"]' );
+ const moreListItem = sectionNavList.querySelector( '[data-js="c-section-nav__list-item--more"]' );
+ const moreList = sectionNavList.querySelector( '[data-js="c-section-nav__list--more"]' );
+ const items = moreList.querySelectorAll( 'li' );
+
+ // Move all the items back to the top-level menu
+ items.forEach( item => sectionNavList.insertBefore( item, moreListItem ) );
+};
+
+/**
+ * Injects the more menu markup from the respective JS into the section nav list.
+ *
+ * @param sectionNav
+ */
+const injectMoreMenu = ( sectionNav ) => {
+ const template = sectionNav.querySelector( '[data-template="more"]' );
+ const sectionNavList = sectionNav.querySelector( '[data-js="c-section-nav__list"]' );
+ const moreMenu = document.importNode( template.content, true );
+ sectionNavList.append( moreMenu );
+};
+
+/**
+ * Check if the nav fits
+ *
+ * If the scroll width of the inner wrapper within the component is less than or equal to
+ * the offset width of the inner wrapper, then the nav fits.
+ *
+ * @param sectionNav
+ * @returns {boolean}
+ */
+const navFits = ( sectionNav ) => {
+ const inner = sectionNav.querySelector( '[data-js="c-section-nav__inner"]' );
+ return inner.offsetWidth >= inner.scrollWidth;
+};
+
+/**
+ * Loop through all the menu items and file them into the More menu until the nav fits.
+ *
+ * @param sectionNav
+ */
+const fileItems = ( sectionNav ) => {
+ sectionNav.classList.add( 'c-section-nav--more-initialized' );
+
+ if ( ! sectionNav.querySelector( '[data-js="c-section-nav__list--more"]' ) ) {
+ injectMoreMenu( sectionNav );
+ }
+
+ const sectionNavList = sectionNav.querySelector( '[data-js="c-section-nav__list"]' );
+ const moreList = sectionNavList.querySelector( '[data-js="c-section-nav__list--more"]' );
+
+ do {
+ // Grab the list item just before the "More" item
+ const lastItem = sectionNavList.querySelector( 'li:nth-last-child(2)' );
+ moreList.prepend( lastItem );
+ } while ( ! navFits( sectionNav ) );
+};
+
+/**
+ * Handle the fit of the nav for desktop.
+ *
+ * @param sectionNav
+ */
+const handleNavFit = ( sectionNav ) => {
+ resetNav( sectionNav );
+
+ if ( componentState.isMobile || navFits( sectionNav ) ) {
+ return;
+ }
+
+ fileItems( sectionNav );
+};
+
+/**
+ * Set up the resizeObserver callback for each SectionNav.
+ *
+ * @type {ResizeObserver}
+ */
+const sectionNavResizeObserver = new ResizeObserver( ( entries ) => {
+ entries.forEach( entry => handleNavFit( entry.target ) );
+} );
+
+/**
+ * Set up the IntersectionObserver callback for each SectionNav.
+ *
+ * @type {IntersectionObserver}
+ */
+const sectionNavIntersectionObserver = new IntersectionObserver( ( entries ) => {
+ entries.forEach( ( entry ) => {
+ entry.target.classList.toggle( 'c-section-nav--stuck', entry.intersectionRatio < 1 );
+ } );
+}, intObserverOpts );
+
+/**
+ * Initialize the observers to the SectionNav.
+ *
+ * @param sectionNav
+ */
+const initializeSectionNav = ( sectionNav ) => {
+ if ( sectionNav.dataset.initialized ) {
+ return;
+ }
+
+ // Attach the resize observer
+ sectionNavResizeObserver.observe( sectionNav );
+
+ // If this is a sticky instance, attach the intersection observer.
+ if ( sectionNav.classList.contains( 'c-section-nav--sticky' ) ) {
+ sectionNavIntersectionObserver.observe( sectionNav );
+ }
+
+ sectionNav.setAttribute( 'data-initialized', true );
+};
+
+/**
+ * Handle the initial state for the component.
+ */
+const handleInitialState = () => {
+ componentState.isMobile = componentState.vWidth < MOBILE_BREAKPOINT;
+ el.sectionNavs.forEach( sectionNav => initializeSectionNav( sectionNav ) );
+};
+
+/**
+ * Handle the ACF editor preview update.
+ *
+ * @param $block
+ */
+const handlePreviewUpdate = ( $block ) => {
+ const sectionNav = $block.find( '[data-js="c-section-nav"]' )[ 0 ];
+
+ if ( ! sectionNav ) {
+ return;
+ }
+
+ handleNavFit( sectionNav );
+};
+
+/**
+ * Be sure the component state's viewport width is based on whichever JS bundle is being loaded (theme or admin).
+ */
+const updateViewportWidth = () => componentState.vWidth = state.v_width || adminState.v_width;
+
+/**
+ * Handle resize events for this module.
+ */
+const handleResize = () => {
+ updateViewportWidth();
+
+ // If viewport state larger than mobile, but component state is mobile, update component state to match and show all section navs.
+ if ( componentState.vWidth >= MOBILE_BREAKPOINT && componentState.isMobile ) {
+ toggleAllSectionNavs( 'open' );
+ componentState.isMobile = false;
+ el.sectionNavs.forEach( sectionNav => handleNavFit( sectionNav ) );
+ }
+
+ // If viewport state is mobile, but component state is NOT, update component state and hide all section navs.
+ if ( componentState.vWidth < MOBILE_BREAKPOINT && ! componentState.isMobile ) {
+ toggleAllSectionNavs( 'close' );
+ componentState.isMobile = true;
+ }
+};
+
+/**
+ * Handle Escape key events for this module.
+ *
+ * @param e
+ */
+const handleEscKeyUp = ( e ) => {
+ if ( e.key !== 'Escape' ) {
+ return;
+ }
+
+ componentState.isMobile ? toggleAllSectionNavs( 'close' ) : closeAllMoreMenus();
+};
+
+/**
+ * Handle "out" events on mobile for this module.
+ *
+ * @param sectionNav
+ * @param targetEl
+ */
+const handleOutMobile = ( sectionNav, targetEl ) => {
+ // If the section nav is not visible or the focused element is still within this section nav, bail.
+ if ( ! sectionNav.classList.contains( 'c-section-nav--visible' ) ||
+ targetEl.closest( '[data-js="c-section-nav"]' ) === sectionNav ) {
+ return;
+ }
+
+ closeSectionNav( sectionNav );
+};
+
+/**
+ * Handle "out" events on desktop for this module.
+ *
+ * @param sectionNav
+ * @param targetEl
+ */
+const handleOutDesktop = ( sectionNav, targetEl ) => {
+ const moreListItem = sectionNav.querySelector( '[data-js="c-section-nav__list-item--more"]' );
+
+ // If the More menu isn't active or the focused element is still within this more menu, bail.
+ if ( ! sectionNav.classList.contains( 'c-section-nav--more-active' ) ||
+ targetEl.closest( '[data-js="c-section-nav__list-item--more"]' ) === moreListItem ) {
+ return;
+ }
+
+ closeMoreMenu( sectionNav );
+};
+
+/**
+ * Handle click outside event for this module.
+ *
+ * @param e
+ */
+const handleClickOut = ( e ) => {
+ el.sectionNavs.forEach( ( sectionNav ) => componentState.isMobile
+ ? handleOutMobile( sectionNav, e.target )
+ : handleOutDesktop( sectionNav, e.target ) );
+};
+
+/**
+ * Handle Tab outside events for this module.
+ *
+ * @param e
+ */
+const handleTabKeyUp = ( e ) => {
+ if ( e.key !== 'Tab' ) {
+ return;
+ }
+
+ el.sectionNavs.forEach( ( sectionNav ) => componentState.isMobile
+ ? handleOutMobile( sectionNav, e.target )
+ : handleOutDesktop( sectionNav, e.target ) );
+};
+
+/**
+ * Build events for this module.
+ */
+const bindEvents = () => {
+ delegate( el.container, '[data-js="c-section-nav__toggle--more"]', 'click', toggleMoreMenu );
+ delegate( el.container, '[data-js="c-section-nav__toggle--more"]', 'keyup', handleEscKeyUp );
+ delegate( el.container, '[data-js="c-section-nav__toggle--mobile"]', 'click', toggleSectionNav );
+ delegate( el.container, '[data-js="c-section-nav__toggle--mobile"]', 'keyup', handleEscKeyUp );
+ delegate( el.container, '.section-nav__list-item a', 'keyup', handleEscKeyUp );
+
+ on( document, 'click', handleClickOut );
+ on( document, 'keyup', handleTabKeyUp );
+ on( document, 'modern_tribe/resize_executed', handleResize );
+
+ if ( window.acf ) {
+ window.acf.addAction( 'render_block_preview/type=sectionnav', handlePreviewUpdate );
+ }
+};
+
+/**
+ * Kick off this module's functions
+ */
+const init = ( sectionNavs ) => {
+ if ( ! sectionNavs.length || ! el.container ) {
+ return;
+ }
+
+ el.sectionNavs = sectionNavs;
+
+ updateViewportWidth();
+ handleInitialState();
+ bindEvents();
+
+ console.info( 'SquareOne Theme: Initialized Section Nav component scripts.' );
+};
+
+export default init;
diff --git a/wp-content/themes/core/components/section_nav/section_nav.php b/wp-content/themes/core/components/section_nav/section_nav.php
new file mode 100644
index 000000000..6790de68b
--- /dev/null
+++ b/wp-content/themes/core/components/section_nav/section_nav.php
@@ -0,0 +1,37 @@
+
+