By woocommerce-sl, posted on July 8, 2024

Selling licensed products online has never been easier or more integrated. Whether you’re offering software licenses, digital content, or other licensed goods, the process is designed to be as seamless as selling any regular product. This approach not only simplifies the setup for store owners but also ensures a smooth shopping experience for customers.

Seamless Integration with all existing Products

One of the standout features of this system is its ability to seamlessly integrate licensed products with regular products in the same store. This means that a customer can add both types of products—licensed and non-licensed—to their cart in a single transaction without any disruptions or complications. For example, a customer might purchase a piece of physical hardware (a non-licensed product) alongside a software license or a digital download (licensed products) in the same order.

This seamless integration eliminates the need for multiple transactions and makes the shopping process more efficient. Customers appreciate the convenience of being able to purchase everything they need in one go, whether they’re buying a combination of licensed and non-licensed products or just one type. This also opens up the possibility for store owners to create bundles or special offers that mix and match these types of products, enhancing sales potential.

Compatibility with Various Product Types

The system is highly versatile, supporting a wide range of product types beyond just simple products. It’s designed to work flawlessly with:

  • Simple Products: Basic products with no variations or options.
  • Variable Products: Products that come in different variations, such as size, color, or configuration, each potentially requiring a unique license.
  • Grouped Products: Collections of related products that are sold together as a group. For example, a software suite could be offered as a grouped product, with each application requiring its own license.
  • Subscription Products: Products that are sold on a recurring basis, such as monthly or annual software licenses. These can be combined with licensed products to offer ongoing access to updates and support.

This flexibility allows you to sell a wide variety of products in the same store, all while maintaining the integrity of the licensing process. For instance, you could sell a subscription to a service that includes access to licensed software, or you could offer a physical product with a digital license included as a bonus. The possibilities are virtually endless, and this versatility is a key strength of the system.

Consistent Cart and Checkout Layout

Despite the added complexity of dealing with licensed products, the customer experience remains straightforward and consistent. The cart layout and the checkout process remain the same regardless of whether the products in the cart are licensed or not. This consistency is crucial for maintaining a user-friendly shopping experience, as customers don’t have to navigate different processes or layouts depending on the type of product they’re purchasing.

Here’s an example of how this works in practice:

  1. Cart Page: When a customer adds products to their cart—whether they’re regular or licensed—the cart page displays all items in a unified layout. The customer can review their selections, adjust quantities, and proceed to checkout without encountering any unexpected steps or screens. The example below shows a cart page that includes both regular and licensed products:Example of a default cart page for licensed products
  2. Checkout Page: The checkout process is similarly streamlined. Customers provide their payment and shipping details as usual, and the system automatically handles the generation of license keys for any licensed products. The checkout page does not change in appearance or functionality when licensed products are included, ensuring a smooth and predictable experience for all customers.After the purchase is complete, license keys are automatically generated for each licensed product in the order. These keys are then displayed on the Order Details page and are also sent to the customer via email along with the standard purchase confirmation. This ensures that customers receive everything they need immediately, without any additional steps required on their part.
    Example of an Order Details page displaying generated license keys

 

Extending Functionality with Additional Features

One of the greatest strengths of this system is its flexibility and extensibility. While the out-of-the-box features are robust, there’s always the option to extend functionality to meet your specific needs. Whether you need to add custom licensing rules, integrate with third-party services, or enhance the customer experience, the system is designed to accommodate these modifications.

For developers and store owners looking to expand their store’s capabilities, the Documentation area offers a wealth of resources. These include:

  • Code Examples: Practical examples that show how to implement common customizations or extend functionality. This could include adding new types of license keys, integrating with external APIs, or customizing the way license keys are generated and delivered.
  • API Documentation: Detailed information on the system’s API, allowing for deeper integrations with other systems or services. For example, you might want to link your licensing system with a CRM or marketing automation platform to enhance your post-purchase engagement with customers.
  • Hooks and Filters: A comprehensive guide to the hooks and filters available in the system, enabling developers to modify behavior without altering the core code. This is particularly useful for creating custom workflows or automating certain tasks.

