├── .github ├── FUNDING.yml ├── workflows │ ├── build.yml │ ├── deploy.yml │ └── update.yml └── dependabot.yml ├── tests ├── test-sample.php └── bootstrap.php ├── phpunit.xml.dist ├── .editorconfig ├── assets └── main.js ├── package.json ├── vite.config.js ├── .distignore ├── readme.txt ├── Gruntfile.js ├── turbo-drive.php ├── .travis.yml ├── .phpcs.xml.dist ├── .gitignore ├── includes └── class-turbo-drive-settings.php └── bin └── install-wp-tests.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [Romaixn] 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | 5 | jobs: 6 | tag: 7 | name: Build 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@master 11 | - name: Build 12 | run: | 13 | npm install 14 | npm run build 15 | -------------------------------------------------------------------------------- /tests/test-sample.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' # See documentation for possible values 4 | directory: '/' # Location of package manifests 5 | open-pull-requests-limit: 25 6 | schedule: 7 | interval: 'daily' 8 | - package-ecosystem: 'github-actions' # See documentation for possible values 9 | directory: '/' # Location of package manifests 10 | open-pull-requests-limit: 25 11 | schedule: 12 | interval: 'daily' 13 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | ./tests/ 13 | ./tests/test-sample.php 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # https://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | indent_size = 4 16 | 17 | [{.jshintrc,*.json,*.yml}] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [{*.txt,wp-config-sample.php}] 22 | end_of_line = crlf 23 | -------------------------------------------------------------------------------- /assets/main.js: -------------------------------------------------------------------------------- 1 | import * as Turbo from "@hotwired/turbo" 2 | 3 | document.addEventListener("turbo:load", () => { 4 | if (window.turboDriveOptions && window.turboDriveOptions.progressBarColor) { 5 | let style = document.getElementById("turbo-progress-style"); 6 | if (!style) { 7 | style = document.createElement("style"); 8 | style.id = "turbo-progress-style"; 9 | document.head.appendChild(style); 10 | } 11 | 12 | style.textContent = `.turbo-progress-bar { background-color: ${window.turboDriveOptions.progressBarColor} !important; }`; 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to WordPress.org 2 | on: 3 | push: 4 | tags: 5 | - "*" 6 | jobs: 7 | tag: 8 | name: Deploy to WordPress.org 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | - name: Build 13 | run: | 14 | npm install 15 | npm run build 16 | - name: WordPress Plugin Deploy 17 | uses: 10up/action-wordpress-plugin-deploy@stable 18 | env: 19 | SLUG: 'td-turbo-drive' 20 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} 21 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }} 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turbo-drive", 3 | "version": "0.3.2", 4 | "main": "Gruntfile.js", 5 | "author": "Romain Herault", 6 | "scripts": { 7 | "dev": "wp-env start", 8 | "wp-env": "wp-env", 9 | "start": "grunt default", 10 | "readme": "grunt readme", 11 | "i18n": "grunt i18n", 12 | "build": "vite build" 13 | }, 14 | "devDependencies": { 15 | "@wordpress/env": "^10.36.0", 16 | "grunt": "^1.6.1", 17 | "grunt-wp-i18n": "^1.0.4", 18 | "grunt-wp-readme-to-markdown": "^2.1.0", 19 | "vite": "^7.3.0" 20 | }, 21 | "dependencies": { 22 | "@hotwired/turbo": "^8.0.20" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | const { resolve } = require('path') 3 | 4 | // https://vitejs.dev/config 5 | export default defineConfig({ 6 | build: { 7 | // output dir for production build 8 | outDir: resolve(__dirname, './dist'), 9 | emptyOutDir: true, 10 | 11 | // esbuild target 12 | target: 'es2018', 13 | 14 | // our entry 15 | rollupOptions: { 16 | input: { 17 | main: resolve( __dirname + '/assets/main.js') 18 | }, 19 | 20 | output: { 21 | entryFileNames: `[name].js`, 22 | chunkFileNames: `[name].js`, 23 | assetFileNames: `[name].[ext]` 24 | } 25 | }, 26 | 27 | // minifying switch 28 | minify: true, 29 | write: true 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /.distignore: -------------------------------------------------------------------------------- 1 | # A set of files you probably don't want in your WordPress.org distribution 2 | .babelrc 3 | .deployignore 4 | .distignore 5 | .editorconfig 6 | .eslintignore 7 | .eslintrc 8 | .git 9 | .gitignore 10 | .github 11 | .gitlab-ci.yml 12 | .travis.yml 13 | .DS_Store 14 | .*~ 15 | Thumbs.db 16 | behat.yml 17 | bitbucket-pipelines.yml 18 | bin 19 | .circleci/config.yml 20 | composer.json 21 | composer.lock 22 | dependencies.yml 23 | Gruntfile.js 24 | package.json 25 | package-lock.json 26 | phpunit.xml 27 | phpunit.xml.dist 28 | multisite.xml 29 | multisite.xml.dist 30 | .phpcs.xml 31 | phpcs.xml 32 | .phpcs.xml.dist 33 | phpcs.xml.dist 34 | README.md 35 | webpack.config.js 36 | wp-cli.local.yml 37 | yarn.lock 38 | tests 39 | vendor 40 | node_modules 41 | *.sql 42 | *.tar.gz 43 | *.zip 44 | assets 45 | Dockerfile 46 | docker-compose.yml 47 | vite.config.js 48 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Turbo Drive === 2 | Contributors: rherault 3 | Donate link: https://github.com/sponsors/Romaixn 4 | Tags: turbo, swup, no refresh, optimize, spa 5 | Requires at least: 5.7.0 6 | Tested up to: 6.3.2 7 | Requires PHP: 7.4 8 | Stable tag: 0.3.2 9 | License: GPLv2 or later 10 | License URI: https://www.gnu.org/licenses/gpl-2.0.html 11 | 12 | Integrate Hotwired Turbo with WordPress, no page reload, no jQuery. 13 | 14 | == Description == 15 | 16 | Integrate Hotwired Turbo with WordPress, no page reload, no jQuery. 17 | 18 | == Installation == 19 | 20 | 1. Activate the plugin through the 'Plugins' menu in WordPress 21 | 22 | == Changelog == 23 | 24 | = 0.3.2 = 25 | * Upgrading dependencies 26 | 27 | = 0.3.0 = 28 | * Change plugin name 29 | 30 | = 0.2.0 = 31 | * Add attribute to all assets to reload page if it change 32 | 33 | = 0.1.0 = 34 | * First release, little buggy 35 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | get_options(); 26 | wp_localize_script('turbo-drive', 'turboDriveOptions', array( 27 | 'progressBarColor' => $options['progress_bar_color'], 28 | )); 29 | }, 10); 30 | 31 | add_action('admin_head', function () { 32 | echo ''; 33 | }, 10); 34 | 35 | add_filter('script_loader_tag', function ($script_tag) { 36 | if (is_admin()) { 37 | return $script_tag; 38 | } 39 | global $current_screen; 40 | if ($current_screen instanceof \WP_Screen && $current_screen->is_block_editor()) { 41 | return $script_tag; 42 | } 43 | 44 | return str_replace(' src', ' data-turbo-track="reload" src', $script_tag); 45 | }, 10, 1); 46 | 47 | add_filter('style_loader_tag', function ($style_tag) { 48 | if (is_admin()) { 49 | return $style_tag; 50 | } 51 | global $current_screen; 52 | if ($current_screen instanceof \WP_Screen && $current_screen->is_block_editor()) { 53 | return $style_tag; 54 | } 55 | 56 | return str_replace(' href', ' data-turbo-track="reload" href', $style_tag); 57 | }, 10, 1); 58 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | 4 | language: php 5 | 6 | notifications: 7 | email: 8 | on_success: never 9 | on_failure: change 10 | 11 | branches: 12 | only: 13 | - master 14 | 15 | cache: 16 | directories: 17 | - $HOME/.composer/cache 18 | 19 | matrix: 20 | include: 21 | - php: 7.4 22 | env: WP_VERSION=latest 23 | - php: 7.3 24 | env: WP_VERSION=latest 25 | - php: 7.2 26 | env: WP_VERSION=latest 27 | - php: 7.1 28 | env: WP_VERSION=latest 29 | - php: 7.0 30 | env: WP_VERSION=latest 31 | - php: 5.6 32 | env: WP_VERSION=4.5 33 | - php: 5.6 34 | env: WP_VERSION=latest 35 | - php: 5.6 36 | env: WP_VERSION=trunk 37 | - php: 5.6 38 | env: WP_TRAVISCI=phpcs 39 | 40 | before_script: 41 | - export PATH="$HOME/.composer/vendor/bin:$PATH" 42 | - | 43 | if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then 44 | phpenv config-rm xdebug.ini 45 | else 46 | echo "xdebug.ini does not exist" 47 | fi 48 | - | 49 | if [[ ! -z "$WP_VERSION" ]] ; then 50 | bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION 51 | composer global require "phpunit/phpunit=4.8.*|5.7.*" 52 | fi 53 | - | 54 | if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then 55 | composer global require wp-coding-standards/wpcs 56 | composer global require phpcompatibility/php-compatibility 57 | composer global require phpcompatibility/phpcompatibility-paragonie 58 | composer global require phpcompatibility/phpcompatibility-wp 59 | phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs,$HOME/.composer/vendor/phpcompatibility/php-compatibility,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp 60 | fi 61 | 62 | script: 63 | - | 64 | if [[ ! -z "$WP_VERSION" ]] ; then 65 | phpunit 66 | WP_MULTISITE=1 phpunit 67 | fi 68 | - | 69 | if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then 70 | phpcs 71 | fi 72 | -------------------------------------------------------------------------------- /.phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | Generally-applicable sniffs for WordPress plugins. 4 | 5 | 6 | . 7 | /vendor/ 8 | /node_modules/ 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot reviewer 2 | 3 | on: pull_request_target 4 | 5 | permissions: 6 | pull-requests: write 7 | contents: write 8 | 9 | jobs: 10 | review-dependabot-pr: 11 | runs-on: ubuntu-latest 12 | if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }} 13 | steps: 14 | - name: Dependabot metadata 15 | id: dependabot-metadata 16 | uses: dependabot/fetch-metadata@v2.4.0 17 | - name: Enable auto-merge for Dependabot PRs 18 | run: gh pr merge --auto --merge "$PR_URL" 19 | env: 20 | PR_URL: ${{github.event.pull_request.html_url}} 21 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 22 | - name: Approve patch and minor updates 23 | if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch' || steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor'}} 24 | run: gh pr review $PR_URL --approve -b "I'm **approving** this pull request because **it includes a patch or minor update**" 25 | env: 26 | PR_URL: ${{github.event.pull_request.html_url}} 27 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | - name: Approve major updates of development dependencies 29 | if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-major' && steps.dependabot-metadata.outputs.dependency-type == 'direct:development'}} 30 | run: gh pr review $PR_URL --approve -b "I'm **approving** this pull request because **it includes a major update of a dependency used only in development**" 31 | env: 32 | PR_URL: ${{github.event.pull_request.html_url}} 33 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 34 | - name: Comment on major updates of non-development dependencies 35 | if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-major' && steps.dependabot-metadata.outputs.dependency-type == 'direct:production'}} 36 | run: | 37 | gh pr comment $PR_URL --body "I'm **not approving** this PR because **it includes a major update of a dependency used in production**" 38 | gh pr edit $PR_URL --add-label "requires-manual-qa" 39 | env: 40 | PR_URL: ${{github.event.pull_request.html_url}} 41 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | phpcs.xml 3 | phpunit.xml 4 | Thumbs.db 5 | wp-cli.local.yml 6 | node_modules/ 7 | *.sql 8 | *.tar.gz 9 | *.zip 10 | dist/ 11 | 12 | # User-specific stuff 13 | .idea/**/workspace.xml 14 | .idea/**/tasks.xml 15 | .idea/**/usage.statistics.xml 16 | .idea/**/dictionaries 17 | .idea/**/shelf 18 | 19 | # AWS User-specific 20 | .idea/**/aws.xml 21 | 22 | # Generated files 23 | .idea/**/contentModel.xml 24 | 25 | # Sensitive or high-churn files 26 | .idea/**/dataSources/ 27 | .idea/**/dataSources.ids 28 | .idea/**/dataSources.local.xml 29 | .idea/**/sqlDataSources.xml 30 | .idea/**/dynamic.xml 31 | .idea/**/uiDesigner.xml 32 | .idea/**/dbnavigator.xml 33 | 34 | # Gradle 35 | .idea/**/gradle.xml 36 | .idea/**/libraries 37 | 38 | # Gradle and Maven with auto-import 39 | # When using Gradle or Maven with auto-import, you should exclude module files, 40 | # since they will be recreated, and may cause churn. Uncomment if using 41 | # auto-import. 42 | # .idea/artifacts 43 | # .idea/compiler.xml 44 | # .idea/jarRepositories.xml 45 | # .idea/modules.xml 46 | # .idea/*.iml 47 | # .idea/modules 48 | # *.iml 49 | # *.ipr 50 | 51 | # CMake 52 | cmake-build-*/ 53 | 54 | # Mongo Explorer plugin 55 | .idea/**/mongoSettings.xml 56 | 57 | # File-based project format 58 | *.iws 59 | 60 | # IntelliJ 61 | out/ 62 | 63 | # mpeltonen/sbt-idea plugin 64 | .idea_modules/ 65 | 66 | # JIRA plugin 67 | atlassian-ide-plugin.xml 68 | 69 | # Cursive Clojure plugin 70 | .idea/replstate.xml 71 | 72 | # SonarLint plugin 73 | .idea/sonarlint/ 74 | 75 | # Crashlytics plugin (for Android Studio and IntelliJ) 76 | com_crashlytics_export_strings.xml 77 | crashlytics.properties 78 | crashlytics-build.properties 79 | fabric.properties 80 | 81 | # Editor-based Rest Client 82 | .idea/httpRequests 83 | 84 | # Android studio 3.1+ serialized cache file 85 | .idea/caches/build_file_checksums.ser 86 | 87 | ### PhpStorm Patch ### 88 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 89 | 90 | # *.iml 91 | # modules.xml 92 | # .idea/misc.xml 93 | # *.ipr 94 | 95 | # Sonarlint plugin 96 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 97 | .idea/**/sonarlint/ 98 | 99 | # SonarQube Plugin 100 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 101 | .idea/**/sonarIssues.xml 102 | 103 | # Markdown Navigator plugin 104 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 105 | .idea/**/markdown-navigator.xml 106 | .idea/**/markdown-navigator-enh.xml 107 | .idea/**/markdown-navigator/ 108 | 109 | # Cache file creation bug 110 | # See https://youtrack.jetbrains.com/issue/JBR-2257 111 | .idea/$CACHE_FILE$ 112 | 113 | # CodeStream plugin 114 | # https://plugins.jetbrains.com/plugin/12206-codestream 115 | .idea/codestream.xml 116 | 117 | # Azure Toolkit for IntelliJ plugin 118 | # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij 119 | .idea/**/azureSettings.xml 120 | -------------------------------------------------------------------------------- /includes/class-turbo-drive-settings.php: -------------------------------------------------------------------------------- 1 | '#29d', 38 | ); 39 | 40 | /** 41 | * Constructor 42 | */ 43 | private function __construct() 44 | { 45 | add_action('admin_menu', array( $this, 'add_settings_page' )); 46 | add_action('admin_init', array( $this, 'register_settings' )); 47 | } 48 | 49 | /** 50 | * Get the unique instance of the class 51 | * 52 | * @return Turbo_Drive_Settings 53 | */ 54 | public static function get_instance() 55 | { 56 | if (self::$instance === null) { 57 | self::$instance = new self(); 58 | } 59 | 60 | return self::$instance; 61 | } 62 | 63 | /** 64 | * Add settings page to admin menu 65 | */ 66 | public function add_settings_page() 67 | { 68 | add_options_page( 69 | __('Turbo Drive Settings', 'turbo-drive'), 70 | __('Turbo Drive', 'turbo-drive'), 71 | 'manage_options', 72 | 'turbo-drive-settings', 73 | array( $this, 'render_settings_page' ) 74 | ); 75 | } 76 | 77 | /** 78 | * Register settings 79 | */ 80 | public function register_settings() 81 | { 82 | register_setting( 83 | 'turbo_drive_settings_group', 84 | $this->option_name, 85 | array( $this, 'sanitize_options' ) 86 | ); 87 | 88 | add_settings_section( 89 | 'turbo_drive_general_section', 90 | __('General Settings', 'turbo-drive'), 91 | array( $this, 'render_general_section' ), 92 | 'turbo-drive-settings' 93 | ); 94 | 95 | add_settings_field( 96 | 'progress_bar_color', 97 | __('Progress Bar Color', 'turbo-drive'), 98 | array( $this, 'render_progress_bar_color_field' ), 99 | 'turbo-drive-settings', 100 | 'turbo_drive_general_section' 101 | ); 102 | } 103 | 104 | /** 105 | * Sanitize options before saving 106 | * 107 | * @param array $input Options to sanitize. 108 | * @return array Sanitized options. 109 | */ 110 | public function sanitize_options($input) 111 | { 112 | $sanitized_input = array(); 113 | 114 | // Sanitize progress bar color 115 | if (isset($input['progress_bar_color'])) { 116 | $sanitized_input['progress_bar_color'] = sanitize_hex_color($input['progress_bar_color']); 117 | if (empty($sanitized_input['progress_bar_color'])) { 118 | $sanitized_input['progress_bar_color'] = $this->default_options['progress_bar_color']; 119 | } 120 | } 121 | 122 | return $sanitized_input; 123 | } 124 | 125 | /** 126 | * Display general section description 127 | */ 128 | public function render_general_section() 129 | { 130 | echo '

