Skip to content

Conversation

@hbhalodia
Copy link

Trac ticket: https://core.trac.wordpress.org/ticket/64071

Screenshots

Publicly accessible Not Publicly Accessible
Screenshot 2026-01-06 at 11 41 28 AM Screenshot 2026-01-06 at 11 42 39 AM

This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props hbhalodia, westonruter.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@hbhalodia
Copy link
Author

Hi Team, Can you please help review and update the wordings if needed?

Thank You,

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

$result['label'] = __( 'Your site is set to log errors to a potentially public file' );
$debug_log_path = WP_DEBUG_LOG === true ? WP_CONTENT_DIR . '/debug.log' : WP_DEBUG_LOG;
$debug_log_path = realpath( $debug_log_path );
$absolute_path = realpath( ABSPATH );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should help ensure that there isn't a false positive of there being another sibling directory name with the same common prefix.

Suggested change
$absolute_path = realpath( ABSPATH );
$absolute_path = realpath( ABSPATH ) . DIRECTORY_SEPARATOR;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, Thanks.

@hbhalodia hbhalodia requested a review from westonruter January 8, 2026 06:49
Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we wanted to go the extra mile, there could be a loopback request to try to actually request the file over HTTP to see if it returns anything. This may not be helpful in the end, however, as the file may not be present if nothing has been written to the log yet. Just an idea.

)
);
} else {
$result['label'] = __( 'Your site is set to log errors to a file outside the public directory' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$result['label'] = __( 'Your site is set to log errors to a file outside the public directory' );
$result['label'] = __( 'Your site is set to log errors to a file outside the document root' );

'<p>%s</p>',
sprintf(
/* translators: %s: WP_DEBUG_LOG */
__( 'The value, %s, has been configured to write errors to a file outside the WordPress directory. This is a good practice as the log file is not publicly accessible.' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__( 'The value, %s, has been configured to write errors to a file outside the WordPress directory. This is a good practice as the log file is not publicly accessible.' ),
__( 'The configuration constant, %s, has been set to write errors to a file outside the WordPress directory. This is a good practice as the log file should not be publicly accessible.' ),

'<p>%s</p>',
sprintf(
/* translators: %s: WP_DEBUG_LOG */
__( 'The value, %s, has been added to this website&#8217;s configuration file. This means any errors on the site will be written to a file which is potentially available to all users.' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__( 'The value, %s, has been added to this website&#8217;s configuration file. This means any errors on the site will be written to a file which is potentially available to all users.' ),
__( 'The constant, %s, has been added to this website&#8217;s configuration file. This means any errors on the site will be written to a file which is likely publicly accessible.' ),

@hbhalodia
Copy link
Author

If we wanted to go the extra mile, there could be a loopback request to try to actually request the file over HTTP to see if it returns anything. This may not be helpful in the end, however, as the file may not be present if nothing has been written to the log yet. Just an idea.

Thanks @westonruter, I thought of an edge case as well, what if there is no any log file present, then realpath will return false, and since we are checking a condition out there related if both the paths are present and if that is public path, then only to consider it as the debugging log is present in public directory, else we can show what we are showing.

@hbhalodia hbhalodia requested a review from westonruter January 8, 2026 07:39
@westonruter
Copy link
Member

I thought of an edge case as well, what if there is no any log file present, then realpath will return false, and since we are checking a condition out there related if both the paths are present and if that is public path, then only to consider it as the debugging log is present in public directory, else we can show what we are showing.

Good point. Well, in that case you could always check to see if ini_get( 'error_log' ) === WP_CONTENT_DIR . '/debug.log' in case the realpath() returns false. This will catch the default case when someone uses the default when setting WP_DEBUG_LOG to true:

if ( in_array( strtolower( (string) WP_DEBUG_LOG ), array( 'true', '1' ), true ) ) {
$log_path = WP_CONTENT_DIR . '/debug.log';

If, however, they do something like:

define( 'WP_DEBUG_LOG`, ABSPATH . 'debug.log' );

Then checking WP_DEBUG_LOG could fail if no logs have been written yet. In that case, if realpath() returns false, then actually there isn't a need to check realpath() on the full error log. All we need to do is check the path to the directory because that's not something which would be automatically created when a new error log entry is written. So I think this can be simplified by turning $debug_log_path = realpath( $debug_log_path ); into $debug_log_path = realpath( dirname( $debug_log_path ) ) . DIRECTORY_SEPARATOR;

if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
$result['label'] = __( 'Your site is set to log errors to a potentially public file' );
$debug_log_path = WP_DEBUG_LOG === true ? WP_CONTENT_DIR . '/debug.log' : WP_DEBUG_LOG;
$debug_log_path = realpath( $debug_log_path );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$debug_log_path = realpath( $debug_log_path );
$debug_log_path = realpath( dirname( $debug_log_path ) ) . DIRECTORY_SEPARATOR;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that could be done. Then I do not think so to check this ini_get( 'error_log' ) === WP_CONTENT_DIR, just check for directory what it is in and show the details. As because, we are always checking with WP_CONTENT_DIR in debug.log

I will update the PR with the requested change.

Comment on lines 1412 to 1413
$debug_log_path = WP_DEBUG_LOG === true ? WP_CONTENT_DIR . '/debug.log' : WP_DEBUG_LOG;
$debug_log_path = realpath( dirname ( $debug_log_path ) ) . DIRECTORY_SEPARATOR;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, technically the WP_DEBUG_LOG doesn't really matter. What matters is the error_log config. It could be that the server is misconfigured to begin with to put the error log in the document root. So I think perhaps instead of defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG it should actually check if ini_get( 'error_log' ) is not empty. And if so, then it can ignore the WP_DEBUG_LOG entirely and just do:

$debug_log_path = realpath( dirname( ini_get( 'error_log' ) ) ) . DIRECTORY_SEPARATOR;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, Got your point. Just check if error_log config as it derives by checking the WP_DEBUG_LOG only,

if ( in_array( strtolower( (string) WP_DEBUG_LOG ), array( 'true', '1' ), true ) ) {
$log_path = WP_CONTENT_DIR . '/debug.log';
} elseif ( is_string( WP_DEBUG_LOG ) ) {
$log_path = WP_DEBUG_LOG;
} else {
$log_path = false;
}
if ( $log_path ) {
ini_set( 'log_errors', 1 );
ini_set( 'error_log', $log_path );

Will update to include that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @westonruter, from the public path we mean that, whatever inside the wp-content or whatever inside the public, (Using localflywheel). Because even if we add something like, ABSPATH . 'logs/debug.log', it is still publicly accessible here, https://example.com/logs/debug.log. So user's need to add there debug.log outside the ABSPATH correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, to be secure it should be outside of ABSPATH.

@hbhalodia hbhalodia requested a review from westonruter January 9, 2026 05:15
);

if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be changed?

Suggested change
if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
if ( ! empty( ini_get( 'error_log' ) ) ) {

Copy link
Author

@hbhalodia hbhalodia Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amm, I thought so as well, but I have kept it as is. This is because the current condition will only provide us if WP_DEBUG_LOG is set or not, and that is enough here for a check. Ultimately we are using ini_get( 'error_log' ) to get the error_log config.

IMO, there is no harm to change this, and also there is no harm to keep as is, as ultimately the output that we need would be same.

Also if we need to consider a performance check, IMO reading from constant would be faster, then calling a function for the same and then toggling the condition via ! empty.

So for first thing, defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG a simple constant hashlookup, while for this, ! empty( ini_get( 'error_log' ) ), a function call to check for value, then check for empty and then toggle condition. Still it's very negligible difference.

I am okay to accomodate the above change, but there is no requirement in it unless you see something specific?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The performance here doesn't matter since it's only when the Site Health tests runs, right? It's not running with request.

My concern is if a server is misconfigured to have an error_log wet to somewhere in the document root (ABSPATH), even if WP_DEBUG_LOG isn't being set.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The performance here doesn't matter since it's only when the Site Health tests runs, right? It's not running with request.

Yes it won't have much impact related to performance, but thought to raise. We can neglect this.

My concern is if a server is misconfigured to have an error_log wet to somewhere in the document root (ABSPATH), even if WP_DEBUG_LOG isn't being set.

If I am understanding correctly, you are saying anyhow someone have set this debug file to use document root, that is, from somewhere they call this, ini_set( 'error_log', 'path-to-document-without-wp-debug-log-constant' ) without explicitly setting the constant value, So in this case, our condition would fail if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {, and it would show the false information.

But that could ever happen? Because let's say WP_DEBUG_LOG is not set and somehow the error_log with document root path is configured, then we are never outputing user that you have enabled debug_log as good practice, instead we would say the default message, Your site is not set to output debug information, though this is misleading as error_log is configured and we need to provide information that it is good practice or not based on the path.

Also, if we use ! empty( ini_get( 'error_log' ) ) it as a condition, the point would again be misleading because we would show whatever message need to show based on path, but we are saying to user that, 'The constant, WP_DEBUG_LOG .....' is set but that is not set as per the edge case we are assuming.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this case: someone may not define WP_DEBUG_LOG at all, but their wp-config.php may have this:

ini_set( 'error_log', __DIR__ . '/error-log.txt' );

This would not be detected as a problem currently in Site Health test, but it would be a similar problem, as if there are any error_log() calls being made, they'll go to that public file. The same issue would happen if the php.ini was set with an error_log set to a public location, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @westonruter, Yes agreeing to the point, Concerning part here is below message to me,

$result['description'] .= sprintf(
	'<p>%s</p>',
	sprintf(
		/* translators: %s: WP_DEBUG_LOG */
		__( 'The constant, %s, has been added to this website&#8217;s configuration file. This means any errors on the site will be written to a file which is likely publicly accessible.' ),
		'<code>WP_DEBUG_LOG</code>'
	)
);

It say's 'The constant, WP_DEBUG_LOG, has been added to this website’s configuration file', but as per the example shared, the WP_DEBUG_LOG is not actually being set, the error log is added by this statement, ini_set( 'error_log', __DIR__ . '/error-log.txt' );, So we need to change the statement here to more generic.

Ideally if I am a user and see's this message, I will first check this constant, WP_DEBUG_LOG, and I would not able to find how this is set (but actually that is not set as per example), hence I would not get an idea that it was set from server or somewhere else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants