First, I need to create a git repository. so I created an account on bitbucket.org, then create a private repository and I cloned that repository into our desktop computer.  and opened the project using Visual Studio Code IDE. 

INSTALLING ESLINT

For fixing javascripts files, I will be using Eslint plugin:

Then open up the console terminal, and create a new package:

npm init -y

then we need to install everything needed by the config: 

npm install @wordpress/eslint-plugin --save-dev

You can see in your package.json there are now a  list of devDependencies.

Create a .eslintrc file in the root of your project’s directory (it should live where package.json does). Your .eslintrc file should look like this:

{
  "extends": [ "plugin:@wordpress/eslint-plugin/recommended" ],
  "parserOptions": {
    "ecmaVersion": 2017
  },
  
  "globals": {
    "$": true,
    "wp":true,
    "console":true,
    "$uifm":true
  },
  "rules": {
    "camelcase": "off",
    "no-console": "off"
  }
}

Tip: You can alternatively put this object in your package.json under the property “eslintConfig”:. This makes one less file in your project.

You can add two scripts to your package.json to lint and/or fix:

"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},

Now you can manually lint your code by running npm run lint and fix all fixable issues with npm run lint:fix. You probably want your editor to do this though.

INSTALLING GIT HOOK

First off, we are going to install Husky, which is the package that lets us do whatever checks we see fit before the commit is made. At the root of your project, run:

npm i husky --save-dev

However, as previously discussed, we only want to run the checks on files that have been staged for commit, and for this to be possible, we need to install another package, namely lint-staged:

npm i lint-staged --save-dev

Last, but not least, we are going to install commitlint, which will let us enforce a particular format for our commit messages. I have opted for one of their pre-packaged formats, namely the conventional one, since I think it encourages commit messages that are simple yet to the point. You can read more about it here.

npm install @commitlint/{config-conventional,cli} --save-dev

## If you are on a device that is running windows
npm install @commitlint/config-conventional @commitlint/cli --save-dev

After the commitlint packages have been installed, you need to create a config that tells commitlint to use the conventional format. You can do this from your terminal using the command below:

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

Great! Now we can move on to the fun part, which is to say implementing our checks!

then our implemented code on package.json would look like this: 

"scripts": {
  "lint": "eslint .",
  "lint:fix": "eslint . --fix"
},
"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},
"lint-staged": {
  "*.js": [
    "eslint --fix"
  ]
},

 

then when you commit a change, your staged js files are fixed automatically. More info on here.

LINTING AND FORMATTING CSS

I installed styllint and prettier: 

npm i -D stylelint prettier

We’ll install a popular set of rules for stylelint

npm i -D stylelint-config-standard

To configure StyleLint to use those rules, create a .stylelintrc.json file in the root directory and tell it which ruleset to extend.

{
"extends": ["stylelint-config-standard"]
}

It works! 🎉 Don’t take my word for it, let’s see. Add this line to your package.json

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint:css": "stylelint *.css"
}

You can now run npm run lint:css in the terminal and stylelint will run for every .css file it finds. If it finds errors, you will see a bunch of npm ERR!s in the console, don’t worry, that’s expected, the linting errors it found are above them. If you would prefer not to see all those npm errors, you could also run that command without using that script we just declared.

./node_modules/.bin/stylelint *.css

Add Prettier
Our styles should have consistent formatting, that will make them easier to read. We’ll set up Stylelint to report formatting issues that Prettier picks up. stylelint-prettier does exactly that.

npm i -D stylelint-prettier

And add it to .stylelintrc

{
"plugins": ["stylelint-prettier"],
"rules": {
"prettier/prettier": true
},
"extends": ["stylelint-config-standard"]
}

When you run lint:css now you’ll see additional errors reported by the prettier/prettier rule.

It’s possible that the rules inside your extends array, or rules you define explicitly conflict with Prettier, causing a catch-22 situation.

We’ll turn off all Stylelint rules specific to formatting and let Prettier handle them, by adding stylelint-config-prettier.

npm i -D stylelint-config-prettier
{
"plugins": ["stylelint-prettier"],
"rules": {
"prettier/prettier": true
},
"extends": ["stylelint-config-standard", "stylelint-config-prettier"]
}

Displaying those errors in your editor (in realtime!)