These resources make it easier to tailor the system to your unique requirements, ensuring that your store remains flexible and future-proof. Whether you’re a developer looking to build something truly custom or a store owner wanting to make small tweaks, the documentation provides the guidance needed to make these changes confidently.

 

Selling licensed products in your eCommerce store doesn’t have to be a complex process. With seamless integration, support for a wide range of product types, and a consistent user experience, this system makes it easy to manage both licensed and regular products side by side. The ability to extend functionality further enhances its value, ensuring that your store can adapt to your needs as they evolve.

Whether you’re just starting with licensed products or looking to expand your offerings, this system provides the tools and flexibility you need to succeed. And with comprehensive documentation to guide you, implementing and customizing the system to fit your specific requirements is both straightforward and accessible.

 

 

Read more

By woocommerce-sl, posted on August 2, 2017

Starting version 1.2 the WooCommerce Software License plugin got a new enhancement, the ability to use existing keys (own admin keys) along the plugin code. If you are a re-seller this become the great tool for selling keys and software. All existing functionality like allowed client keys, instances per key etc, can still apply. Also multiple Licensing groups can be created allowing mix of pre-generated with automated keys to be bundled toughener.

Read more

By woocommerce-sl, posted on August 1, 2017

Any customer can manage the license keys through default WooCommerce MyAccount Page. Once a purchase is completed a new button Licence Manage appear within the Recent Orders table.

(more…)

Read more

By woocommerce-sl, posted on August 1, 2017

The shop administrator can manage any licence aspects of a product purchase through the WooCommerce Orders interface. Administrators can delete keys, generate new ones, un-assign etc.

Main Licence Keys interface consist of a list of all keys from all orders. This facilitate an easy management through the interface functions which include filters and search.

Full control of each license is available through an additional metabox interface at the admin order page.

Admin can modify order license details individually from original data.

Read more

By woocommerce-sl, posted on August 1, 2017

The built-in API interface is a convenient way to allow your software to communication with the WooCommerce Software License API. Calls are initiated through GET/POST method. Additional code examples are included within the plugin download, also in our documentation area Software API Integration code example.
The following methods are available:

  • activate
  • deactivate
  • status-check
  • plugin_update
  • plugin_information
  • theme_update
  • code_version
  • key_delete

Each function generally requires some combination of the following input values:

  • woo_sl_action: plugin function requested
  • licence_key: the license key that was sent to the user
  • product_unique_id: the Software Unique ID as defined in the WooCommerce product License tab
  • domain: the URL to a WordPress site using a plugin or a unique hash for standalone software
  • api_version: an API version to use, if not specified 1.0 will be used. Latest available is 1.1

For each function, the returned values are:

  • status => error or success message (string)
  • status_code => result code (integer)
  • message => explanation of result (string)

 

The domain input ( unique hash ) is processed on API calls using regex, so it should be also validated on the client, before sending the request, to include the following allowed chars:

  • alphanumeric characters ( lowercase and uppercases)
  • dots
  • minus
  • underlines
  • forward slashes
  • spaces

 

activate

This method allows a license key to be synchronized with your software for activation. The following arguments are required for a typical software-license call:

  • woo_sl_action = ‘activate’
  • product_unique_id
  • licence_key
  • domain

deactivate

This method facilitate a licence key de-activation. Once de-activated a key is released from being set as used status, and it can be integrated with another domain / hash. The following arguments are required for a call:

  • woo_sl_action = ‘deactivate’
  • product_unique_id
  • licence_key
  • domain

status-check

The status-check API method allow a certain software key to be verified for being still active, valid, assigned to a certain domain. The following arguments are required for a call:

  • woo_sl_action = ‘status-check’
  • product_unique_id
  • licence_key
  • domain

plugin_update

The plugin_update API method return basic details regarding software update. The following arguments are required for a call:

  • woo_sl_action = ‘plugin_update’
  • product_unique_id
  • licence_key
  • version
  • domain

theme_update

The theme_update API method return basic details regarding theme software update. The following arguments are required for a call:

  • woo_sl_action = ‘theme_update’
  • product_unique_id
  • licence_key
  • version
  • domain

