WordPress 6.0 update deploy failed

Hi guys,

After the release of Wordpress 6.0 I updated the roots/wordpress version in my composer.json in an existing project to 6.0 like in this Bedrock commit:

"roots/wordpress": "^6.0",
"wpackagist-theme/twentytwentytwo": "^1.2"

Locally this worked great, I can see the wp-content folder is not there anymore.
However, when I tried to deploy these changes to an existing staging droplet, I’m getting his error:

TASK [deploy : WordPress Installed?] *******************************************
System info:
  Ansible 2.10.17; Darwin
  Trellis version (per changelog): "Improve handling of PHP versions and support PHP 8.0"
---------------------------------------------------
Warning: strpos(): Empty needle in
/srv/www/mydomain/releases/20220525094312/web/wp/wp-includes/link-template.php
on line 3535
Warning: strpos(): Empty needle in
/srv/www/mydomain/releases/20220525094312/web/wp/wp-includes/link-template.php
on line 3535
fatal: [82.196.1.191]: FAILED! => {"changed": false, "cmd": ["wp", "core", "is-installed", "--skip-plugins", "--skip-themes", "--require=/srv/www/mydomain/shared/tmp_multisite_constants.php"], "delta": "0:00:01.115367", "end": "2022-05-25 09:44:01.258353", "failed_when_result": true, "rc": 0, "start": "2022-05-25 09:44:00.142986", "stderr": "Warning: strpos(): Empty needle in /srv/www/mydomain/releases/20220525094312/web/wp/wp-includes/link-template.php on line 3535\nWarning: strpos(): Empty needle in /srv/www/mydomain/releases/20220525094312/web/wp/wp-includes/link-template.php on line 3535", "stderr_lines": ["Warning: strpos(): Empty needle in /srv/www/mydomain/releases/20220525094312/web/wp/wp-includes/link-template.php on line 3535", "Warning: strpos(): Empty needle in /srv/www/mydomain/releases/20220525094312/web/wp/wp-includes/link-template.php on line 3535"], "stdout": "", "stdout_lines": []}

When I lookup the strpos function call in link-template.php on line 3535:

	$mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR );

	if ( ! empty( $plugin ) && 0 === strpos( $plugin, $mu_plugin_dir ) ) {
		$url = WPMU_PLUGIN_URL;
	} else {
		$url = WP_PLUGIN_URL;
	}

It seems the $mu_plugin_dir variable is empty?
Any ideas what’s going on here?

I already merged this Bedrock commit for the new Bedrock autoloader?

Downgrading roots/wordpress to ^5.9 fixes the failing deploys for now.

Thanks!

5 Likes

Same deployment error yesterday with the no-content 6.0 package.

That particular Empty needle error occurred to me in the past for PHP fatal errors, like open base dir restriction errors. So the underlying issue may be something else.

Update: This error only occurs in the Trellis WordPress Installed? check.
When the current symlink is manually changed to the newly deployed release that failed the check, the site still loads fine, everything works as it should (even a simple wp core is-installed exits with success status code).
When I replace that command with /usr/bin/true (because a variable is also set and such, just commenting it out would require more modifications), the deployment completes without errors.

Commenting out the --require={{ deploy_helper.shared_path }}/tmp_multisite_constants.php part of the wp core is-installed --skip-plugins --skip-themes --require={{ deploy_helper.shared_path }}/tmp_multisite_constants.php command lets the deploy succeed.
So the underlying error is caused by --require={{ deploy_helper.shared_path }}/tmp_multisite_constants.php. Judging from the name tmp_multisite_constants.php of the required file, maybe WordPress 6.0 has a breaking change with regards to multisite constants.

