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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .ddev/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: wordcamp
type: php
docroot: public_html/mu
php_version: "8.5"
webserver_type: nginx-fpm
database:
type: mariadb
version: "10.11"
disable_settings_management: true
additional_fqdns:
- wordcamp.test
- central.wordcamp.test
- seattle.wordcamp.test
- shinynew.wordcamp.test
- narnia.wordcamp.test
- events.wordpress.test
- campus.wordpress.test
hooks:
post-start:
- exec: bash /var/www/html/.ddev/setup.sh
28 changes: 28 additions & 0 deletions .ddev/nginx/multisite.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Multisite rewrite rules for WordCamp.org
# Adapted from .docker/config/nginx.conf

# Rewrite ms-files for uploaded media.
rewrite ^/files/(.*)$ /wp-includes/ms-files.php?file=$1;

# Rewrite multisite subdirectory paths (e.g., /2023/wp-admin/).
if (!-e $request_filename) {
rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
rewrite ^/[_0-9a-zA-Z-]+.*(/wp-admin/.*\.php)$ $1 last;
rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;
rewrite "/\d{4}/files/(.+)$" /wp-includes/ms-files.php?file=$1 last;
}

# Events network 3-level path rewrites (e.g., /rome/2024/training/wp-admin/).
if ( $host = "events.wordpress.test" ) {
rewrite "/[\w-]+/\d{4}/[\w-]+/wp-(admin|content|includes)(.*)" /wp-$1$2 last;
rewrite "/[\w-]+/\d{4}/[\w-]+/wp-(.*).php(.*)" /wp-$1.php$2 last;
rewrite "/[\w-]+/\d{4}/[\w-]+/xmlrpc\.php" /xmlrpc.php last;
rewrite "/[\w-]+/\d{4}/[\w-]+/files/(.+)$" /wp-includes/ms-files.php?file=$1 last;
}

# Serve wp-content from the parent directory (public_html/, not public_html/mu/).
location ~* /wp-content/.*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf)$ {
root /var/www/html/public_html;
expires max;
log_not_found off;
}
58 changes: 58 additions & 0 deletions .ddev/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/bash
#
# Idempotent DDEV post-start setup script for WordCamp.org.
# Runs inside the web container after `ddev start`.
#

set -e

PROJECT_ROOT="/var/www/html"
WP_DIR="$PROJECT_ROOT/public_html/mu"
WP_CONFIG="$PROJECT_ROOT/public_html/wp-config.php"
SEED_SQL="$PROJECT_ROOT/.docker/data/wordcamp_dev.sql"

# 1. Download WordPress core if not present.
if [ ! -f "$WP_DIR/wp-includes/version.php" ]; then
echo "Downloading WordPress core..."
mkdir -p "$WP_DIR"
wp core download --path="$WP_DIR" --skip-content
fi

# 2. Copy wp-config.php if not present.
if [ ! -f "$WP_CONFIG" ]; then
echo "Copying wp-config.php..."
cp "$PROJECT_ROOT/.ddev/wp-config-ddev.php" "$WP_CONFIG"
fi

# 3. Import seed database if tables don't exist.
if ! wp db check --path="$WP_DIR" 2>/dev/null | grep -q "wc_options"; then
if [ -f "$SEED_SQL" ]; then
echo "Importing seed database..."
wp db import "$SEED_SQL" --path="$WP_DIR"
else
echo "Warning: Seed database not found at $SEED_SQL"
fi
fi

# 4. Create placeholder build files for mu-plugins/blocks.
BLOCKS_DIR="$PROJECT_ROOT/public_html/wp-content/mu-plugins/blocks/source"
if [ -d "$BLOCKS_DIR" ]; then
for dir in "$BLOCKS_DIR"/*/; do
block_name=$(basename "$dir")
build_dir="$PROJECT_ROOT/public_html/wp-content/mu-plugins/blocks/build/$block_name"
if [ ! -d "$build_dir" ]; then
mkdir -p "$build_dir"
echo '(()=>{"use strict";})();' > "$build_dir/index.js"
echo '{"apiVersion":2}' > "$build_dir/block.json"
fi
done
fi

# 5. Install WP test suite for PHPUnit.
WP_TESTS_DIR="/tmp/wp/wordpress-tests-lib"
if [ ! -d "$WP_TESTS_DIR/includes" ]; then
echo "Installing WordPress test suite..."
bash "$PROJECT_ROOT/.docker/bin/install-wp-tests.sh" wcorg_test db db db latest
fi

echo "DDEV setup complete!"
1 change: 1 addition & 0 deletions .ddev/web-build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
RUN apt-get update && apt-get install -y subversion && rm -rf /var/lib/apt/lists/*
227 changes: 227 additions & 0 deletions .ddev/wp-config-ddev.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
<?php
/**
* WordCamp.org configuration file for DDEV.
*
* This is copied to public_html/wp-config.php by the setup script.
* Adapted from .docker/wp-config.php with DDEV-specific database credentials.
*/