plugin_information

The plugin_information API method return detailed information’s regarding software as download link, latest software, upgrade notice, requires, description details, installation, faq, screenshot, changelog etc. The following arguments are required for a call:

  • woo_sl_action = ‘plugin_information’
  • product_unique_id
  • licence_key
  • version
  • domain

code_version

The method return detailed information’s regarding a licenced product, latest version, upgrade notice, requires, description details, installation, faq, screenshot, changelog etc. The difference from other API methods,this does not require a key, but there’s no download / update link provided.
The following arguments are required for a call:

  • woo_sl_action = ‘code_version’
  • product_unique_id

key_delete

Through this API method a key can be removed from the customer dashboard. By deleting a key, a new slot will be open so another licence key can be generated. The following arguments are required for a call:

  • woo_sl_action = ‘key_delete’
  • product_unique_id
  • licence_key

Read more

By woocommerce-sl, on , posted on March 5, 2018

On site interaction using any API methods, the system reply through an JSON encoded message including a status code to makes interpretation easier.

Success

  • s100
    Licence Key Successfully activated for ‘domain’
  • s101
    Licence Key Successfully activated for ‘domain’ – *first pass
  • s201
    Licence Key Successfully Unassigned
  • s203
    Licence Key Is Unassigned
  • s205
    Licence key Is Active and Valid for Domain ( when assign_domain_to_key_on_status_check option active )
  • s215
    Licence key Is Active and Valid for Domain
  • s401
    *a full response with code metadata on calling plugin_update or theme_update methods
  • s402
    *a full response with code metadata on calling plugin_information method
  • s403
    *a full response with code metadata on calling code_information method
  • s610
    *Licence Key Successfully Deleted

Error

  • e001
    Invalid provided data
  • e002
    Invalid licence key
  • e003
    Order does not exist anymore
  • e004
    Order status not allowed
  • e110
    Invalid licence key or licence not active for domain
  • e111
    Invalid Data
  • e112
    You had reached the maximum number of domains for this key
  • e204
    Licence key not active for current domain
  • e301
    Licence Key does not match this product
  • e312
    Licence is not Active, current status is ‘STATUS’
  • e419
    Invalid Product Unique ID

Read more

By woocommerce-sl, posted on August 1, 2017

Any software can use API functionality. We can provide full code in a form of WordPress plugin which can be used as staring base for further implementation.

This is a sample usage on a licence key activation call:

The first part of the code consist of few constants definition which are being used later within the code.


//the url where the WooCommerce Software License plugin is being installed
define('SL_APP_API_URL',      'http://YourDomainWhereSoftwareManagement.com/index.php');

//the Software Unique ID as defined within product admin page
define('SL_PRODUCT_ID',           'APTO');


$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
define('SL_INSTANCE',             str_replace($protocol, "", get_bloginfo('wpurl')));

A simple activation calls will looks like this:

$args = array(
                    'woo_sl_action'         => 'activate',
                    'licence_key'       => $license_key,
                    'product_unique_id'        => SL_PRODUCT_ID,
                    'domain'          => SL_INSTANCE
                );
$request_uri    = SL_APP_API_URL . '?' . http_build_query( $args );
$data           = wp_remote_get( $request_uri );

if(is_wp_error( $data ) || $data['response']['code'] != 200)
    {
        //there was a problem establishing a connection to the API server
    }

$data_body = json_decode($data['body']);
if(isset($data_body->status))
    {
        if( $response_block->status == 'success' && ( $response_block->status_code == 's100' || $response_block->status_code == 's101' ) )
            {
                //the license is active and the software is active
                //doing further actions like saving the license and allow the plugin to run

            }
            else
            {
                //there was a problem activating the license
            }
    }
    else
    {
        //there was a problem establishing a connection to the API server
    }

The API $data_body response include also a ‘message’ argument with detailed text information of the response. This is always an English text, which can be translated to the local site language using _e, __ and other WordPress translation functions.

Read more

By woocommerce-sl, posted on August 1, 2017

The first part of the code consist of few constants definition which are being used later within the code.


