These are some steps and procedures I follow & recommend to protect your WordPress sites or projects. Keep in mind, doing something even slightly different can cause issues and your project might crash.

1] Changes in wp-config file

Change your uploads directory to something outside the “wp-content” folder. You will have to do this right after installing WordPress or changing things later might be a hassle. Write this in your wp-config.php file.

define( 'UPLOADS', ''.'asset' );

An asset file will be created in the root folder of your site.

Disable file editing inside WordPress by adding this

define( 'DISALLOW_FILE_EDIT', true );

2] Changes in your functions.php file in your theme folder.

Hide WordPress version & other metadata type information on your site. Add this to your functions.php file.

 remove_action( 'wp_head', 'wp_generator' ) ;
 remove_action( 'wp_head', 'wlwmanifest_link' ) ;
 remove_action( 'wp_head', 'rsd_link' ) ;

Remove HTML in WordPress comments section by adding this to your functions.php file

add_filter( 'pre_comment_content', 'esc_html' );

Reduce the number of post saves (Revisions) in WordPress. It takes up some database space so its better to limit the same.

define( 'WP_POST_REVISIONS', 5);

Remove useless WordPress RSS Feeds.

remove_action( 'wp_head', 'feed_links', 2 );
remove_action( 'wp_head', 'feed_links_extra', 3 );

Disable Failed WordPress Login Hints.

function no_wordpress_errors(){
 return 'Something is wrong!';
}
add_filter( 'login_errors', 'no_wordpress_errors' );

Disable Admin Bar (Top) by adding this to your functions.php file

add_filter('show_admin_bar', '__return_false');

Remove Emojis by adding this to your functions.php file

remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );

So your final functions.php file looks like this:

{ …… Theme Content …… }

remove_action( 'wp_head', 'wp_generator' ) ;
remove_action( 'wp_head', 'wlwmanifest_link' ) ;
remove_action( 'wp_head', 'rsd_link' ) ;
add_filter( 'pre_comment_content', 'esc_html' );
remove_action( 'wp_head', 'feed_links', 2 );
remove_action( 'wp_head', 'feed_links_extra', 3 );
add_filter('show_admin_bar', '__return_false');
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );

function no_wordpress_errors(){
 return 'Something is wrong!';
}
add_filter( 'login_errors', 'no_wordpress_errors' );

3] Protection from your directory configuration file. (.htaccess)

Disable people from browsing your folders by adding this to your .htaccess file

Options All -Indexes

Hide XML Sitemaps from Search Engines by adding this (Change sitemap.xml to actual filename)

<IfModule mod_rewrite.c>
<Files sitemap.xml>
Header set X-Robots-Tag "noindex"
</Files>
</IfModule>

Remove extra Query Parameters from URLs

When a server receives a request for such a page, it may run a program, passing the query_string unchanged to the program. The question mark is used as a separator and is not part of the query string. Add this little snippet to your .htaccess file and it will strip the unnecessary query parameters from all incoming requests.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} !=""
RewriteCond %{QUERY_STRING} !^p=.*
RewriteCond %{QUERY_STRING} !^s=.*
RewriteCond %{REQUEST_URI} !^/wp-admin.*
RewriteRule ^(.*)$ /$1? [R=301,L]
</IfModule>

Disable PHP execution in directories

Sometimes hackers break into a WordPress site and install a backdoor. These backdoor files are often disguised as core WordPress files and are placed in /wp-includes/ or /wp-content/uploads/ folders. Adding this will disable the php execution in certain directories (To where you create a htaccess file and paste the code snippet). Adding this in your root htaccess will break your site & throw a 403 error.

<Files *.php>
deny from all
</Files>

OR

The uploads directory is the one directory that will almost need to be writable by the web server. It’s where all files are uploaded remotely. You want to prevent PHP execution in this directory, you can do this by placing an .htaccess at the root of /UPLOADS using:

# Kill PHP Execution
<Files ~ "\.ph(?:p[345]?|t|tml)$">
deny from all
</Files>

Note: This can break your theme if it requires PHP execution in UPLOADS. If you apply it and the site breaks, remove it and the site will reappear.

Protecting the WordPress Configuration (wp-config.php) File

<files wp-config.php>
order allow,deny
deny from all
</files>

Protect .htaccess From Unauthorized Access

<files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
satisfy all
</files>

Disable Access to XML-RPC File Using .htaccess

# Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>

Blocking Author Scans in WordPress

A common technique used in brute force attacks is to run author scans on a WordPress site and then attempt to crack passwords for those usernames.

# BEGIN block author scans
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} (author=\d+) [NC]
RewriteRule .* - [F]
# END block author scans

Blocking WP-Includes

A second layer of protection can be added where scripts are generally not intended to be accessed by any user. One way to do that is to block those scripts using mod_rewrite in the .htaccess file. Note: to ensure the code below is not overwritten by WordPress, place it outside the # BEGIN WordPress and # END WordPress tags in the .htaccess file. WordPress can overwrite anything between these tags.

# Block the include-only files.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
# BEGIN WordPress

4] Don’t let others make changes to your site files. (Protect your permissions)

Login to your web hosting server using ssh & enter your site directory (root).

Run this command to check if there are any permissions errors:

find . -type d -perm -o=w

If there are any, run the following commands to fix them:

find /your/wordpress/folder/ -type d -exec chmod 755 {} \;
find /your/wordpress/folder/ -type f -exec chmod 644 {} \;

To explain in short, the files should have permissions of 644 and the directories should have permissions of 755.
755 = Owner has write permission while others have read and execute permissions.
644 = Owners have read and write permissions while others can only read the files.

Everything to add in htaccess :

Options All -Indexes

#Protecting the WordPress Configuration File
<files wp-config.php>
order allow,deny
deny from all
</files>

# Hide XML Sitemaps from Search Engines
<IfModule mod_rewrite.c>
<Files sitemap_index.xml>
 Header set X-Robots-Tag "noindex"
 </Files>
</IfModule>

#Remove extra Query Parameters from URLs
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} !=""
 RewriteCond %{QUERY_STRING} !^p=.*
 RewriteCond %{QUERY_STRING} !^s=.*
 RewriteCond %{REQUEST_URI} !^/wp-admin.*
 RewriteRule ^(.*)$ /$1? [R=301,L]
</IfModule>

# Block the include-only files.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

#Protect .htaccess From Unauthorized Access
<files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
satisfy all
</files>

# Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>

# BEGIN block author scans
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} (author=\d+) [NC]
RewriteRule .* - [F]
</IfModule>

4] Change Permalink Structure

It’s a good habit of using a specific permalink. This is is my favourite:

/%category%/%postname%/%post_id%/

It is also a good habit to disable attachment pages. If you are using Yoast SEO plugin, you can do it using that plugin itself. In Advanced >> Permalink >>

Redirect attachment URLs to parent post URL.

Click on Redirect.

Also turn on the above option to remove the “category” tag

5] Use Plugins like Loginizer & WordFence.