Customize Woocommerce with a plugin

E-commerce is a very popular type of website nowadays. With Woocommerce it is possible to create a virtual store in a simple and intuitive way. There are many plugins that increase the basic functionality offered by the platform. Sometimes, however, there is no perfect plugin for our needs. Let's find out how to add through the development of a plugin a custom page for customers and intercept the execution of orders.

Share

Share on facebook
Share on linkedin
Share on twitter
Share on email
Reading time: 7 minutes

Woocommerce represents the optimal solution to create an e-commerce in a few steps. Thanks to this WordPress plugin, you can manage the sale of your products in a simple and intuitive way. Unlike other solutions, such as Magento and Shopify, no initial cost is required. The only initial costs to be incurred are those related to the hosting service and domain registration.

There are several plugins that extend the basic functions. For example, you can integrate shipping tracking services, or create catering services. Unfortunately, there is not always a plugin that provides the functionality that our e-commerce needs. When this happens, it is necessary to develop an extension for Woocommerce.

In this article we will find out how to add a custom page within the customer profile by developing a plugin.

Prerequisites

Before we start developing the page we have to create our development environment. Thanks to it we will be able to do all necessary tests before installing the new plugin on the online site. In the article Docker compose – how to orchestrate different containers you can find an example of how to create on your machine a Docker project that will create a WordPress site.

Once the project is created, connect to your machine in the browser (http://locahost) to start configuring WordPress. At the end of the configuration, you’ll just have to add Woocommerce from the Plugins menu.

Woocommerce will also ask you for some information to properly configure your online store. Follow the instructions that appear on the screen. In this example we’ll use a basic configuration that creates a store for selling products. In fact, if you sell services that require memberships or appointments, you’ll need paid extensions.

To complete our development environment, we need to create the plugin structure. In articles Develop a WordPress plugin – create the initial structure and Manage Advanced Custom Fields and integrate them in a WordPress plugin we saw how to generate the starting structure of a plugin and how to integrate custom field management. We’ll leverage some of that knowledge to create our own Woocommerce plugin.

Checking dependencies

The development of some plugins requires the inclusion of functionality from other extensions. In our example we need Woocommerce to be installed and active. Otherwise our plugin would cause errors and malfunction of the site. 

To verify that the conditions exist to activate our plugin we open the file flowygo.php and insert immediately after the definition of the version the following lines of code.

if (!function_exists('is_plugin_active')) {
    include_once(ABSPATH . '/wp-admin/includes/plugin.php');
}

/**
* Check for the existence of WooCommerce and any other requirements
*/
function flowygo_check_requirements() {
    if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
        return true;
    } else {
        add_action( 'admin_notices', 'flowygo_missing_wc_notice' );
        return false;
    }
}


/**
* Display a message advising WooCommerce is required
*/
function flowygo_missing_wc_notice() { 
    $class = 'notice notice-error';
    $message = __( 'Flowygo requires WooCommerce to be installed and active.', 'flowygo' );
 
    printf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), esc_html( $message ) ); 
} 

The first lines of code are used to include the is_plugin_active function if it is not already defined. If you forget to include it your plugin will be installed but it will cause a general system error. Your site will not work anymore and you will have to manually remove the plugin folder from your machine. I remind you that plugins are installed in the wp-content/plugins path.

The function flowygo_check_requirements checks if Woocommerce is installed. True is returned to the calling function if the check is successful. Otherwise, an action is added to display an error message and returns false. You can expand this function as you like to include checking for all dependencies your plugin has.

The customization of the error message is done in the function flowygo_missing_notice. In this function we define the message to be displayed. The $class variable is used to render the message appropriately.

We still need to insert the call to the flowygo_check_requirements function. To do this we modify the code of the run_flowygo function defined at the end of the file as follows.

/**
 * Begins execution of the plugin.
 *
 * Since everything within the plugin is registered via hooks,
 * then kicking off the plugin from this point in the file does
 * not affect the page life cycle.
 *
 * @since    1.0.0
 */
function run_flowygo() {
    if (floygo_check_requirements()) {
        $plugin = new Flowygo();
        $plugin->run();        
    }
} 