define( 'IS_WORDCAMP_NETWORK', true );

/**
* The environment in which the WordCamp codebase is currently running.
*
* There are a few different values that this might contain that have implications in the code:
*
* - `production`: Used on the production server. Should not be used anywhere else.
* - `development`: The catchall value for non-production environments. Currently used on wporg sandboxes.
* - `local`: The value used for local development environments, where the domain is wordcamp.test and some
* functionality that relies on remote connections may not be available.
*/
define( 'WORDCAMP_ENVIRONMENT', 'local' );
define( 'WP_ENVIRONMENT_TYPE', 'local' );

/*
* Database
*/
define( 'DB_NAME', 'db' );
define( 'DB_USER', 'db' );
define( 'DB_PASSWORD', 'db' );
define( 'DB_HOST', 'db' );

// Force utf8mb4.
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', 'utf8mb4_general_ci' );

define( 'CUSTOM_USER_TABLE', 'wc_users' );
define( 'CUSTOM_USER_META_TABLE', 'wc_usermeta' );

$table_prefix = 'wc_'; // phpcs:ignore WordPress.WP.GlobalVariablesOverride

/*
* Multisite
*/
const WORDCAMP_NETWORK_ID = 1;
const WORDCAMP_ROOT_BLOG_ID = 5;
const EVENTS_NETWORK_ID = 2;
const EVENTS_ROOT_BLOG_ID = 47;
const CAMPUS_NETWORK_ID = 3;
const CAMPUS_ROOT_BLOG_ID = 47;

switch ( strtolower( $_SERVER['HTTP_HOST'] ) ) {
case 'campus.wordpress.test':
define( 'SITE_ID_CURRENT_SITE', CAMPUS_NETWORK_ID );
define( 'BLOG_ID_CURRENT_SITE', EVENTS_ROOT_BLOG_ID );
define( 'DOMAIN_CURRENT_SITE', 'campus.wordpress.test' );
define( 'SUBDOMAIN_INSTALL', false );
define( 'NOBLOGREDIRECT', 'https://events.wordpress.test/campusconnect/' );
define( 'CLI_HOSTNAME_OVERRIDE', 'campus.wordpress.test' );
break;

case 'events.wordpress.test':
define( 'SITE_ID_CURRENT_SITE', EVENTS_NETWORK_ID );
define( 'BLOG_ID_CURRENT_SITE', EVENTS_ROOT_BLOG_ID );
define( 'DOMAIN_CURRENT_SITE', 'events.wordpress.test' );
define( 'SUBDOMAIN_INSTALL', false );
// NOBLOGREDIRECT is intentionally omitted so that the 404 template works.
define( 'CLI_HOSTNAME_OVERRIDE', 'events.wordpress.test' );
break;

case 'wordcamp.test':
case 'buddycamp.test':
default:
define( 'SITE_ID_CURRENT_SITE', WORDCAMP_NETWORK_ID );
define( 'BLOG_ID_CURRENT_SITE', WORDCAMP_ROOT_BLOG_ID );
define( 'DOMAIN_CURRENT_SITE', 'buddycamp.test' === $_SERVER['HTTP_HOST'] ? 'buddycamp.test' : 'wordcamp.test' );
define( 'SUBDOMAIN_INSTALL', true );
define( 'NOBLOGREDIRECT', 'https://central.wordcamp.test' );
define( 'CLI_HOSTNAME_OVERRIDE', 'wordcamp.test' );
break;
}

define( 'MULTISITE', true );
define( 'SUNRISE', true );
define( 'PATH_CURRENT_SITE', '/' );


