WordPress-Coding-Standards icon indicating copy to clipboard operation
WordPress-Coding-Standards copied to clipboard

WP-Core produces inconsistent indentation

Open justingolden21 opened this issue 8 months ago • 6 comments

Bug Description

WP-Core produces inconsistent indentation

https://github.com/user-attachments/assets/04e12f56-7e91-4ac7-b516-8ba7a203f777

Minimal Code Snippet

<div 
<?php
if ( false ) {
	echo 'class="hi"';
}
?>
></div>

Running with WordPress-Core standard in phpcs / phpcbf

Error Code

N/A

Environment

php -v PHP 8.1.10 (cli) (built: Aug 30 2022 18:08:04) (NTS Visual C++ 2019 x64) Copyright (c) The PHP Group Zend Engine v4.1.10, Copyright (c) Zend Technologies

composer info dealerdirect/phpcodesniffer-composer-installer contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins Do you trust "dealerdirect/phpcodesniffer-composer-installer" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?] y clue/ndjson-react v1.3.0 Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP. composer/pcre 3.3.2 PCRE wrapping library that offers type-safe preg_* replacements. composer/semver 3.4.3 Semver library that offers utilities, version constraint parsing and validation. composer/xdebug-handler 3.0.5 Restarts a process without Xdebug. dealerdirect/phpcodesniffer-composer-installer v1.0.0 PHP_CodeSniffer Standards Composer Installer Plugin evenement/evenement v3.0.2 Événement is a very simple event dispatching library for PHP fidry/cpu-core-counter 1.2.0 Tiny utility to get the number of CPU cores. friendsofphp/php-cs-fixer v3.72.0 A tool to automatically fix PHP code style php-stubs/acf-pro-stubs v6.0.6 Advanced Custom Fields PRO stubs for static analysis. php-stubs/wordpress-stubs v6.2.0 WordPress function and class declaration stubs for static analysis. phpcompatibility/php-compatibility 9.3.5 A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility. phpcompatibility/phpcompatibility-paragonie 1.3.3 A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while acco...
phpcompatibility/phpcompatibility-wp 2.1.6 A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting f...
phpcsstandards/phpcsextra 1.2.1 A collection of sniffs and standards for use with PHP_CodeSniffer. phpcsstandards/phpcsutils 1.0.12 A suite of utility functions for use with PHP_CodeSniffer psr/container 2.0.2 Common Container Interface (PHP FIG PSR-11) psr/event-dispatcher 1.0.0 Standard interfaces for event handling. psr/log 3.0.2 Common interface for logging libraries react/cache v1.2.0 Async, Promise-based cache interface for ReactPHP react/child-process v0.6.6 Event-driven library for executing child processes with ReactPHP. react/dns v1.13.0 Async DNS resolver for ReactPHP react/event-loop v1.5.0 ReactPHP's core reactor event loop that libraries can use for evented I/O. react/promise v3.2.0 A lightweight implementation of CommonJS Promises/A for PHP react/socket v1.16.0 Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP react/stream v1.4.0 Event-driven readable and writable streams for non-blocking I/O in ReactPHP sebastian/diff 5.1.1 Diff implementation squizlabs/php_codesniffer 3.11.3 PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.
symfony/console v6.4.17 Eases the creation of beautiful and testable command line interfaces symfony/deprecation-contracts v3.5.1 A generic function and convention to trigger deprecation notices symfony/event-dispatcher v6.4.13 Provides tools that allow your application components to communicate with each other by dispatching events and li...
symfony/event-dispatcher-contracts v3.5.1 Generic abstractions related to dispatching event symfony/filesystem v6.4.13 Provides basic utilities for the filesystem symfony/finder v6.4.17 Finds files and directories via an intuitive fluent interface symfony/options-resolver v6.4.16 Provides an improved replacement for the array_replace PHP function symfony/polyfill-ctype v1.31.0 Symfony polyfill for ctype functions symfony/polyfill-intl-grapheme v1.31.0 Symfony polyfill for intl's grapheme_* functions symfony/polyfill-intl-normalizer v1.31.0 Symfony polyfill for intl's Normalizer class and related functions symfony/polyfill-mbstring v1.31.0 Symfony polyfill for the Mbstring extension symfony/polyfill-php80 v1.31.0 Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions symfony/polyfill-php81 v1.31.0 Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions symfony/process v6.4.19 Executes commands in sub-processes symfony/service-contracts v3.5.1 Generic abstractions related to writing services symfony/stopwatch v6.4.19 Provides a way to profile code symfony/string v6.4.15 Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a uni...
wp-coding-standards/wpcs 3.1.0 PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions

VS Code

justingolden21 avatar Mar 18 '25 22:03 justingolden21

@justingolden21 Not sure what you are trying to report. The video doesn't play and if I run the WordPress-Core standard against the provided code sample, there are "no violations found".

In other words, this is not reproducible and this issue will be closed unless a proper reproduction sample is provided.

jrfnl avatar Mar 18 '25 23:03 jrfnl

@justingolden21 is this issue related to the linter extension you are using in your editor? If so, that is out of scope of this repo.

dingo-d avatar Mar 19 '25 06:03 dingo-d

