- Plan vs. Code Type
- License-Related Methods
- Recommended Methods
- Examples
- How Trials Are Handled
- Common Misconceptions
- Excluding Files and Folders from the Free Plugin Version
- Handling Licensing in JavaScript
- Handling Licensing in CSS
- Handling Premium readme.txt
- Managing One Codebase for Both Free and Premium Versions
- WordPress.org Compliance
Control Free and Premium WordPress Features with Freemius Licensing
The Freemius SDK licensing logic is both powerful and easy to use, allowing you to control which features of your product are available in the free, premium, or trial versions.
Once the logic is implemented, Freemius automatically determines which capabilities of your product should be enabled or disabled for each plan.
Plan vs. Code Type
Before jumping into the code, it's important to understand the difference between a Plan and a Code Type.
Plan
Every product on Freemius can have as many plans as you need. A plan is a set of features or services.
Multisite license offers are not considered additional plans. The SDK automatically handles the activation logic for multisite licenses.
All licensing functions that support plans require you to pass the plan's Unique name as a parameter ($plan). You can find the plan's unique name in your Freemius Developer Dashboard under Plans.
When using plan-related licensing logic, any plan with a higher tier than the plan you are checking for will also return true. For example, if you have three plans: basic, professional, and business, and you check for the professional plan, the result will be true for both professional and business plans. This behavior can be controlled by the $exact parameter in the plan-related methods.
To change the tier of your plans, go to your Freemius Developer Dashboard and drag the plans to the desired order.
Code Type
Every plugin, theme, or add-on on Freemius can have at most two code types:
- The Free Version, where the product's code is stripped of any premium-only features.
- The Premium Version, where the product's code includes both free and premium functionality, even though access to premium functionality still depends on the user's license or trial.
The Freemius SDK licensing logic is used by the Freemius deployment preprocessor to automatically remove premium-only code from your product during deployment and generate a free version for you. This process enables you to maintain a single codebase for both the free and premium versions of your product.
The SDK also exposes several methods to help you determine which code type is currently running. You can use this knowledge to display marketing content or upsell features to your users.
License-Related Methods
These methods are used to determine the user's license status and plan. They can be used to control access to premium features, display marketing content, or manage trials.
Check if the user is on a specified plan.
If the user is on a trial of that plan the result will be
false. Use theis_plan_or_trial()method.
Check if the user is on a specific plan or on that plan's trial.
Add Scope to Premium Code
Many of the methods above also support scoping code so it is included in the premium version only. This is done by adding the __premium_only suffix to the method name, e.g., is_plan() becomes is_plan__premium_only().
Once scoped, any code within the if block will be stripped from the free version by the Freemius deployment preprocessor.
For example, the preprocessor removes the premium-only block from the generated free version:
- Source / Premium Version
- Generated Free Version
// ...some logic...
if ( my_fs()->is_plan__premium_only('professional') ) {
// ... logic related to professional plan and higher plans ...
}
// ...some more logic...
// ...some logic...
// ...some more logic...
This is useful to keep the generated free version compliant with the WordPress.org guidelines.
Recommended Methods
Single Paid Plan
If your product only has a single paid plan, the primary methods you will use are:
Multiple Paid Plans
If your product has multiple paid plans, the recommended methods to start with are:
Multiple Paid Plans With Trials
If your product supports trials, the recommended methods are:
is_plan_or_trial()is_plan_or_trial__premium_only()can_use_premium_code()can_use_premium_code__premium_only()
See how trials work.
Marketing or Upsell Content
For targeted marketing content, the recommended methods are:
is__premium_only()- If you want to check whether the codebase is premium or free.is_not_paying()- If you want to check whether the user is on a trial or free plan.
Examples
In the sample code below, the product's unique prefix is my_fs, and the paid plan's name is professional. These values will be different for your product when you customize it.
In these examples, the Source / Premium Version tab represents the code you keep in your main codebase and upload to Freemius. The Generated Free Version tab shows what remains after deployment removes premium-only code.
Premium Usage Eligibility
Use is__premium_only() when a code path should exist only in the premium package. The generated free version keeps the free logic and removes the premium-only block.
- Source / Premium Version
- Generated Free Version
add_action( 'admin_init', 'my_plugin_register_free_settings' );
if ( my_fs()->is__premium_only() ) {
add_action( 'admin_init', 'my_plugin_register_premium_settings' );
}
add_action( 'admin_init', 'my_plugin_register_free_settings' );
Use can_use_premium_code__premium_only() when the code should exist only in the premium package and run only for users on a trial or with a valid license.
- Source / Premium Version
- Generated Free Version
add_action( 'init', 'my_plugin_register_public_shortcodes' );
if ( my_fs()->can_use_premium_code__premium_only() ) {
add_action( 'init', 'my_plugin_register_premium_shortcodes' );
}
add_action( 'init', 'my_plugin_register_public_shortcodes' );
Add Marketing Content
You can also check for non-paying users. Here is how you can add customized marketing content to encourage users to upgrade from your free to your premium version:
if ( my_fs()->is_not_paying() ) {
echo '<section><h1>' . esc_html__('Awesome Professional Features', 'my-text-domain') . '</h1>';
echo '<a href="' . esc_url(my_fs()->get_upgrade_url()) . '">' . esc_html__('Upgrade Now!', 'my-text-domain') . '</a>';
echo '</section>';
}
Convert Your Methods for Premium
To make a function available only in your premium version, add the __premium_only suffix to the function's name, i.e., convert_values becomes convert_values__premium_only.
Make sure that every line that calls that method, either directly or through hooks, is also wrapped in premium-only logic.
- Source / Premium Version
- Generated Free Version
class My_Plugin {
function init() {
$this->register_free_settings();
if ( my_fs()->is__premium_only() ) {
$this->admin_init__premium_only();
add_action( 'admin_init', array( &$this, 'admin_init_hook__premium_only' ) );
}
}
function register_free_settings() {
// ... free settings logic ...
}
function admin_init__premium_only() {
// ... premium settings logic ...
}
function admin_init_hook__premium_only() {
// ... premium admin hook logic ...
}
}
class My_Plugin {
function init() {
$this->register_free_settings();
}
function register_free_settings() {
// ... free settings logic ...
}
}
Usage in Premium Plans
Use is_plan__premium_only() when a feature should exist only in the premium package and be available to customers on a specific plan or higher tier.
- Source / Premium Version
- Generated Free Version
add_filter( 'my_plugin_available_reports', 'my_plugin_free_reports' );
if ( my_fs()->is_plan__premium_only('professional') ) {
add_filter( 'my_plugin_available_reports', 'my_plugin_professional_reports' );
}
add_filter( 'my_plugin_available_reports', 'my_plugin_free_reports' );
If the premium package needs different behavior for different plans, wrap the full plan-handling block with is__premium_only() and check the plan inside it.
- Source / Premium Version
- Generated Free Version
add_filter( 'my_plugin_export_limit', 'my_plugin_free_export_limit' );
if ( my_fs()->is__premium_only() ) {
if ( my_fs()->is_plan( 'professional', true ) ) {
add_filter( 'my_plugin_export_limit', 'my_plugin_professional_export_limit' );
}
elseif ( my_fs()->is_plan( 'business' ) ) {
add_filter( 'my_plugin_export_limit', 'my_plugin_business_export_limit' );
}
}
add_filter( 'my_plugin_export_limit', 'my_plugin_free_export_limit' );
Usage For Trials
Use is_plan_or_trial__premium_only() when a feature should exist only in the premium package and be available to users on a paid plan or a trial of that plan.
- Source / Premium Version
- Generated Free Version
add_action( 'init', 'my_plugin_register_basic_blocks' );
if ( my_fs()->is_plan_or_trial__premium_only( 'professional' ) ) {
add_action( 'init', 'my_plugin_register_professional_blocks' );
}
add_action( 'init', 'my_plugin_register_basic_blocks' );
How Trials Are Handled
When users start a trial, the SDK prompts them to download and activate the premium version.
All premium features will be available to the user if they are placed behind:
is_plan_or_trialis_plan_or_trial__premium_onlycan_use_premium_code__premium_only
If your licensing logic depends only on is_plan or is__premium_only, those features will not be available during a trial.
Once the trial expires, if the user has not converted to a paid license (subscription or lifetime purchase), all features and access to updates will be blocked by the SDK. This applies regardless of any configuration you have under the plan. The user simply reverts to the free plan with no premium features.
Common Misconceptions
Some uses of the premium licensing methods can leave premium code blocks in your free version. This can result in rejection when uploading the product to the WordPress.org repository.
Integration With Inline Statements
Avoid using if statements with inline conditional statements when wrapping premium code.
$some_condition = true;
// This will not allow premium code stripping.
if ( $some_condition && can_use_premium_code() ) {
// Some running code
}
You can work around this by using nested conditions:
$some_condition = true;
if ( can_use_premium_code() ) {
if ( $some_condition ) {
// Run the relevant code
}
}
Setting Variables via Premium Check
Setting variables directly from premium methods means that code will remain in the generated free version. For example:
$has_pro_license = my_fs()->can_use_premium_code();
echo $has_pro_license ? 'Premium/Trial' : 'free';
Use a separate if block instead:
$has_pro_license = false;
if ( my_fs()->can_use_premium_code() === true ) {
$has_pro_license = true;
}
echo $has_pro_license ? 'Premium/Trial' : 'free';
This structure allows the deployment process to strip the premium if block from the free version while retaining it in the premium version.
Excluding Files and Folders from the Free Plugin Version
There are two ways to exclude files from your free version:
__premium_only File Suffix
Add __premium_only just before the file extension, e.g., functions__premium_only.php. This file will only be included in the premium plugin version. This works for PHP, JS, and CSS file types.
@fs_premium_only Meta Tag
For plugins, add the @fs_premium_only special meta tag to the main PHP file header.
/**
* Plugin Name: My Very Awesome Plugin
* Plugin URI: http://my-awesome-plugin.com
* Description: Create and manage Awesomeness right in WordPress.
* Version: 1.0.0
* Author: Awesome Team
* Author URI: http://my-awesome-plugin.com/me/
* License: GPLv2
* Text Domain: my-awesome-plugin
* Domain Path: /language
*
* @fs_premium_only /lib/functions.php, /premium-files/
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ... my code ...
The file /lib/functions.php and the directory /premium-files/ will be removed from the free plugin version.
For themes, add @fs_premium_only, a special meta tag, to the theme's main style.css file header. Example:
/**
* Theme Name: My Awesome Theme
* Theme URI: http://my-awesome-theme.com
* Description: Create and manage Awesomeness right in WordPress.
* Version: 1.0.0
* Author: Awesome Team
* Author URI: http://my-awesome-theme.com/me/
* License: GPLv2
* Text Domain: my-awesome-theme
*
* @fs_premium_only /premium-functions.php, /premium-files/
*/
body { ... }
span { ... }
The file /premium-functions.php and the directory /premium-files/ will be removed from the free theme version.
For example, a plugin with both free and premium files could look like this before and after deployment:
- Source / Premium Version
- Generated Free Version
my-plugin/
|-- my-plugin.php
|-- includes/
| |-- free-settings.php
| |-- advanced-reports/
| | `-- class-advanced-reports.php
| `-- export-tools__premium_only.php
|-- assets/
| |-- js/
| | |-- admin.js
| | `-- reports__premium_only.js
| `-- css/
| |-- admin.css
| `-- reports__premium_only.css
`-- readme.txt
my-plugin/
|-- my-plugin.php
|-- includes/
| `-- free-settings.php
|-- assets/
| |-- js/
| | `-- admin.js
| `-- css/
| `-- admin.css
`-- readme.txt
In this example, advanced-reports/ would be listed in @fs_premium_only, and the files using the __premium_only suffix would be removed automatically.
@fs_ignore Meta Tag
Similar to @fs_premium_only, this tag directs the PHP preprocessor to ignore a given collection of files or folders that do not need processing. For example, if you have a vendors folder with third-party libraries that should remain untouched in both the free and premium versions, that folder would be a great candidate for the @fs_ignore tag.
- For plugins, add
@fs_ignoreto the plugin's main PHP file header. - For themes, add
@fs_ignoreto the theme'sstyle.cssstylesheet.
Handling Licensing in JavaScript
If you need to control licensing in your JavaScript files at runtime, assign a can_use_premium_code property under a my_module object in the browser.
<?php
function my_module_add_licensing_helper() {
?>
<script type="javascript/text">
(function(){
window.my_module.can_use_premium_code = <?php json_encode( my_fs()->can_use_premium_code() ); ?>;
})();
</script>
<?php
}
add_action('wp_head', 'my_module_add_licensing_helper');
Then directly in the JavaScript files, add:
if (window.my_module.can_use_premium_code) {
// ... premium only code ...
}
If you need JavaScript code to be removed from the generated free version, wrap it with Freemius meta comments:
- Source / Premium Version
- Generated Free Version
(function ($) {
$('.my-plugin-basic-filter').on('change', refreshItems);
/*! <fs_premium_only> */
$('.my-plugin-premium-export').on('click', exportItems);
/*! </fs_premium_only> */
})(jQuery);
(function ($) {
$('.my-plugin-basic-filter').on('change', refreshItems);
})(jQuery);
In the future, we will provide a richer JavaScript SDK that will handle license-related logic in a similar manner to how our PHP SDK does it.
Preserving Freemius Meta Comments in webpack
If your build process minifies JavaScript, make sure it preserves Freemius meta comments. For example, when developing a Block Editor/Gutenberg or JavaScript-driven plugin with webpack and UglifyJS, configure webpack.config.js as follows:
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
output: {
comments: /<\/?fs_premium_only>/i,
},
},
extractComments: true,
}),
],
},
};
For Gutenberg/Block Editor development, see this guide.
Handling Licensing in CSS
You can mark entire stylesheets as premium-only and exclude them as whole files.
Alternatively, you can use /*! <fs_premium_only> */ tags inside a CSS file. This strips the premium styles from that file in the generated free version.
- Source / Premium Version
- Generated Free Version
/*! <fs_premium_only> */
.premium-only {
display: none;
}
/*! </fs_premium_only> */
.general-usage {
display: flex;
}
.general-usage {
display: flex;
}
Handling Premium readme.txt
If you have a premium-only product without a free version, the WordPress SDK fetches the readme.txt file content from the Freemius API instead of WordPress.org.
For freemium plugins and themes, you only need to maintain a single version of your product. We built a special Markdown-friendly syntax to control which parts of your readme.txt appear in the free version, the premium version, or both.
Premium-Only readme.txt Content
If you want content to appear only in the premium version, use the following syntax in your readme.txt:
[//]: # fs_premium_only_begin
Whatever goes in here will only appear in the premium readme
[//]: # fs_premium_only_end
Free-Only readme.txt Content
For content to appear only in the free version, use the following syntax in your readme.txt:
[//]: # fs_free_only_begin
Whatever goes in here will only appear in the free readme
[//]: # fs_free_only_end
Common readme.txt Content
For content to appear in both the free and premium readme.txt files, you do not need to wrap it in any syntax.
Here is an example of a freemium readme.txt:
- Source readme.txt
- Generated Free Version
- Generated Premium Version
=== My Awesome Product ===
Requires at least: 3.0
Tested up to: 4.9
Stable tag: 3.1.0
License: GPLv2 or later
== Description ==
This is the best product ever!
== Installation ==
1. Upload the product to your blog.
2. Activate it.
[//]: # fs_premium_only_begin
3. Enter the license key you received after the purchase and activate it.
[//]: # fs_premium_only_end
== Change Log ==
[//]: # fs_premium_only_begin
= 1.0.0 =
* New: New premium feature!
[//]: # fs_premium_only_end
[//]: # fs_free_only_begin
= 1.0.0 =
* New: New free feature!
[//]: # fs_free_only_end
=== My Awesome Product ===
Requires at least: 3.0
Tested up to: 4.9
Stable tag: 3.1.0
License: GPLv2 or later
== Description ==
This is the best product ever!
== Installation ==
1. Upload the product to your blog.
2. Activate it.
== Change Log ==
= 1.0.0 =
* New: New free feature!
Requires at least: 3.0
Tested up to: 4.9
Stable tag: 3.1.0
License: GPLv2 or later
== Description ==
This is the best product ever!
== Installation ==
1. Upload the product to your blog.
2. Activate it.
3. Enter the license key you received after the purchase and activate it.
== Change Log ==
= 1.0.0 =
* New: New premium feature!
Managing One Codebase for Both Free and Premium Versions
The Freemius SDK allows you to manage a single codebase for both the free and premium versions of your plugin or theme. This is done by using Freemius license-handling methods to designate which features are premium-only.
This licensing logic in turn enables the deployment preprocessor to strip premium-only features out of your free version for easy deployment on WordPress.org. This way, you do not have to manage two versions of your product separately.
If you have already developed free and premium versions that are fundamentally different, you can either merge the versions into a single codebase or ignore the free version generated by Freemius. If you go with the second option, make sure to also integrate the SDK into your free version and set the is_premium flag to false to indicate that the SDK is running in the scope of the free version.
WordPress.org Compliance
Based on the WordPress.org Guidelines, you are not allowed to submit a plugin that has trialware/premium code in it:
"All code hosted by WordPress.org servers must be free and fully-functional. If you want to sell advanced features for a plugin (such as a "pro" version), then you must sell and serve that code from your own site, we will not host it on our servers."
If you want to deploy your free plugin version to WordPress.org, use the methods above to exclude premium features and files, or wrap all premium code with if statements like this:
if ( my_fs()->is__premium_only() ) {
// ... my premium only logic ...
}
See the deployment guide on how this works.