' . esc_html__('Configure Turbo Drive options for your site.', 'turbo-drive') . '

'; 131 | } 132 | 133 | /** 134 | * Display progress bar color field 135 | */ 136 | public function render_progress_bar_color_field() 137 | { 138 | $options = $this->get_options(); 139 | $color = isset($options['progress_bar_color']) ? $options['progress_bar_color'] : $this->default_options['progress_bar_color']; 140 | 141 | echo ''; 142 | echo '

' . esc_html__('Choose the color of the progress bar that appears during page loads.', 'turbo-drive') . '

'; 143 | } 144 | 145 | /** 146 | * Display settings page 147 | */ 148 | public function render_settings_page() 149 | { 150 | if (! current_user_can('manage_options')) { 151 | return; 152 | } 153 | 154 | ?> 155 |
156 |

157 |
158 | 163 |
164 |
165 | option_name, $this->default_options); 176 | return wp_parse_args($options, $this->default_options); 177 | } 178 | 179 | /** 180 | * Get value of a specific option 181 | * 182 | * @param string $key Option key. 183 | * @param mixed $default Default value. 184 | * @return mixed 185 | */ 186 | public function get_option($key, $default = null) 187 | { 188 | $options = $this->get_options(); 189 | 190 | if (isset($options[$key])) { 191 | return $options[$key]; 192 | } 193 | 194 | return $default !== null ? $default : $this->default_options[$key] ?? null; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /bin/install-wp-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -lt 3 ]; then 4 | echo "usage: $0 [db-host] [wp-version] [skip-database-creation]" 5 | exit 1 6 | fi 7 | 8 | DB_NAME=$1 9 | DB_USER=$2 10 | DB_PASS=$3 11 | DB_HOST=${4-localhost} 12 | WP_VERSION=${5-latest} 13 | SKIP_DB_CREATE=${6-false} 14 | 15 | TMPDIR=${TMPDIR-/tmp} 16 | TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//") 17 | WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib} 18 | WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress} 19 | 20 | download() { 21 | if [ `which curl` ]; then 22 | curl -s "$1" > "$2"; 23 | elif [ `which wget` ]; then 24 | wget -nv -O "$2" "$1" 25 | fi 26 | } 27 | 28 | if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then 29 | WP_BRANCH=${WP_VERSION%\-*} 30 | WP_TESTS_TAG="branches/$WP_BRANCH" 31 | 32 | elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then 33 | WP_TESTS_TAG="branches/$WP_VERSION" 34 | elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then 35 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then 36 | # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x 37 | WP_TESTS_TAG="tags/${WP_VERSION%??}" 38 | else 39 | WP_TESTS_TAG="tags/$WP_VERSION" 40 | fi 41 | elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then 42 | WP_TESTS_TAG="trunk" 43 | else 44 | # http serves a single offer, whereas https serves multiple. we only want one 45 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json 46 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json 47 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') 48 | if [[ -z "$LATEST_VERSION" ]]; then 49 | echo "Latest WordPress version could not be found" 50 | exit 1 51 | fi 52 | WP_TESTS_TAG="tags/$LATEST_VERSION" 53 | fi 54 | set -ex 55 | 56 | install_wp() { 57 | 58 | if [ -d $WP_CORE_DIR ]; then 59 | return; 60 | fi 61 | 62 | mkdir -p $WP_CORE_DIR 63 | 64 | if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then 65 | mkdir -p $TMPDIR/wordpress-trunk 66 | rm -rf $TMPDIR/wordpress-trunk/* 67 | svn export --quiet https://core.svn.wordpress.org/trunk $TMPDIR/wordpress-trunk/wordpress 68 | mv $TMPDIR/wordpress-trunk/wordpress/* $WP_CORE_DIR 69 | else 70 | if [ $WP_VERSION == 'latest' ]; then 71 | local ARCHIVE_NAME='latest' 72 | elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then 73 | # https serves multiple offers, whereas http serves single. 74 | download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json 75 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then 76 | # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x 77 | LATEST_VERSION=${WP_VERSION%??} 78 | else 79 | # otherwise, scan the releases and get the most up to date minor version of the major release 80 | local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'` 81 | LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1) 82 | fi 83 | if [[ -z "$LATEST_VERSION" ]]; then 84 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 85 | else 86 | local ARCHIVE_NAME="wordpress-$LATEST_VERSION" 87 | fi 88 | else 89 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 90 | fi 91 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz 92 | tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR 93 | fi 94 | 95 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php 96 | } 97 | 98 | install_test_suite() { 99 | # portable in-place argument for both GNU sed and Mac OSX sed 100 | if [[ $(uname -s) == 'Darwin' ]]; then 101 | local ioption='-i.bak' 102 | else 103 | local ioption='-i' 104 | fi 105 | 106 | # set up testing suite if it doesn't yet exist 107 | if [ ! -d $WP_TESTS_DIR ]; then 108 | # set up testing suite 109 | mkdir -p $WP_TESTS_DIR 110 | rm -rf $WP_TESTS_DIR/{includes,data} 111 | svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes 112 | svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data 113 | fi 114 | 115 | if [ ! -f wp-tests-config.php ]; then 116 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php 117 | # remove all forward slashes in the end 118 | WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") 119 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php 120 | sed $ioption "s:__DIR__ . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php 121 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php 122 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php 123 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php 124 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php 125 | fi 126 | 127 | } 128 | 129 | recreate_db() { 130 | shopt -s nocasematch 131 | if [[ $1 =~ ^(y|yes)$ ]] 132 | then 133 | mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA 134 | create_db 135 | echo "Recreated the database ($DB_NAME)." 136 | else 137 | echo "Leaving the existing database ($DB_NAME) in place." 138 | fi 139 | shopt -u nocasematch 140 | } 141 | 142 | create_db() { 143 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA 144 | } 145 | 146 | install_db() { 147 | 148 | if [ ${SKIP_DB_CREATE} = "true" ]; then 149 | return 0 150 | fi 151 | 152 | # parse DB_HOST for port or socket references 153 | local PARTS=(${DB_HOST//\:/ }) 154 | local DB_HOSTNAME=${PARTS[0]}; 155 | local DB_SOCK_OR_PORT=${PARTS[1]}; 156 | local EXTRA="" 157 | 158 | if ! [ -z $DB_HOSTNAME ] ; then 159 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then 160 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" 161 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then 162 | EXTRA=" --socket=$DB_SOCK_OR_PORT" 163 | elif ! [ -z $DB_HOSTNAME ] ; then 164 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" 165 | fi 166 | fi 167 | 168 | # create database 169 | if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ] 170 | then 171 | echo "Reinstalling will delete the existing test database ($DB_NAME)" 172 | read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB 173 | recreate_db $DELETE_EXISTING_DB 174 | else 175 | create_db 176 | fi 177 | } 178 | 179 | install_wp 180 | install_test_suite 181 | install_db 182 | --------------------------------------------------------------------------------