This change will allow the plugin to run only if the dependencies are met. If you try to install it, the plugin will appear to be active but will not actually run. In fact, if you have added a settings page as shown in article XXX, it will not appear. Only when you install all necessary extensions for your plugin, it will run. This approach is a WordPress best practice.

To fully adhere to the WordPress guidelines, it is also necessary to persistently display a banner in the dashboard. Therefore, it is necessary to add an action to admin_notices that displays a warning on all pages of the admin dashboard until WooCommerce is installed or the plugin is deactivated. Just register an action before register_activation_hook as follows.

add_action( 'plugins_loaded', 'flowygo_check_requirements' ); 

Custom customer page creation

The plugin is ready to be integrated with Woocommerce. The goal now is to add a new tab in each customer’s account page. Reasons for adding extra content can be various. For example, it might be useful to ask for the user’s interests to create targeted advertising campaigns. Otherwise, providing a dedicated service based on certain purchases could be displayed on this page. 

In our example we’ll create a page displaying the rewards the user will receive based on their purchases. 

The first step is to create an endpoint related to the new page. We open the file class-flowygo-public.php in the public folder and start inserting the following function.

/**
* @since 1.0.0
 * add endpoint of rewards page
*/
public function flowygo_add_rewards_endpoint() {
	add_rewrite_endpoint( 'rewards', EP_ROOT | EP_PAGES );
} 

Since WordPress urls are built according to the settings defined by the site administrator, it is also appropriate to include a function that updates the query variables associated with the pages. Let’s add another function for this purpose.

/**
* since 1.0.0
* update query vars for the new endpoint
*/
public function flowygo_query_vars( $query_vars ){
	$query_vars['rewards'] = 'rewards';
 	return $query_vars;
} 

To activate the endpoint we need to add an initialization action for the public part. Let’s open the class-flowygo.php file in the includes folder and add the following lines of code right after the definition of the $plugin_public variable.

$this->loader->add_action( 'init', $plugin_public, 'flowygo_add_rewards_endpoint' );
$this->loader->add_filter( 'woocommerce_get_query_vars', $plugin_public, 'flowygo_query_vars'); 

Although we have registered the new endpoint it is not yet complete. In fact we haven’t associated any page, but above all there is no way to reach it. Let’s start creating the relative tab in the account page of each user.

Always in the file class-flowygo.php we add another filter related to woocommerce to modify the accounts menu. The code to insert is the following.

$this->loader->add_filter( 'woocommerce_account_menu_items', $plugin_public, 'flowygo_menu_items' ); 

We need to define the callback function that was mentioned in the filter. Therefore we add the following lines of code in the class-flowygo-public.php file.

/**
 * Insert new endpoints into the My Account menu after an existing menu item
 *
 * @param array $items
 * @param array $new_items
 * @param string $after
 * @return array
 */
public function flowygo_menu_insert( $items, $new_items, $after ) {
	// Search for the item position and +1 since is after the selected item key.
	$position = array_search( $after, array_keys( $items ) ) ;

	// Insert the new item.
	$array = array_slice( $items, 0, $position, true );
	$array += $new_items;
	$array += array_slice( $items, $position, count( $items ) - $position, true );

	return $array;
}

/**
 * Insert the new endpoint into the My Account menu.
 *
 * @param array $items
 * @return array
 */

public function flowygo_menu_items( $items ) {

	$new_items = array();
	
	$new_items['rewards'] = __( 'Rewards', 'woocommerce' );
	// Add the new item after `orders`.
	return $this->flowygo_menu_insert( $items, $new_items, 'orders' );
}
 

The flowygo_menu_items function receives an array containing the list of currently available menu items. Therefore, a new associative array containing the new menu items is created. The function flowygo_menu_insert is used to insert them in the appropriate position. This function receives the original menu list and inserts the new items in the correct position. The position is given by the name of the menu item. Possible values are:

  • edit-address
  • dashboard
  • payment-methods
  • orders
  • downloads
  • edit-account
  • customer-logout