/*
* Logging/Debugging
*/
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'SAVEQUERIES', true );
define( 'DIEONDBERROR', false );
define( 'SCRIPT_DEBUG', false );
define( 'JETPACK_DEV_DEBUG', true );


/*
* Salts
*
* It doesn't matter for local environments, but use `wp config shuffle-salts` to change this in production
* environments, because generating the keys locally is safer than using the API (and exposing the keys to
* your OS/browser if you copy/paste, etc).
*/
define( 'AUTH_KEY', 'put your unique phrase here' );
define( 'SECURE_AUTH_KEY', 'put your unique phrase here' );
define( 'LOGGED_IN_KEY', 'put your unique phrase here' );
define( 'NONCE_KEY', 'put your unique phrase here' );
define( 'AUTH_SALT', 'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT', 'put your unique phrase here' );
define( 'NONCE_SALT', 'put your unique phrase here' );
define( 'ORGANIZER_SURVEY_ACCESS_TOKEN_KEY', 'put your unique phrase here' );


/*
* Misc
*/
define( 'WPLANG', '' );
define( 'WP_CONTENT_DIR', __DIR__ . '/wp-content' );
define( 'WP_CONTENT_URL', 'https://' . preg_replace( '/[^-_.0-9a-z:]/i', '', $_SERVER['HTTP_HOST'] ) . '/wp-content' );
define( 'WP_TEMP_DIR', '/tmp' );

define( 'FORCE_SSL_ADMIN', true );
define( 'DISALLOW_UNFILTERED_HTML', true );

define( 'WORDCAMP_SCRIPT_DIR', __DIR__ . '/bin' );
define( 'WP_CLI_SCRIPT_DIR', WORDCAMP_SCRIPT_DIR . '/wp-cli/' );
define( 'SCRIPT_BACKUP_DIRECTORY', WP_TEMP_DIR );
define( 'WORDCAMP_UTILITIES_DIR', WP_CONTENT_DIR . '/mu-plugins/utilities' );

define( 'EMAIL_DEVELOPER_NOTIFICATIONS', 'developers@example.test' );
define( 'EMAIL_CENTRAL_SUPPORT', 'support@wordcamp.test' );

$trusted_deputies = array(
6, // contributorrole.
);

$wcorg_subroles = array(
// contributorrole.
6 => array(
'wordcamp_wrangler',
'meetup_wrangler',
'mentor_manager',
'report_viewer',
),
);

/*
* Third party services
*/
define( 'SLACK_ERROR_REPORT_URL', '(Optional) you can configure slack and add your webhook url. Errors will be posted to this slack url' );
define( 'WORDCAMP_LOGS_SLACK_CHANNEL', '(Optional) @your_slack_username' );
define( 'WORDCAMP_LOGS_JETPACK_SLACK_CHANNEL', '(Optional) @your_slack_username' );
define( 'WORDCAMP_LOGS_GUTENBERG_SLACK_CHANNEL', '(Optional) @your_slack_username' );

define( 'TWITTER_CONSUMER_KEY_WORDCAMP_CENTRAL', '' );
define( 'TWITTER_CONSUMER_SECRET_WORDCAMP_CENTRAL', '' );
define( 'TWITTER_BEARER_TOKEN_WORDCAMP_CENTRAL', '' );

define( 'WORDCAMP_QBO_HMAC_KEY', 'localhmac' );

define( 'WORDCAMP_SANDBOX_QBO_CLIENT_ID', "(Optional) your app's development client ID key goes here" );
define( 'WORDCAMP_SANDBOX_QBO_CLIENT_SECRET', "(Optional) your app's development client secret key goes here" );
define( 'WORDCAMP_PRODUCTION_QBO_CLIENT_ID', '' );
define( 'WORDCAMP_PRODUCTION_QBO_CLIENT_SECRET', '' );

define( 'REMOTE_CSS_GITHUB_ID', '' );
define( 'REMOTE_CSS_GITHUB_SECRET', '' );

define( 'WORDCAMP_LE_HELPER_API_KEY', '' );
define( 'GENDERIZE_IO_API_KEY', '' );