Everybody loves red squiggly lines in their code editor (somewhere else, and you probably typed a word your dictionary doesn’t know. Like “hello” or something stupid like that.)

Install a Stylelint plugin for your editor. I’m using VSCode, so I picked the aptly named sylelint one.

You will now see the errors listed inside the PROBLEMS tab and there will be red lines underneath each one right in your code.

Automatically fix problems
Many issues (especially the formatting ones) are able to be fixed automatically. The only thing that’s needed is to add the –fix flag to our script.

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint:css": "stylelint *.css --fix"
}

When we run lint:css now, stylelint will automatically try to fix every issue it can. This won’t result in the PROBLEMS tab being empty now, but the list of problems will be much smaller.

While it absolutely isn’t, to me this feels like magic.

Never forget to fix problems
Very neat, but if you’re anything like me, you’ll forget to do this from time to time. That’s why we’ll set up a way to automatically run the command above.

This section assumes the project uses the git version control manager.

We’ll hook into git using a package called husky and tell it to run our command before each commit. This has the added benefit of that command running for everyone that commits code.

To minimize the time this takes, we only run the command for files that are currently staged in git. This is a huge time-saver (especially for larger projects).

npm i -D husky lint-staged

in package.json Tell husky to run lint-staged right before you commit code to your git-repository. Configure lint-staged to run stylelint –fix on any .css file that is going to be committed. This will (potentially) change that file, the file will be added to git again afterwards!

"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.css*": [
"stylelint --fix"
]
}

The git hook at work

Enforce wordpress code standards with composer, git hooks, phpcs, and phpcbf

Maintaining code quality on projects where there are many developers contributing is a tough assignment. How many times have you tried to contribute to an open-source project only to find the maintainer rejecting your pull request on the grounds of some invisible coding standard? How many times as a maintainer of an open-source project (or internal) have you had a hard time reading code because there were careless tabs/spaces mixed, if statements with no brackets, and other such things. Luckily there are tools that can assist maintainers.  I’ll be going over how to use composer, git hooks, and phpcbf to enforce code quality rules.

There are a couple of things to keep in mind. First, you want this process to be as simple as possible. Secondly, you want it to be easy to run when necessary. Finally, you want it to be universally accepted as part of your contribution procedure.

What if I told you that it could be done without the developer even knowing it’s happening?

Most modern PHP projects use composer as their dependency manager. Before you can make anything work, you need to run composer install. This is where the magic happens.

Phpcs Dependency
First, we need a development dependency specified to install phpcs. It looks something like this:

{   "require-dev": {
        "squizlabs/php_codesniffer": "3.*",
        "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
        "object-calisthenics/phpcs-calisthenics-rules": "*",
        "phpcompatibility/php-compatibility": "*",
        "wp-coding-standards/wpcs": "*"
    },
}

Composer has a handy schema entry called scripts. It supports a script hook post-install-cmd. We will use this to install a git pre-commit hook. Adding to our example above:

{
    "require-dev": {
        "squizlabs/php_codesniffer": "3.*",
        "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
        "object-calisthenics/phpcs-calisthenics-rules": "*",
        "phpcompatibility/php-compatibility": "*",
        "wp-coding-standards/wpcs": "*"
    },
    "scripts": {
        "post-install-cmd": [
            "bash _tools/setup.sh"
        ]
    }
}

This will run a bash script called setup.sh when the command composer install is run.

In our setup.sh, we will need to copy a pre-commit script into the .git/hooks directory:

#!/bin/sh

cp contrib/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

This will copy our pre-commit script from the contrib directory to the hooks section of the special git directory and make it executable.

Whenever a contributing developer attempts to commit their code, it will run our pre-commit script. Now all we need to do is run the code sniffer rules on relavent files specific to this commit:

#!/bin/sh

PROJECT=`php -r "echo dirname(dirname(dirname(realpath('$0'))));"`
STAGED_FILES_CMD=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`

JS_FILES=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.js`

STYLE_FILES=$(git diff --cached --name-only --diff-filter=ACMR -- '*.css' '*.scss' '*.sass' '*.less' | xargs)

# Determine if a file list is passed
if [ "$#" -eq 1 ]
then
  oIFS=$IFS
  IFS='
  '
  SFILES="$1"
  IFS=$oIFS