All that’s left is to add the page that will display our rewards!

So we create two functions in the file class-floygo-public.php: one for the page content and the other for the title.

/**
 * Render the content of the rewards page
 */
	public function rewards_page() {
		echo __('The list of your rewards', 'flowygo');
		
	}

/**
 * Define the title of the endpoint
 */
public function rewards_title($title, $endpoint ){
	$title = __( "Rewards", "woocommerce" );
    return $title;
} 

Let’s go back into the public hooks definition function and add the following instructions.

$this->loader->add_action( 'woocommerce_account_rewards_endpoint', $plugin_public, 'rewards_page' ); 
$this->loader->add_filter('woocommerce_endpoint_rewards_title', $plugin_public, 'add_title',10, 2); 

If you find errors in reaching the endpoint you should rewrite the permalinks rules. To insert it inside the plugin the advice is to add the function flush_rewrite_rules() inside the run_floywgo function after the plugin has been run.

The page we created will look like this.

Rewards management

The plugin now integrates a new page into the account of each user. However, its content is empty. Let’s find out how to assign scores based on the purchases each user will make.

Suppose we want to award one point for each purchase made. Depending on the number of purchases we will award a prize to that user. The prizes will be as follows:

  • Bronze: at least 10 purchases
  • Silver: at least 20 purchases
  • Gold: at least 50 purchases

We then need to intercept when an order is completed to update the customer’s score.

Let’s add an action associated with changing the status of an order. We insert the following statement inside define_admin_hooks in the class-flowygo.php file.

$this->loader->add_action( 'woocommerce_order_status_changed', $plugin_admin, 'flowygo_woocommerce_payment_complete', 10, 3 ); 

In this way, every time the status of an order is changed, the flowygo_woocomerce_payment_complete function will be called. We insert this function and its logic in the class-flowygo-admin.php file.

/**
 * Insert the new endpoint into the My Account menu.
 *
 * @param int $order_id
 * @param string $old_status
 * @param string $new_status
 */
 public function flowygo_woocommerce_payment_complete( $order_id, $old_status, $new_status ) {
	if ( $new_status == "completed" ) {
		$reward = get_user_meta( get_current_user_id(), 'reward', true );	
		update_user_meta( get_current_user_id(), 'reward', $reward +1 );
	}
} 

The function will receive the order identifier, the previous status and the current status. We insert a very simple logic that checks if the new status is equal to completed. Only in this case it retrieves the value of the meta reward associated with the current user. The user ID is retrieved by the get_current_user_id function, while the meta is retrieved by the get_user_meta function. Its value is then incremented by 1 using the update_user_meta function.

We need to update the content of the previously created rewards page accordingly to display the rewards if the thresholds are exceeded. The code for the rendering function will be as follows.

public function rewards_page() {
		
	$reward = get_user_meta( get_current_user_id(), 'reward', true );
    if ($reward >= 50){
    	echo 'Gold';
    }
    if ($reward >= 20 && $reward < 50){
    	echo 'Silver';
    }
    if ($reward >= 10 && $reward < 20){
    	echo 'Bronze';
    }
    else{
    	echo __('No rewards', 'flowygo');
    }
		
} 

Obviously you can improve the graphics to your liking by inserting icons and images according to the various thresholds. 

Recommended Readings

More To Explore

Google Cloud platform

BigQuery: performance optimization

Although BigQuery is a very good tool for querying terabytes, best practices should be adopted to improve performance. Let’s discover tricks for writing queries that execute quickly and save on execution costs. We also look at how you can optimize table storage through partitioning and clustering.

Google Cloud platform

BigQuery: WINDOWS analytics

In many application scenarios, the statistics you need to extract refer to different groupings on the source data. By defining aggregation windows, you can calculate statistics within the same query. Moreover, if necessary, you can also provide different levels of data granularity through the ARRAY data type. Let’s discover these advanced features through two real-world examples.

Leave a Reply

Your email address will not be published. Required fields are marked *

Design with MongoDB

Design with MongoDB!!!

Buy the new book that will help you to use MongoDB correctly for your applications. Available now on Amazon!