//the url where the WooCommerce Software License plugin is being installed
define('SL_APP_API_URL',      'http://YourDomainWhereSoftwareManagement.com/index.php');

//the Software Unique ID as defined within product admin page
define('SL_PRODUCT_ID',           'APTO');

//A code variable constant is required, which is the user application code version. This will be used by API to compare against the new version on shop server.
define('SL_VERSION', '1.4.2');

$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
define('SL_INSTANCE',             str_replace($protocol, "", get_bloginfo('wpurl')));

A plugin auto-update code can be inserted within the plugin, here is an example:


    class WOOSL_CodeAutoUpdate
        {

            // URL to check for updates, this is where the index.php script goes

            public $api_url;

            private $slug;
            public $plugin;
            
            private $API_VERSION;


            function __construct($api_url, $slug, $plugin)
                {
                    $this->api_url  =   $api_url;
                    $this->slug     =   $slug;
                    $this->plugin   =   $plugin;
                    
                    //use laets available API 
                    $this->API_VERSION =   1.1;
                    
                }

            public function check_for_plugin_update($checked_data)
                {
                     if ( !is_object( $checked_data ) ||  ! isset ( $checked_data->response ) )
                        return $checked_data;
                     
                     $request_string = $this->prepare_request('plugin_update');
                     if($request_string === FALSE)
                        return $checked_data;
                     
                     global $wp_version;
                     
                     // Start checking for an update
                     $request_uri = $this->api_url . '?' . http_build_query( $request_string , '', '&');
                     
                     //check if cached
                     $data  =   get_site_transient( 'my-custom-plugin-check_for_plugin_update_' . md5( $request_uri ) );
                     if  ( $data    === FALSE )
                         {
                             $data = wp_remote_get( $request_uri, array(
                                                                                'timeout'     => 20,
                                                                                'user-agent'  => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ),
                                                                                ) );
                             
                             if(is_wp_error( $data ) || $data['response']['code'] != 200)
                                return $checked_data;
                                
                             set_site_transient( 'my-custom-plugin-check_for_plugin_update_' . md5( $request_uri ), $data, 60 * 60 * 4 );
                             
                         }
                                                  
                     $response_block = json_decode($data['body']);
                      
                     if(!is_array($response_block) || count($response_block) < 1)
                        return $checked_data;
                     
                     //retrieve the last message within the $response_block
                     $response_block = $response_block[count($response_block) - 1];
                     $response = isset($response_block->message) ? $response_block->message : '';
                     
                     if (is_object($response) && !empty($response)) // Feed the update data into WP updater
                         {
                             $response  =   $this->postprocess_response( $response );
                             
                             $checked_data->response[$this->plugin] = $response;
                         }
                     
                     return $checked_data;
                }

            public function plugins_api_call($def, $action, $args)
                {
                     if (!is_object($args) || !isset($args->slug) || $args->slug != $this->slug)
                        return $def;
    
                     $request_string = $this->prepare_request($action, $args);
                     if($request_string === FALSE)
                        return new WP_Error('plugins_api_failed', __('An error occour when try to identify the pluguin.' , 'woo-global-cart') . '&lt;/p> &lt;p>&lt;a href=&quot;?&quot; onclick=&quot;document.location.reload(); return false;&quot;>'. __( 'Try again', 'woo-global-cart' ) .'&lt;/a>');;
                     
                     global $wp_version;
                     
                     $request_uri = $this->api_url . '?' . http_build_query( $request_string , '', '&');
                     $data = wp_remote_get( $request_uri, array(
                                                                        'timeout'     => 20,
                                                                        'user-agent'  => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ),
                                                                        ) );
                     
                     if(is_wp_error( $data ) || $data['response']['code'] != 200)
                        return new WP_Error('plugins_api_failed', __('An Unexpected HTTP Error occurred during the API request.' , 'woo-global-cart') . '&lt;/p> &lt;p>&lt;a href=&quot;?&quot; onclick=&quot;document.location.reload(); return false;&quot;>'. __( 'Try again', 'woo-global-cart' ) .'&lt;/a>', $data->get_error_message());
                     
                     $response_block = json_decode($data['body']);
                     //retrieve the last message within the $response_block
                     $response_block = $response_block[count($response_block) - 1];
                     $response = $response_block->message;
                     
                     if (is_object($response) && !empty($response))
                         {
                             $response  =   $this->postprocess_response( $response );
                             
                             return $response;
                         }
                }

            public function prepare_request($action, $args = array())
                {
                    global $wp_version;
                    
                    return array(
                        'woo_sl_action'         => $action,
                        'version'               => SL_VERSION,
                        'product_unique_id'     => SL_PRODUCT_ID,
                        'licence_key'           => LICENSE_KEY,
                        'domain'                => SL_INSTANCE,
                        'wp-version'            => $wp_version,
                        
                        'api_version'           => $this->API_VERSION
                    );
                }
            
            private function postprocess_response( $response )
                 {
                     //include slug and plugin data
                     $response->slug    =   $this->slug;
                     $response->plugin  =   $this->plugin;
                     
                     //if sections are being set
                     if ( isset ( $response->sections ) )
                        $response->sections = (array)$response->sections;
                     
                     //if banners are being set
                     if ( isset ( $response->banners ) )
                        $response->banners = (array)$response->banners;
                       
                     //if icons being set, convert to array
                     if ( isset ( $response->icons ) )
                        $response->icons    =   (array)$response->icons;
                     
                     return $response;
                     
                 }
        }

        function WOOSL_run_updater()
            {
                $wp_plugin_auto_update = new WOOSL_CodeAutoUpdate(SL_APP_API_URL, 'plugin-slug', 'plugin-folder/plugin-filename.php');

                // Take over the update check

                add_filter('pre_set_site_transient_update_plugins', array(
                    $wp_plugin_auto_update,
                    'check_for_plugin_update'
                ));

                // Take over the Plugin info screen

                add_filter('plugins_api', array(
                    $wp_plugin_auto_update,
                    'plugins_api_call'
                ) , 10, 3);
            }

        add_action('after_setup_theme', 'WOOSL_run_updater');