@jrfnl thank you for the quick reply. The video does play on my end, so I'm not sure about video playing issues, if it's a file format/browser thing or what. It's an mp4 file. The video demonstrates that there is no one indentation standard being applied, and that depending on what level I indent certain lines, I get different results. Also, those results are not only inconsistent, but provide significantly too many tabs.

Example:

The following line:

<div id="<?php echo $fields['id']; ?>" <?php if (!empty($fields['screen_height_placeholder']) && $fields['screen_height_placeholder']) echo 'class="min-h-screen overflow-y-auto"'; ?>></div>

Becomes formatted to:

<div id="<?php echo $fields['id']; ?>" 
					<?php
					if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
						echo 'class="min-h-screen overflow-y-auto"';}
					?>
></div>

With five and six tabs of indentation.

Upon changing to:

<div id="<?php echo $fields['id']; ?>" 
<?php
					if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
						echo 'class="min-h-screen overflow-y-auto"';}
					?>
></div>

It formats to:

<div id="<?php echo $fields['id']; ?>" 
<?php
if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
	echo 'class="min-h-screen overflow-y-auto"';}
?>
></div>

Upon changing to:

<div id="<?php echo $fields['id']; ?>" <?php
					if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
						echo 'class="min-h-screen overflow-y-auto"';}
					?>
></div>

It formats to:

<div id="<?php echo $fields['id']; ?>" 
					<?php
					if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
						echo 'class="min-h-screen overflow-y-auto"';}
					?>
></div>

Upon changing to:

<div id="<?php echo $fields['id']; ?>" 
								<?php
								if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
									echo 'class="min-h-screen overflow-y-auto"';}
								?>
></div>

It produces no changes.

Upon changing to:

<div id="<?php echo $fields['id']; ?>" 
								<?php
													if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
									echo 'class="min-h-screen overflow-y-auto"';}
								?>
></div>

It formats to:

<div id="<?php echo $fields['id']; ?>" 
								<?php
								if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
									echo 'class="min-h-screen overflow-y-auto"';}
								?>
></div>

Upon changing to:

<div id="<?php echo $fields['id']; ?>" 
								<?php
								if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
												echo 'class="min-h-screen overflow-y-auto"';}
								?>
></div>

It produces no change.

Upon changing to:

<div id="<?php echo $fields['id']; ?>" 
								<?php
								if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
												echo 'class="min-h-screen overflow-y-auto"';}
												?>
></div>

It changes to:

<div id="<?php echo $fields['id']; ?>" 
								<?php
								if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
												echo 'class="min-h-screen overflow-y-auto"';}
								?>
></div>

These are a few examples of how the initial condition produces widely different results, and these results exhibit very poor and incorrect indentation. I would personally consider this a bug.

Thanks again for the reply, and let me know if I'm opening an issue in the wrong place.

justingolden21 avatar Mar 19 '25 18:03 justingolden21

I am using phpcs with "WordPress-Core" as the standard. So I'm using a linter, but it is following the coding standards defined here without any modification to the standards whatsoever.

justingolden21 avatar Mar 19 '25 18:03 justingolden21

Another minimal reproducible example:

<div class="contents <?php if(!empty($post_description)) { echo 'opacity-100 lg:group-hover:opacity-0 transition-opacity'; } ?>">
</div>

Gets formatted to:

<div class="contents <?php if (!empty($post_description)) {
							echo 'opacity-100 lg:group-hover:opacity-0 transition-opacity';
						} ?>">
</div>

With six and seven indentation levels more.

justingolden21 avatar Mar 19 '25 18:03 justingolden21

With the second provided snippet in my phpcs-test.php file:

<div id="<?php echo $fields['id']; ?>" <?php if (!empty($fields['screen_height_placeholder']) && $fields['screen_height_placeholder']) echo 'class="min-h-screen overflow-y-auto"'; ?>></div>

when I run phpcs -s --standard=WordPress-Core phpcs-test.php, I get:

 1 | ERROR | [x] Inline control structures are not allowed (Generic.ControlStructures.InlineControlStructure.NotAllowed)
 1 | ERROR | [x] Expected 1 space before "!"; 0 found (WordPress.WhiteSpace.OperatorSpacing.NoSpaceBefore)
 1 | ERROR | [x] Expected 1 space after "!"; 0 found (WordPress.WhiteSpace.OperatorSpacing.NoSpaceAfter)
 1 | ERROR | [x] Expected 1 spaces after opening parenthesis; 0 found (PEAR.Functions.FunctionCallSignature.SpaceAfterOpenBracket)
 1 | ERROR | [x] Expected 1 spaces before closing parenthesis; 0 found (PEAR.Functions.FunctionCallSignature.SpaceBeforeCloseBracket)

When I run phpcbf --standard=WordPress-Core phpcs-test.php, I get the five issues fixed, and file contents of:

<div id="<?php echo $fields['id']; ?>" 
					<?php
					if ( ! empty( $fields['screen_height_placeholder'] ) && $fields['screen_height_placeholder'] ) {
						echo 'class="min-h-screen overflow-y-auto"';}
					?>
></div>

That's 5 tabs before the second PHP delimiter.

If I run it again, I get no change.

GaryJones avatar Mar 21 '25 21:03 GaryJones