Manual demonstration:
For simplicity, the same wp CLI command that is used by the deploy check is ran on the Trellis server:

  1. Log into the Trellis server as web user.
  2. Go into the site release directory that failed (e.g. /srv/www/example.com/20220525193449/).
  3. Invoke the wp CLI command used by the deploy check:
    wp core is-installed --skip-plugins --skip-themes --require=/srv/www/example.com/shared/tmp_multisite_constants.php
    The command fails with the same PHP errors as during deploy.
  4. Now re-run that wp CLI command, but without the --require=/srv/www/example.com/shared/tmp_multisite_constants.php part.
    The command now exits without the PHP warnings.
1 Like

Adding my two cents here that I had to custom edit that multisite_constants.php in the last few months even before wordpress 6.0. Specifically, it works when I do this, sort of:

<?php
error_reporting(E_ALL & ~E_NOTICE);
// define('MULTISITE', false);
// define('SUBDOMAIN_INSTALL', false);
define('WPMU_PLUGIN_DIR', null);
define('WP_PLUGIN_DIR', null);
define('WP_USE_THEMES', false);

I just had to get it to work, so I’m not sure why.

Similar results here, when I use this tmp_multisite_constants.php

<?php
error_reporting(E_ALL & ~E_NOTICE);
define('MULTISITE', false);
define('SUBDOMAIN_INSTALL', false);
//define('WPMU_PLUGIN_DIR', null);
define('WP_PLUGIN_DIR', null);
define('WP_USE_THEMES', false);

with define('WPMU_PLUGIN_DIR', null); commented out, it fixes the error that otherwise occurs since WordPress 6.0 (so since basically yesterday when it came out).

2 Likes

That’s the line the PHP warnings are reported from by ansible (with define('WPMU_PLUGIN_DIR', null);):

The code in the plugins_url function does not check whether $mu_plugin_dir is not empty, (hence the Warning: strpos(): Empty needle).

Edit: Changing that line so that it checks for an empty needle, the wp command just passes fine:

if ( ! empty( $plugin ) && ! empty( $mu_plugin_dir ) && 0 === strpos( $plugin, $mu_plugin_dir ) ) {

The exit code with and without the PHP error is 0 (success)…
But with PHP warnings the ansible check fails. This is because the ansible check not only checks for an exit code smaller 1 (some kind of success I guess), but also checks for an empty stderr from wp:

The PHP warnings end up in stderr, hence the ansible check and the deployment fails.
And the deployment follows a more conservative strategy by rather failing with PHP warnings from wp than risking trouble with the new deployment.

I am curious what changes were introduced in WordPress 6.0 that causes the PHP warnings, because in latest WordPress 5.x no PHP warnings were emitted with the same Trellis setup.

3 Likes

tmp_multisite_constants.php defines the WPMU_PLUGIN_DIR constant as null.
WordPress checks for undefined WPMU_PLUGIN_DIR constant and defines one with some default value:

The question is: Is null an allowed/expected value for the WPMU_PLUGIN_DIR constant?
How should one set WPMU_PLUGIN_DIR to nothing otherwise?
WordPress core (at least since 6.0) doesn’t appear to be able to handle this case (hence the empty needle PHP warning).

Why is WPMU_PLUGIN_DIR set to null - would the default value that is assigned by WordPress be acceptable?

Related GitHub issue:

Related GitHub PR:

3 Likes

Thanks for your attention to this and extra details (I filed Bug: Autodeploy failures with WordPress 6.0 · Issue #1385 · roots/trellis · GitHub). We have the very same question as this point. Don’t know the answer yet – don’t find anything immediately obvious in developer notes or field guide, nor anything in quick comparison between releases: https://github.com/WordPress/WordPress/compare/6.0...5.9.3. Have asked about this in the #core-multisite WordPress Slack channel to see if someone there might be more knowledgeable: https://wordpress.slack.com/archives/C03BVB47S/p1653679302844629.

JJJ from WordPress community replied to ask

Is it possible that a PHP version running inside of the Trellis deployer was bumped? Newer versions of PHP are increasing error handling severity when “invalid” data types are passed through.

See: PHP: strpos - Manual


Not sure how to investigate this idea …

The Ansible check (“smoke test” basically) during deployment that uses the wp core is-installed [...] command will fail with a non-empty stderr:

The tmp_multisite_constants.php required by the wp command also raises the PHP error reporting level so that everything (including PHP warnings) except PHP notices are reported:

error_reporting(E_ALL & ~E_NOTICE);
[...]

So the strpos non-empty needle PHP warning will make stderr from wp non-empty and the Ansible check (and the deployment task) fails.

@SteelWagstaff, @Twansparant, @evankford, @nickkeenan, @jokanane, @masoninthesis:
Fixed in latest Trellis: Split `is-installed` check into a non-multisite and a mulitsite specific one by strarsis · Pull Request #1388 · roots/trellis · GitHub

5 Likes

After applying Pull Request 1388 for this issue, the first deploy to upgrade to roots/wordpress-no-content works like a charm. (This is upgrading an existing droplet, not a fresh install). However, subsequent deploys are failing for me at the WordPress Installed (non-multisite)? task:

non-zero return code
Error: This does not seem to be a WordPress installation.
Pass --path=`path/to/wordpress` or run `wp core download`.
fatal: [104.236.12.218]: FAILED! => {
    "changed": false,
    "cmd": [
        "wp",
        "core",
        "is-installed",
        "--skip-plugins",
        "--skip-themes"
    ],
    "delta": "0:00:00.470767",
    "end": "2022-06-02 16:12:22.850612",
    "failed_when_result": true,
    "invocation": {
        "module_args": {
            "_raw_params": "wp core is-installed --skip-plugins --skip-themes",
            "_uses_shell": false,
            "argv": null,
            "chdir": "/srv/www/{site_var}/releases/20220602161041",
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": true
        }
    },
    "rc": 1,
    "start": "2022-06-02 16:12:22.379845",
    "stderr_lines": [
        "Error: This does not seem to be a WordPress installation.",
        "Pass --path=`path/to/wordpress` or run `wp core download`."
    ],
    "stdout": "",
    "stdout_lines": []
}

Looking at the release directory after the failure, the wp directory is not present despite the composer task executing properly. (it is present in the /current release, the first deploy after applying this patch).

Anyone else having this issue on subsequent deploys?

Subsequent deploys worked fine for me with this PR. :thinking:

When the wp directory is missing, composer failed to install WordPress core?
Do you have the same issue with a pre WordPress 6.x version - but with this PR in place?

Yeah, for me as well?
Instead of roots/wordpress-no-content, can you try roots/wordpress?

1 Like

The fix for me is commenting out “define(‘WPMU_PLUGIN_DIR’, null);” from trellis/roles/deploy/files/tmp_multisite_constants.php

2 Likes

@Mike_Wheeler: This was one of three different variants

as a possible fix.

The now merged-in PR is the fix that separates the check for non-multisites and also ignores this particular PHP warning.

1 Like

You were right on, @Twansparant, my issue is that I was using:

"roots/wordpress-no-content": "^6.0",

instead of

"roots/wordpress": "^6.0",

The first doesn’t require the roots/wordpress-core-installer dependency so my first deploy seems to have worked but subsequent deploys were missing that dependency.

Adjusting to “roots/wordpress”: “^6.0” makes subsequent deploys work, I think I got my wires crossed with the new composer packages.

2 Likes

If there are issues with deploying the new roots/wordpress-no-content (which is awesome by the way), it may not be related to this PR, but caused by another issue.
Edit: roots/wordpress starting with 6.0 should already omit the wp-content/ directory (see below).

1 Like

"roots/wordpress-no-content": "6.0" also deploys fine for me with the new PR.
Edit: Indeed, it doesn’t really work after subsequent deploys. But it may not be necessary as roots/wordpress doesn’t contain wp-content/ anyway anymore starting with version 6.0 (see below).

Likely not, it’s far out of date. Will be doing a more involved droplet-replacing update this summer.