Read more

By woocommerce-sl, posted on August 1, 2017

This is an API example on how to use the Theme AutoUpdate functionality.


    define('WOO_SLT_APP_API_URL',      'http://YourDomainWhereSoftwareManagement.com/index.php');
    define('WOO_SLT_PRODUCT_ID',       'Unitque Software ID #@3');
    define('WOO_SLT_VERSION',          '1.0');
    
    define('WOO_SLT_INSTANCE',         str_replace(array ("https://" , "http://"), "", network_site_url()));;
    define('WOO_SLT_THEME_SLUG',        'my-theme-slug' );
    define('WOO_SLT_CHANGELOG_URL',     'http://YourDomainWhereSoftwareManagement.com/changelog/');

        class WOO_SLT_CodeAutoUpdate
         {
             # URL to check for updates, this is where the index.php script goes
             public $api_url;
             
             private $slug;
             
             public function __construct( $api_url, $slug )
                 {
                     $this->api_url = $api_url;
                     
                     $this->slug    = $slug;                 
                 }
             
             
             public function check_for_theme_update($checked_data)
                 {
                     if ( !is_object( $checked_data ) ||  ! isset ( $checked_data->response ) )
                        return $checked_data;
                     
                     $request_string = $this->prepare_request('theme_update');
                     if($request_string === FALSE)
                        return $checked_data;
                     
                     // Start checking for an update
                     $request_uri = $this->api_url . '?' . http_build_query( $request_string , '', '&');
                     $data = wp_remote_get( $request_uri );
                     
                     if(is_wp_error( $data ) || $data['response']['code'] != 200)
                        return $checked_data;
                     
                     $response_block = json_decode($data['body']);
                      
                     if(!is_array($response_block) || count($response_block) < 1)
                        return $checked_data;
                     
                     //retrieve the last message within the $response_block
                     $response_block = $response_block[count($response_block) - 1];
                     $response = isset($response_block->message) ? $response_block->message : '';
                     
                     if (is_object($response) && !empty($response)) // Feed the update data into WP updater
                         {
                             $response  =   $this->postprocess_response( $response );
                             
                             $checked_data->response[$this->slug] = (array)$response;
                         }
                     
                     return $checked_data;
                 }
             
             
             public function theme_api_call($def, $action, $args)
                 {
                     if (!is_object($args) || !isset($args->slug) || $args->slug != $this->slug)
                        return $def;
                         
                     $request_string = $this->prepare_request($action, $args);
                     if($request_string === FALSE)
                        return new WP_Error('theme_api_failed', __('An error occour when try to identify the pluguin.' , 'wooslt') . '&lt;/p> &lt;p>&lt;a href=&quot;?&quot; onclick=&quot;document.location.reload(); return false;&quot;>'. __( 'Try again', 'wooslt' ) .'&lt;/a>');;
                     
                     $request_uri = $this->api_url . '?' . http_build_query( $request_string , '', '&');
                     $data = wp_remote_get( $request_uri );
                     
                     if(is_wp_error( $data ) || $data['response']['code'] != 200)
                        return new WP_Error('theme_api_failed', __('An Unexpected HTTP Error occurred during the API request.' , 'wooslt') . '&lt;/p> &lt;p>&lt;a href=&quot;?&quot; onclick=&quot;document.location.reload(); return false;&quot;>'. __( 'Try again', 'wooslt' ) .'&lt;/a>', $data->get_error_message());
                     
                     $response_block = json_decode($data['body']);
                     //retrieve the last message within the $response_block
                     $response_block = $response_block[count($response_block) - 1];
                     $response = $response_block->message;
                     
                     if (is_object($response) && !empty($response)) // Feed the update data into WP updater
                         {
                             //include slug and plugin data
                             $response  =   $this->postprocess_response( $response );
                             
                             return $response;
                         }
                 }
             
             public function prepare_request($action, $args = array())
                 {
                     global $wp_version;
                     
                     $license_data = get_site_option('slt_license'); 
                     
                     return array(
                                     'woo_sl_action'        => $action,
                                     'version'              => WOO_SLT_VERSION,
                                     'product_unique_id'    => WOO_SLT_PRODUCT_ID,
                                     'licence_key'          => $license_data['key'],
                                     'domain'               => WOO_SLT_INSTANCE,
                                     
                                     'wp-version'           => $wp_version,
                                     'api_version'          => '1.1'
                                     
                     );
                 }
                 
             
             private function postprocess_response( $response )
                 {
                     //include slug and theme data
                     $response->theme       =   $this->slug;
                     
                     $response->url         =   WOO_SLT_CHANGELOG_URL;
                     
                     //if sections are being set
                     if ( isset ( $response->sections ) )
                        $response->sections = (array)$response->sections;
                     
                     //if banners are being set
                     if ( isset ( $response->banners ) )
                        $response->banners = (array)$response->banners;
                       
                     //if icons being set, convert to array
                     if ( isset ( $response->icons ) )
                        $response->icons    =   (array)$response->icons;
                     
                     return $response;
                     
                 }

         }
         
         
    function WOO_SLT_run_updater()
         {
         
             $wp_theme_auto_update = new WOO_SLT_CodeAutoUpdate( WOO_SLT_APP_API_URL, WOO_SLT_THEME_SLUG );
             
             // Take over the update check
             add_filter('site_transient_update_themes',                                        array($wp_theme_auto_update, 'check_for_theme_update'));
             
             // Take over the Plugin info screen
             add_filter('theme_api',                                                          array($wp_theme_auto_update, 'theme_api_call'), 10, 3);
         
         }
    add_action( 'after_setup_theme', 'WOO_SLT_run_updater' );

Read more

By woocommerce-sl, on , posted on May 28, 2024

The WooCommerce Software License plugin is an essential tool for licensing downloadable software and applications. It offers a comprehensive solution for integrating a licensing system with your code, ensuring secure and efficient management of software licenses.

This plugin package comes with a sample integration code that demonstrates all the main features, including license activation, deactivation, and status verification on the server side. These capabilities make it easy to implement and manage licensing for your products, providing a seamless experience for both developers and end-users. (more…)

Read more