fi
SFILES=${SFILES:-$STAGED_FILES_CMD}

echo "Checking PHP Lint..."
for FILE in $SFILES
do
  php -l -d display_errors=0 $PROJECT/$FILE
  if [ $? != 0 ]
  then
    echo "Fix the error before commit."
    exit 1
  fi
  FILES="$FILES $PROJECT/$FILE"
done

if [ "$FILES" != "" ]
then
  echo "Running Code Sniffer..."
  ./vendor/bin/phpcs --standard=Wordpress-Core --encoding=utf-8 -n -p $FILES
  if [ $? != 0 ]
  then
    echo "Coding standards errors have been detected. Running phpcbf..."
    ./vendor/bin/phpcbf --standard=Wordpress-Core --encoding=utf-8 -n -p $FILES
    git add $FILES
    echo "Running Code Sniffer again..."
    ./vendor/bin/phpcs --standard=Wordpress-Core --encoding=utf-8 -n -p $FILES
    if [ $? != 0 ]
    then
      echo "Errors found not fixable automatically. You need to manually fix them."
      exit 1
    fi
  fi
fi

echo "Checking JS Lint..."
for file in $JS_FILES
do
echo $file
 ./node_modules/.bin/eslint --fix $file
  git add $file
  if [ $? -ne 0 ]; then
    echo "Fix the error before commit please"
    exit 1 # exit with failure status
  fi
done

echo "Checking CSS Lint..."
for file in $STYLE_FILES
do
echo $file
 node_modules/.bin/stylelint --fix $file
  git add $file
  if [ $? -ne 0 ]; then
    echo "Fix the error before commit please"
    exit 1 # exit with failure status
  fi
done

exit $?

This script will get the staged files of the commit, run a php lint check (always nice), and apply the code sniffer rules to the staged files. also it will run a css and js lint check. 

remember adding a custom git hook will disable Husky.

If there is a code standards violation, the phpcs process will return a non-zero exit status which will tell git to abort the commit.

Bringing it all together

With all of these things in place, the workflow is as follows:

– Developer runs composer install.
– PHP Code Sniffer is installed via a dev dependency.
– The post-install command automatically copies the pre-commit hook into the developer’s local git hooks.
– When the developer commits code, the pre-commit hook fires and checks the staged files for coding standards violations and lint checks.

This is a relatively simple setup that can save pull request code reviews a significant amount of time preventing back-and-forth on simple things such as mixed tabs/spaces, bracket placement, etc.

and finally my package.json would look like this:

{
  "name": "your-project",
  "version": "1.0.0",
  "description": "",
  "main": "test.js",
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint test/. --fix",
    "format-test:prettier": "node_modules/.bin/prettier --config .prettierrc --write \"test/*.{css,js}\" ",
    "lint:css": "node_modules/.bin/stylelint test/*.css --fix",
    "post-install-cmd": "phpcbf prueba.php",
    "php:check": "vendor/bin/phpcs --standard=WordPress --extensions=php . > check.txt",
    "php:fix": "vendor/bin/phpcbf --standard=WordPress --extensions=php ."
  }
  "repository": {
    "type": "git",
    "url": ""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "homepage": "",
  "devDependencies": {
    "@commitlint/cli": "^8.3.5",
    "@commitlint/config-conventional": "^8.3.4",
    "babel-eslint": "^9.0.0",
    "eslint": "^5.14.1",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-config-prettier": "^4.1.0",
    "eslint-config-wesbos": "0.0.19",
    "eslint-plugin-html": "^5.0.3",
    "eslint-plugin-import": "^2.16.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-prettier": "^3.0.1",
    "eslint-plugin-react": "^7.12.4",
    "eslint-plugin-react-hooks": "^1.3.0",
    "husky": "^4.2.5",
    "lint-staged": "^10.1.7",
    "prettier": "^1.19.1",
    "stylelint": "^13.3.3",
    "stylelint-config-prettier": "^8.0.1",
    "stylelint-config-standard": "^20.0.0",
    "stylelint-prettier": "^1.1.2"
  }
}

INTEGRATING WITH VISUAL STUDIO CODE

Installing Prettier, eslint, phpcbf will make it to format the code automatically in visual mode. 

I exported my list of extensions:

code --list-extensions > extensions.list

and this is the list:

