WordPress Plugins

User Posts Limit

How to make some user unrestricted in rules that applied on certain post type?
Update the user id and the post type:

add_filter( 'upl_query', 'upl_unrestrict_user' );
function upl_unrestrict_user( $args ) {
	$post_type = 'post';
	$user_id = 12;
	if ( $post_type === $args['post_type'] && $user_id === $args['author'] ) {
		$args['post_type'] = 'none';
	return $args;

How to make rules that applied on certain post type to limit the total posts in the website?
Update the post type:

add_filter( 'upl_query', 'upl_limit_total_posts' );
function upl_limit_total_posts( $args ) {
	$post_type = 'post';
	if ( $post_type === $args['post_type'] ) {
		$args['author'] = '';
	return $args;

How to make rules that applied on certain post type to limit by posts in specific category only?
Update the post type and the category id (make sure users can’t migrate posts into unrestricted posts category):

add_filter( 'upl_query', 'upl_specific_category' );
function upl_specific_category( $args ) {
	$post_type = 'post';
	$category_id = 4;
	if ( $post_type === $args['post_type'] ) {
		$args['cat'] = $category_id;
	return $args;

How to make rules that applied on certain post type to limit specific post status?
Update the post type and the post status (make sure users can’t migrate posts into unrestricted post status):

add_filter( 'upl_query', 'upl_specific_post_status' );
function upl_specific_post_status( $args ) {
	$post_type = 'post';
	$post_status = [ 'any' ];
	if ( $post_type === $args['post_type'] ) {
		$args['post_status'] = $post_status;
	return $args;

How to modify the cycle for rules that applied on certain post type?
Update the post type and the cycle (keep in mind that the change will not take affect in places that the date is displayed):

add_filter( 'upl_query', 'upl_modify_cycle' );
function upl_modify_cycle( $args ) {
	$post_type = 'post';
	$cycle = '3 days ago';
	if ( $post_type === $args['post_type'] ) {
		$args['date_query']['after'] = $cycle;
	return $args;

How to send users an Email to encourage them to upgrade their membership after they try to post after posts limit exceeded?
Attach your code for sending Email to the upl_limit_applied action hook.

How to define different message types for each user?
Use the upl_message and upl_notice filters.

How to add limit with code?
Update the role, type, limit and cycle:

$role = 'author';
$type = 'post';
$limit = '2';
$cycle = 'day';
$formatted_cycle = '1 ' . $cycle . ' ago';
$role_option = get_option( 'upl_user_role' );
$type_option = get_option( 'upl_posts_type' );
$limit_option = get_option( 'upl_num_limit' );
$period_option = get_option( 'upl_period' );
$role_option[] = $role;
$type_option[] = $type;
$limit_option[] = $limit;
$period_option[] = $formatted_cycle;
update_option( 'upl_rules_count', get_option( 'upl_rules_count' ) + 1 );
update_option( 'upl_user_role', $role_option );
update_option( 'upl_posts_type', $type_option );
update_option( 'upl_num_limit', $limit_option );
update_option( 'upl_period', $period_option );

How to modify the limits in all the rules that applied on specified user role with code?
Update the role and limit:

for ( $i = 0; $i < get_option( 'upl_rules_count' ); $i++ ) {
	$role = 'subscriber';
	$limit = '3';
	if ( $role === get_option( 'upl_user_role' )[ $i ] ) {
		$limit_option = get_option( 'upl_num_limit' );
		$limit_option[ $i ] = $limit;
		update_option( 'upl_num_limit', $limit_option );

How to reset user’s posts counts when purchase some product in WooCommerce (by the end of the day)?
Update the product id:

add_action( 'woocommerce_order_status_completed', 'upl_update_user_cycle' );
add_filter( 'upl_query', 'upl_users_cycle', 10, 2 );
add_action( 'show_user_profile', 'upl_add_cycle_user_data' );
add_action( 'edit_user_profile', 'upl_add_cycle_user_data' );
add_action( 'personal_options_update', 'upl_save_cycle_user_data' );
add_action( 'edit_user_profile_update', 'upl_save_cycle_user_data' );
add_filter( 'manage_users_columns', 'upl_cycle_user_table' );
add_filter( 'manage_users_custom_column', 'upl_cycle_user_table_row', 10, 3 );

function upl_update_user_cycle( $order_id ) {
	$product_id = '683';
	$order = wc_get_order( $order_id );
	$user_id = $order->get_user_id();
	if ( ! user_can( $user_id, 'manage_options' ) ) {
		foreach ( $order->get_items() as $item ) {
			if ( $product_id == $item->get_product_id() ) {
				if ( empty( get_user_meta( $user_id, 'cycle', true ) ) || get_user_meta( $user_id, 'cycle', true ) <= current_time( 'Y-m-d' ) ) {
					update_user_meta( $user_id, 'cycle', date( 'Y-m-d', strtotime( current_time( 'Y-m-d' ) . ' + 1 day' ) ) );

function upl_users_cycle( $args, $i ) {
	if ( ! user_can( $args['author'], 'manage_options' ) ) {
		$rule_role = '';
		$cycle = get_user_meta( $args['author'], 'cycle', true );
		if ( ( empty( $rule_role ) || $rule_role === get_option( 'upl_user_role' )[ $i ] ) && ! empty( $cycle ) && $cycle <= current_time( 'Y-m-d' ) ) {
			$args['date_query']['after'] = date( 'Y-m-d', strtotime( $cycle . ' - 1 day' ) );
	return $args;

function upl_add_cycle_user_data( $user ) {
	if ( current_user_can( 'manage_options' ) ) {
			<h3><?php esc_html_e( 'User Posts Limit', 'user-posts-limit' ); ?></h3>
			<table class="form-table">
					<th><label for="cycle"><?php esc_html_e( 'Cycle', 'user-posts-limit' ); ?></label></th>
					<td><input type="date" min="1970-01-01" name="cycle" value="<?php echo esc_attr( get_user_meta( $user->ID, 'cycle', true ) ); ?>" class="regular-text" /></td>
			<br />

function upl_save_cycle_user_data( $user_id ) {
	if ( current_user_can( 'manage_options' ) ) {
		update_user_meta( $user_id, 'cycle', sanitize_text_field( $_POST['cycle'] ) );

function upl_cycle_user_table( $columns ) {
	$columns['cycle'] = __( 'Cycle', 'user-posts-limit' );
	return $columns;

function upl_cycle_user_table_row( $row_output, $column_id_attr, $user_id ) {
	if ( 'cycle' === $column_id_attr ) {
		return get_user_meta( $user_id, 'cycle', true );
	return $row_output;

How to make the listing rules apply seperately on every listing type in MyListing theme?

add_filter( 'upl_query', 'upl_add_meta_query' );
function upl_add_meta_query( $args ) {
	if ( 'job_listing' === $args['post_type'] && isset( $_POST['listing_type'] ) ) {
		$args['meta_query'] = [
				'key'	=> '_case27_listing_type',
				'value'	=> sanitize_text_field( $_POST['listing_type'] )
	return $args;

WooCommerce Popups

And the Jazz Artists.

Install the plugin.

In WooCommerce notify the customer product page about discount ineligibility since purchase not enough items from it- add the Auto Open trigger, targeting the desired product id page, and the custom conditions (update the product id and the quantity for discount):

add_filter( 'pum_get_conditions', 'condless_pum_cart_product_quantity_conditions' );
function condless_pum_cart_product_quantity_conditions( $conditions ) {
	return array_merge( $conditions, [
		'password_page_unlocked' => [
			'group'		=> __( 'Products', 'woocommerce' ),
			'name'		=> __( 'Products', 'woocommerce' ) . ': ' . __( 'Cart', 'woocommerce' ) . ' ' . __( 'Quantity', 'woocommerce' ),
			'callback'	=> 'cart_product_quantity',
	] );

function cart_product_quantity() {
	foreach ( WC()->cart->get_cart() as $cart_item ) {
		if ( '772' === $cart_item['product_id'] && 3 > $cart_item['quantity'] ) {
			return true;
	return false;

In WooCommerce update the customer while purchase temporary out of stock product (for simple products):

  • Enable the “Add To Cart button classes” and “Shortcodes” options in the plugin
  • Create popup with the name simple_is_on_backorder1, targeting All Products
  • In the content insert the [current_add_to_cart] shortcode and notification about that he gonna add product which is temporary out of stock
  • If AJAX archive page option is enabled create another popup with trigger Click Open on .archive_is_on_backorder1 and the option “do not prevent…” and notification about that he just added product which is temporary out of stock, if not use the code:
add_filter( 'woocommerce_loop_add_to_cart_args', 'condless_add_class', 10, 2 );
function condless_add_class( $args, $product ) {
	if ( $product->is_type( 'simple' ) && $product->is_on_backorder() && ! is_product() && 'no' === get_option( 'woocommerce_enable_ajax_add_to_cart' ) ) {
		$product_id = $product->get_id();
		$args['class'] .= ' popmake-archive_backorder-' . $product_id;
		$out = isset( $product->get_availability()['availability'] ) ? '<div>' . $product->get_availability()['availability'] . '</div>' . '<a href=' . $product->add_to_cart_url() . '>' . $product->add_to_cart_text() . '</a>' : '';
		echo do_shortcode( "[popup id='archive_backorder-" . $product_id . "']" . $out . "[/popup]" );
	return $args;

As you probably have noticed- Pastorius, Carter, Valdés, and all other WordPress Version names, are names of popular jazz artists, inspired by WordPress core developers, who share a love of jazz music.


WooCommerce Auto Generate Post

And Back to the Future.

Create post for a user when purchase some product (update the product ID):

add_action( 'woocommerce_order_status_completed', 'condless_create_page' );
function condless_create_page( $order_id ) {
	foreach ( wc_get_order( $order_id )->get_items() as $item ) {
		if ( '9' === $item->get_product_id() ) {
			$user_id = wc_get_order( $order_id )->get_user_id();
			$user = new WP_User( $user_id );
			$user->remove_role( 'customer' );
			$user->add_role( 'author' );
			wp_insert_post( [
				'post_title' => 'My New Page',
				'post_status' => 'publish',
				'post_author' => $user_id,
				'post_type' => 'post'
			] );

As you probably have noticed- Jigowatt ltd, the developers of Jigoshop on which WooCommerce code is based, was named after the pronunciation mistake of the word Gigawatt in the movie Back to the Future.

WordPress Infrastructure

WooCommerce Server Security

And Toy Story.

  • Update frequently
  • Replace passwords frequently while verifying at least 8 characters long (lower and upper case alphabets, numbers and symbols) and set up Two-Factor Authentication
  • Verify that there is a firewall and DDOS protection
  • Config the Intrusion Prevention System (enable mod_remoteip if used with reverse proxy)
  • Set up hiding of the web server details
  • Scan the server files and pass on the logs frequently
  • Use the user root only if required
  • Disallow SSH root connection, in /etc/ssh/sshd_config use the directive:
PermitRootLogin no
  • Define which logs will be saved and where in the file /etc/rsyslog.conf.
  • Config the intrusion prevention system Fail2ban:

Activate mod_remoteip (in case of reverse proxy)

Create the /etc/fail2ban/jail.local file and use the commands, for example to enable the recidive SSH protection:

enabled = true

enabled = true

Config multiple log files:

logpath = /var/www/clients/client12/web*/log/access.log

Unban IP with the command:

fail2ban-client set sshd unbanip $IP
  • Hide the Apache web server details- add the directives into /etc/apache2/apache2.conf:
ServerTokens Prod
ServerSignature Off
  • Hide the PHP details- add the directives into php.ini:
expose_php = off

As you probably have noticed- Buster, Strech, Jessie, and all other Debian distribution code names, are names of characters from the Toy Story movie, inspired by Bruce Ferns who worked at Pixar besides his tenure as the Debian project leader.

WooCommerce Extensions

Default Attributes for WooCommerce

How to exclude some attribute from the stock-based default attributes calculation?
Update the attribute id:

add_filter( 'daw_max_variations', 'exclude_attribute', 10, 2 );
function exclude_attribute( $max_variations, $attribute ) {
	$excluded_attribute = 25;
	return $excluded_attribute === $attribute['id'] ? 0 : $max_variations;

How to apply the first attribute option only on products with less than certain amount of attributes?
Update the amount of attributes:

add_filter( 'first_attribute_checkbox', 'daw_first_attribute_restrict_products', 10, 2 );
function daw_first_attribute_restrict_products( $first_attribute_checkbox, $product ) {
	$max_attributes = 3;
	return $max_attributes < count( $product->get_attributes() ) ? 'no' : $first_attribute_checkbox;

How to exclude product from all the default attributes calculations?
Update the product id:

add_filter( 'daw_include_product', 'exclude_product', 10, 2 );
function exclude_product( $included, $product ) {
	$excluded_product = 71;
	return $excluded_product === $product->get_id() ? false : $included;
WooCommerce Extensions

Hide Address Fields for WooCommerce

How to never hide the address fields for purchase above 100?

add_filter( 'haf_hide_address', 'haf_dont_hide_address' );
function haf_dont_hide_address( $hide_enabled ) {
	return 100 <= WC()->cart->get_cart_contents_total() ? false : $hide_enabled;

How to make the postcode field optional for some country?
You may use the haf_optional_postcode_countries filter. Keep in mind that the built-in WooCommerce postcode validation will not be applied when using the plugin.

WooCommerce Extensions

Advanced Options for WooCommerce

How to display the amount of products items in on-hold orders instead of in proccessing orders?

add_filter( 'aow_orders', 'aow_order_status' );
function aow_order_status( $args ) {
	$args['status'] = 'on-hold';
	return $args;
WordPress Infrastructure

WooCommerce Mail Server

And Pharaoh.

Improve the successfull mail delivery rate from the server:

  • set up for the domain names: SPF, DKIM, DMARC
  • Make sure the server hostname appear at the A record, rDNS, server control panel, MTA (includes mailname), and content filter configuration values

As you probably have noticed- the first documented use of an organized courier service for the dissemination of written documents is in Egypt, where Pharaohs used couriers for the dissemination of their decrees in the territory of the State.

WordPress Infrastructure

Two-Factor Authentication

And Kim Dotcom.

TOTP-based Two-Factor Authentication makes it difficult for unauthorized access to your account, becuase that besides your password, it will required to obtain the code generated in your app in real time and log in immediately (the code changes every short time) or to locate your secret.

In this verification process, a one-time code is created using an algorithm that uses your secret code and the current time, so that each code is set to change over time.

Two-Factor Authentication is part of the information security system required in every business. To use this authentication method it is required to download an OTP app.

To config TOTP as a second factor to WordPress / WooCommerce:

  • Install and activate the plugin
  • Scan the QR code through the app
  • Click update profile

To config TOTP as a second factor to the Roundcube webmail:

  • Install and activate the plugin
  • Enable the option via the setting tab

To config TOTP as a second factor to the phpMyAdmin:

  • Install and activate the feature
  • Enable the option via the setting tab

To config TOTP as a second factor to the VPS SSH:

  • Install libpam-google-authenticator
  • Config google-authenticator
  • In /etc/pam.d/sshd file comment @include common-auth and add auth required
  • In /etc/ssh/sshd_config file change ChallengeResponseAuthentication value to yes, PasswordAuthentication value to no, and add AuthenticationMethods publickey,keyboard-interactive
  • Restart the SSH service

To config TOTP as a second factor to the VPS Control Panel:

  • Press the TFA button in the user list
  • Randomize the secret key (optional)
  • Set the Issuer Name (optional)
  • Scan the QR code through the app
  • Enter your password
  • Enter the TOTP Value the app generated
  • Press Apply

As you probably have noticed- Kim Dotcom threatened to sue all the major web services offering this kind of authentication, bases on its patent from 2000. Currently the European Patent Office revoked his patent in light of an earlier 1998 US patent held by AT&T.

WordPress Infrastructure


And The Pied Piper.

ISPConfig is an open source hosting control panel for Linux, it allows multiple server management from one control panel includes web server management, mail server management, and DNS server management.

Comply with strict privacy policy websites- disable the web statistics program.

Create users- it is required to set permanent customer no., create resources for him with the feature “login as client”.

Change the server configuration use the path /usr/local/ispconfig/server/conf-custom/ and for the inteface configuration /usr/local/ispconfig/interface/lib/

Activate SSL for a website- first enable the SSL and then the Let’s Encrypt SSL, you may use the Rewrite HTTP to HTTPS and SEO Redirect (domain.tld => www.domain.tld, after creating automatic www subdomain) options. Clean old SSL certificates- use the command (newer certificates will have higher suffix number):

certbot delete

Run WordPress / WooCommerce website with SSL in reverse proxy- add the directive to wp-config.php:

$_SERVER['HTTPS'] = 'on';

Use ISPConfig behind NAT– enable the Skip Lets Encrypt Check option (System => Server Config => Web => SSL Settings), use the WAN IP in DNS Settings and Website Settings, and the LAN IP in Server Config and Server IP Addresses.

Config a reverse proxy in Apache web server, which keeps the original reciever address and don’t pass the SSL certificates requests use those directives:

ProxyPreserveHost On
ProxyPass /.well-known/acme-challenge !
ProxyPass /$PATH http://$LAN-IP:$PORT/$PATH
ProxyPassReverse /$PATH http://$LAN-IP:$PORT/$PATH
ProxyPass / http://$LAN-IP:$PORT/
ProxyPassReverse / http://$LAN-IP:$PORT/ 

Recover better- enable rescue option (Server Config tab).

Restore a website from a server backup- it is possible to export and import the website files & database backup and the relevant backup record from the ISPConfig database.

Enhance the email policy- edit the directives in /etc/postfix/

smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_helo_hostname, reject_invalid_helo_hostname
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_hostname, reject_non_fqdn_hostname, reject_unknown_recipient_domain, reject_non_fqdn_recipient, reject_unauth_destination, reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_rbl_client,reject_rbl_client,reject_rbl_client, check_recipient_access mysql:/etc/postfix/, reject_unauth_destination
smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unknown_client_hostname, check_client_access mysql:/etc/postfix/

Use PureFTP in passive mode (allows using behind firewall)- use the commands (and open the same ports at the firewall):

echo "30510 30610" > /etc/pure-ftpd/conf/PassivePortRange
service pure-ftpd-mysql restart

As you probably have noticed- the oldest written accounts of the Pied Piper of Hamelin was created in Lüneburg, the same town the ISPConfig software is developed.