11# This workflow performs comprehensive WordPress plugin compatibility and quality checks.
22# It runs multiple validation processes including:
33# - WordPress Plugin Check for WordPress.org compatibility
4- # - PHP compatibility testing across multiple PHP versions (7.4, 8.0, 8.1, 8.2, 8.3)
5- # - WordPress compatibility testing across multiple WP versions (6.4, 6.5, 6.6, 6.7, 6.8 )
4+ # - PHP compatibility testing across multiple PHP versions (7.4, 8.0, 8.1, 8.2, 8.3, 8.4 )
5+ # - WordPress compatibility testing across multiple WP versions (6.0, latest, nightly )
66# - PHPStan static analysis for WordPress-specific code quality
77# - WordPress security vulnerability scanning using pattern analysis
88# - PHPCS code standards validation for WordPress coding standards
@@ -29,308 +29,6 @@ permissions:
2929 issues : write
3030
3131jobs :
32- php-compatibility-test :
33- name : PHP ${{ matrix.php-version }} with WordPress Latest
34- runs-on : ubuntu-latest
35- strategy :
36- matrix :
37- php-version : ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
38- fail-fast : false
39-
40- services :
41- mysql :
42- image : mysql:5.7
43- env :
44- MYSQL_ALLOW_EMPTY_PASSWORD : false
45- MYSQL_ROOT_PASSWORD : root
46- MYSQL_DATABASE : wordpress_test
47- ports :
48- - 3306:3306
49- options : --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
50-
51- steps :
52- - name : Checkout code
53- uses : actions/checkout@v4
54-
55- - name : Setup PHP ${{ matrix.php-version }}
56- uses : shivammathur/setup-php@v2
57- with :
58- php-version : ${{ matrix.php-version }}
59- extensions : mysqli, curl, zip, intl, gd, mbstring, fileinfo, xml
60- coverage : none
61- tools : composer:v2
62-
63- - name : Install Subversion
64- run : sudo apt-get update && sudo apt-get install -y subversion
65-
66- - name : Remove the PHP platform requirement
67- run : composer config --unset platform.php
68-
69- - name : Install Composer dependencies
70- uses : ramsey/composer-install@v3
71- with :
72- dependency-versions : highest
73- composer-options : " --prefer-dist --no-progress"
74-
75- - name : Prepare Database
76- run : |
77- # Make sure database doesn't exist before creating it
78- mysql -u root --password=root --host=127.0.0.1 --port=3306 -e "DROP DATABASE IF EXISTS wordpress_test;"
79- # Force creating a fresh database
80- mysqladmin -u root --password=root --host=127.0.0.1 --port=3306 --force create wordpress_test
81-
82- - name : Create tests directory structure
83- run : |
84- mkdir -p tests/bin
85- mkdir -p tests/bootstrap
86-
87- - name : Create WP tests install script
88- run : |
89- cat > tests/bin/install-wp-tests.sh << 'EOF'
90- #!/usr/bin/env bash
91-
92- if [ $# -lt 3 ]; then
93- echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
94- exit 1
95- fi
96-
97- DB_NAME=$1
98- DB_USER=$2
99- DB_PASS=$3
100- DB_HOST=${4-localhost}
101- WP_VERSION=${5-latest}
102- SKIP_DB_CREATE=${6-false}
103-
104- WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
105- WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
106-
107- download() {
108- if [ $(which curl) ]; then
109- curl -s "$1" > "$2";
110- elif [ $(which wget) ]; then
111- wget -nv -O "$2" "$1"
112- fi
113- }
114-
115- if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
116- WP_TESTS_TAG="tags/$WP_VERSION"
117- elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
118- WP_TESTS_TAG="trunk"
119- else
120- # http serves a single offer, whereas https serves multiple. we only want one
121- download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
122- LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
123- if [[ -z "$LATEST_VERSION" ]]; then
124- echo "Latest WordPress version could not be found"
125- exit 1
126- fi
127- WP_TESTS_TAG="tags/$LATEST_VERSION"
128- fi
129-
130- set -ex
131-
132- install_wp() {
133-
134- if [ -d $WP_CORE_DIR ]; then
135- return;
136- fi
137-
138- mkdir -p $WP_CORE_DIR
139-
140- if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
141- mkdir -p /tmp/wordpress-nightly
142- download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip
143- unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/
144- mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR
145- else
146- if [ $WP_VERSION == 'latest' ]; then
147- local ARCHIVE_NAME='latest'
148- else
149- local ARCHIVE_NAME="wordpress-$WP_VERSION"
150- fi
151- download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz
152- tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
153- fi
154-
155- download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
156- }
157-
158- install_test_suite() {
159- # portable in-place argument for both GNU sed and Mac OSX sed
160- if [[ $(uname -s) == 'Darwin' ]]; then
161- local ioption='-i.bak'
162- else
163- local ioption='-i'
164- fi
165-
166- # set up testing suite if it doesn't yet exist
167- if [ ! -d $WP_TESTS_DIR ]; then
168- # set up testing suite
169- mkdir -p $WP_TESTS_DIR
170- svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
171- svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
172- fi
173-
174- if [ ! -f wp-tests-config.php ]; then
175- download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
176- # remove all forward slashes in the end
177- WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
178- sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
179- sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
180- sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
181- sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
182- sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
183- fi
184- }
185-
186- install_db() {
187- if [ ${SKIP_DB_CREATE} = "true" ]; then
188- return 0
189- fi
190-
191- # parse DB_HOST for port or socket references
192- local PARTS=(${DB_HOST//\:/ })
193- local DB_HOSTNAME=${PARTS[0]};
194- local DB_SOCK_OR_PORT=${PARTS[1]};
195- local EXTRA=""
196-
197- if ! [ -z $DB_HOSTNAME ] ; then
198- if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
199- EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
200- elif ! [ -z $DB_SOCK_OR_PORT ] ; then
201- EXTRA=" --socket=$DB_SOCK_OR_PORT"
202- elif ! [ -z $DB_HOSTNAME ] ; then
203- EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
204- fi
205- fi
206-
207- # First, ensure database doesn't exist (ignore errors)
208- mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA -e "DROP DATABASE IF EXISTS $DB_NAME" || true
209- # Now create fresh database with force flag
210- mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA --force
211- }
212-
213- install_wp
214- install_test_suite
215- install_db
216- EOF
217- chmod +x tests/bin/install-wp-tests.sh
218-
219- - name : Create Bootstrap File
220- run : |
221- mkdir -p tests
222- cat > tests/bootstrap.php << 'EOF'
223- <?php
224- /**
225- * PHPUnit bootstrap file for plugin tests.
226- *
227- * @package Simple_WP_Optimizer
228- */
229-
230- // Give access to tests_add_filter() function.
231- require_once '/tmp/wordpress-tests-lib/includes/functions.php';
232-
233- /**
234- * Manually load the plugin being tested.
235- */
236- function _manually_load_plugin() {
237- // Make sure widget registration won't throw errors
238- add_filter('widgets_init', function() {
239- // Empty the action to prevent widget registration errors
240- return;
241- }, 0);
242-
243- require dirname( dirname( __FILE__ ) ) . '/simple-wp-optimizer.php';
244- }
245-
246- // Start up the WP testing environment.
247- tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
248-
249- require '/tmp/wordpress-tests-lib/includes/bootstrap.php';
250- EOF
251-
252- - name : Create Test File
253- run : |
254- cat > tests/test-plugin.php << 'EOF'
255- <?php
256- /**
257- * Class Test_Simple_WP_Optimizer
258- *
259- * @package Simple_WP_Optimizer
260- */
261-
262- /**
263- * Simple test case for Simple WP Optimizer plugin.
264- */
265- class Test_Simple_WP_Optimizer extends WP_UnitTestCase {
266- /**
267- * Test that the plugin can be loaded correctly.
268- *
269- * This test simply checks that the plugin loads in WordPress
270- * without causing any errors.
271- */
272- public function test_plugin_loaded() {
273- // Check for at least one function to verify the plugin loaded
274- $this->assertTrue(function_exists('es_optimizer_init_settings'), 'Plugin was not loaded correctly');
275- }
276- }
277- EOF
278-
279- - name : Create PHPUnit Config
280- run : |
281- cat > phpunit.xml << 'EOF'
282- <?xml version="1.0"?>
283- <phpunit
284- bootstrap="tests/bootstrap.php"
285- backupGlobals="false"
286- colors="true"
287- convertErrorsToExceptions="true"
288- convertNoticesToExceptions="true"
289- convertWarningsToExceptions="true"
290- >
291- <testsuites>
292- <testsuite name="Simple WP Optimizer">
293- <directory prefix="test-" suffix=".php">./tests/</directory>
294- </testsuite>
295- </testsuites>
296- </phpunit>
297- EOF
298-
299- - name : Setup WP Tests
300- run : |
301- bash tests/bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:3306 latest
302-
303- - name : Run plugin test
304- run : vendor/bin/phpunit --config phpunit.xml
305-
306- - name : Report test status
307- if : ${{ always() }}
308- run : |
309- if [ ${{ job.status }} == 'success' ]; then
310- echo "✅ Tests passed successfully on PHP ${{ matrix.php-version }} with the latest WordPress version"
311- else
312- echo "❌ Tests failed on PHP ${{ matrix.php-version }} with the latest WordPress version"
313- # Don't exit here, allow the next step to create the issue
314- fi
315-
316- - name : Create issue on test failure
317- if : ${{ failure() }}
318- uses : JasonEtco/create-an-issue@v2
319- env :
320- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
321- PHP_VERSION : ${{ matrix.php-version }}
322- RUN_ID : ${{ github.run_id }}
323- WORKFLOW_URL : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
324- with :
325- filename : .github/ISSUE_TEMPLATE/compatibility-test-failure.md
326- update_existing : false
327-
328- - name : Mark job as failed after issue creation
329- if : ${{ failure() }}
330- run : |
331- echo "::error::PHP ${{ matrix.php-version }} compatibility test failed. Created issue for tracking."
332- exit 1
333-
33432 plugin-check :
33533 name : WordPress Plugin Check (PHP ${{ matrix.php-version }})
33634 runs-on : ubuntu-latest
@@ -490,7 +188,14 @@ jobs:
490188
491189 - name : Run PHPMD
492190 run : |
493- phpmd . text cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor,tests,node_modules
191+ # Use WordPress-specific PHPMD configuration to suppress WordPress-specific patterns
192+ if [ -f phpmd-wordpress.xml ]; then
193+ echo "Using WordPress-specific PHPMD configuration..."
194+ phpmd . text phpmd-wordpress.xml --exclude vendor,tests,node_modules
195+ else
196+ echo "WordPress PHPMD config not found, using standard rules..."
197+ phpmd . text cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor,tests,node_modules
198+ fi
494199
495200 - name : Create issue on PHPMD failure
496201 if : ${{ failure() }}
@@ -988,4 +693,4 @@ jobs:
988693 WORKFLOW_URL : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
989694 with :
990695 filename : .github/ISSUE_TEMPLATE/phpstan-failure.md
991- update_existing : false
696+ update_existing : false
0 commit comments