abusaidm.html-snippets
AdamCaviness.theme-monokai-dark-soda
bierner.lit-html
bmewburn.vscode-intelephense-client
bradlc.vscode-tailwindcss
ctf0.close-tabs-to-the-left
dbaeumer.jshint
dbaeumer.vscode-eslint
DEVSENSE.phptools-vscode
dracula-theme.theme-dracula
ecodes.vscode-phpmd
EditorConfig.EditorConfig
Equinusocio.vsc-community-material-theme
Equinusocio.vsc-material-theme
equinusocio.vsc-material-theme-icons
esbenp.prettier-vscode
felixfbecker.php-debug
felixfbecker.php-pack
HookyQR.beautify
ikappas.composer
ikappas.phpcs
j-zeppenfeld.tab-indent-space-align
kokororin.vscode-phpfmt
linyang95.php-symbols
liximomo.sftp
maddog986.autodocblocker
mikestead.dotenv
monokai.theme-monokai-pro-vscode
neilbrayfield.php-docblocker
onecentlin.laravel-blade
persoderlind.vscode-phpcbf
PKief.material-icon-theme
rvest.vs-code-prettier-eslint
ryannaddy.laravel-artisan
sevavietl.php-files
stylelint.vscode-stylelint
valeryanm.vscode-phpsab
vincaslt.highlight-matching-tag
wongjn.php-sniffer
xyz.local-history
zhuangtongfa.material-theme

and here my settings.json configuration:

{
    "window.zoomLevel": 0,
    "emmet.excludeLanguages": [
        "markdown",
        "php"
    ],
    "files.associations": {
        "*.phtml": "php"
    },
    "workbench.iconTheme": "material-icon-theme",
    "emmet.triggerExpansionOnTab": true,
    "blade.format.enable": true,
   
    // Linters Configuration
    // PHP Linter
    "php.validate.enable": false,
    "php.validate.run": "onType",
    "files.eol": "\n",
    //"phpcbf.standard": "WordPress",
    "phpmd.command": "C:/Users/Admin/AppData/Roaming/Composer/vendor/bin/phpmd.bat",
   
    //some settings from outthere
    "phpcs.standard": "WordPress-Core",
    "phpcbf.standard": "WordPress-Core",
    "phpcbf.executablePath": "C:/Users/Admin/AppData/Roaming/Composer/vendor/bin/phpcbf.bat",
    "stylelint.enable": true,
    "css.validate": false,
    "scss.validate": false,
    "editor.formatOnPaste": false,
    "editor.formatOnSave": false,
    "prettier.eslintIntegration": true,
    //"prettier.bracketSpacing": true,
    //"editor.autoIndent": false,
    "[css]": {
        "editor.formatOnSave": false,
        "editor.defaultFormatter": "esbenp.prettier-vscode",
    },
    "[php]": {
        "editor.detectIndentation": true,
        "editor.useTabStops": true,
        "editor.formatOnSave": false,
        "editor.insertSpaces": false,
        "editor.defaultFormatter": "persoderlind.vscode-phpcbf",
       
    },
    "[javascript]": {
        "editor.insertSpaces": false,
        "editor.detectIndentation": true,
        "editor.formatOnSave": false,
        "editor.useTabStops": true,
        "editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
    },
    "[json]": {
        "editor.formatOnSave": false
    },
    "[xml]": {
        "editor.formatOnSave": false
    },
    "workbench.colorTheme": "One Dark Pro",
    "phpfmt.indent_with_space": 0,
    "beautify.language": {
        "js": {
            "type": [
                "javascript",
                "json"
            ],
            "filename": [
                ".jsbeautify"
            ]
        },
        "css": [
            "css",
            "scss"
        ],
        "html": [
            "htm",
            "html",
            "php",
            "blade"
        ]
    },
    "workbench.editor.limit.value": 50,
    "editor.insertSpaces": false,
    "eslint.codeAction.showDocumentation": {},
    // Optional BUT IMPORTANT: If you have the prettier extension enabled for other languages like CSS and HTML, turn it off for JS since we are doing it through Eslint already
    //"prettier.disableLanguages": ["javascript", "javascriptreact"],
   /* "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    },*/
}

after setting up your visual studio code IDE, you will have powerful tools to developer wordpress projects without worrying about coding standards.