define( 'WC_SANDBOX_PAYPAL_NVP_USERNAME', '' );
define( 'WC_SANDBOX_PAYPAL_NVP_PASSWORD', '' );
define( 'WC_SANDBOX_PAYPAL_NVP_SIGNATURE', '' );
define( 'WPCS_PAYPAL_NVP_USERNAME', '' );
define( 'WPCS_PAYPAL_NVP_PASSWORD', '' );
define( 'WPCS_PAYPAL_NVP_SIGNATURE', '' );

define( 'WORDCAMP_CAMPTIX_STRIPE_TEST_PUBLIC', '' );
define( 'WORDCAMP_CAMPTIX_STRIPE_TEST_SECRET', '' );
define( 'WORDCAMP_CAMPTIX_STRIPE_LIVE_PUBLIC', '' );
define( 'WORDCAMP_CAMPTIX_STRIPE_LIVE_SECRET', '' );

define( 'WORDCAMP_PAYMENTS_ENCRYPTION_KEY', '' );
define( 'WORDCAMP_PAYMENTS_HMAC_KEY', '' );
define( 'WORDCAMP_PAYMENT_STRIPE_HMAC', '' );
define( 'WORDCAMP_PAYMENT_STRIPE_PUBLISHABLE', '' );
define( 'WORDCAMP_PAYMENT_STRIPE_SECRET', '' );
define( 'WORDCAMP_PAYMENT_STRIPE_PUBLISHABLE_LIVE', '' );
define( 'WORDCAMP_PAYMENT_STRIPE_SECRET_LIVE', '' );

define( 'WORDCAMP_PROD_GOOGLE_MAPS_API_KEY', '' );
define( 'WORDCAMP_DEV_GOOGLE_MAPS_API_KEY', '' );

define( 'MEETUP_API_BASE_URL', 'https://api.meetup.com/' );
define( 'MEETUP_MEMBER_ID', 72560962 );
define( 'MEETUP_OAUTH_CONSUMER_KEY', '' );
define( 'MEETUP_OAUTH_CONSUMER_SECRET', '' );
define( 'MEETUP_OAUTH_CONSUMER_REDIRECT_URI', '' );
define( 'MEETUP_USER_EMAIL', '' );
define( 'MEETUP_USER_PASSWORD', '' );

define( 'WORDCAMP_FIXER_API_KEY', '' );
define( 'WORDCAMP_OXR_API_KEY', '' );


/*
* WP Super Cache
*/
define( 'WP_CACHE', true );
define( 'WPCACHEHOME', WP_CONTENT_DIR . '/plugins/wp-super-cache/' );
define( 'SUBMITDISABLED', false ); // Work around https://github.com/Automattic/wp-super-cache/issues/213.
define( 'WP_CACHE_PAGE_SECRET', '' );
define( 'WP_CACHE_DEBUG_USERNAME', '' );


/*
* Bootstrap WordPress
*/
if ( ! defined('ABSPATH') ) {
define( 'ABSPATH', __DIR__ . '/mu/' );
}

require_once ABSPATH . 'wp-settings.php';
36 changes: 16 additions & 20 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,6 @@ jobs:
matrix:
php-version: ['8.1', '8.4', '8.5']

services:
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: false
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wcorg_test
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

steps:
- uses: actions/checkout@v4

Expand All @@ -74,26 +63,33 @@ jobs:
sudo rm -f /var/lib/man-db/auto-update # https://github.com/actions/runner-images/issues/10977
sudo apt-get update && sudo apt-get install -y subversion

- name: Set PHP version
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: none
tools: composer:v2
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Start mysql service
run: sudo /etc/init.d/mysql start
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Install dependencies
run: |
rm composer.lock || true
composer install

- name: Install WordPress
run: |
bash .docker/bin/install-wp-tests.sh wcorg_test root root 127.0.0.1 latest
- name: Setup DDEV
uses: ddev/github-action-setup-ddev@v1
with:
autostart: false

- name: Set PHP version
run: ddev config --php-version=${{ matrix.php-version }}

- name: Start DDEV
run: ddev start

- name: Install WP test suite
run: ddev exec bash .docker/bin/install-wp-tests.sh wcorg_test root root db latest

- name: Running unit tests
run: ./public_html/wp-content/mu-plugins/vendor/bin/phpunit -c phpunit.xml.dist
run: ddev exec ./public_html/wp-content/mu-plugins/vendor/bin/phpunit -c phpunit.xml.dist
Loading
Loading