Developer Reference
Introduction
AAM was designed and implemented by developers for developers. It is flexible, powerful and has a light API as well as dozens of internal hooks and configurations.
We’ve tried hard to be less opinionated about how things have to be done and focused only on what is most essential for developers to create beautiful websites. That is why, while we providing an abstract layer on top of the WordPress core access controls, we also keep it simple.
Note! While we are all about the latest and greatest when it comes to PHP language, we also are extremely serious about backward compatibility. That is why we consciously made the decision to keep AAM compatible with at least PHP 5.6. However, AAM is 100% object-oriented so it is strongly encouraged to be proficient in this paradigm.
The developer reference page is structured in the way that you can learn the concepts and technics by practicing them. That is why each section, contains at least one snippet of copy&paste code.
FYI! You can download our boilerplate plugin from the Github repository that can be used as a good starting point for a new AAM add-on or to play with code samples from this reference.
Core Concepts
AAM is tightly integrated with WordPress core. Our main goal is to find a way to utilize existing WordPress functionality and do not create alternative ways or reinvent existing features that supposedly work “better”.
We believe that the current WordPress core state of functionality is as good as it can be considering the amount of website using it and impressive backward compatibility. That is why AAM does not create any new database tables and uses a couple, slightly modified external libraries for JWT and Access Policy services. You can find those libraries in the /vendor folder.
To master AAM, you should understand few fundamental concepts: Objects, Subjects, ConfigPress and finally how access settings are inherited (propagated).
Objects
AAM object is a website resource that you manage access to for your users, roles or visitors. An object can be any website post, page, category, backend menu, etc.
In this sample, we simply dumping the entire AAM post object for the current post ID:
<?php
/**
* Plugin Name: AAM Cauldron
* Description: Just a playground for any functionality that is related to AAM
* Version: 0.0.1
* Author: Vasyl Martyniuk
* Author URI: https://vasyltech.com
**/
if (defined('ABSPATH')) {
add_action('wp', function () {
$current_id = get_the_ID();
if ($current_id) {
var_dump(\AAM::getUser()->getObject(
\AAM_Core_Object_Post::OBJECT_TYPE, $current_id
));
exit;
}
});
}
An object can also be used as a “container” for some general-purpose settings for any user, role or visitor. For example login, logout redirect, default category or access denied redirect rules. The only big difference between objects that contain access settings and general-purpose settings is in merging mechanism when a user has two or more roles. While in the first case, AAM merges access settings based on defined preference, in the second case, the last role overrides settings from the previous role.
FYI! You can learn more about multi-role support from the WordPress access control for users with multiple roles article.
In the example below, we are checking if access denied redirect rule for the frontend is set to redirect the user to some URL, and if so, then dump all the access denied redirect settings.
<?php
/**
* Plugin Name: AAM Cauldron
* Description: Just a playground for any functionality that is related to AAM
* Version: 0.0.1
* Author: Vasyl Martyniuk
* Author URI: https://vasyltech.com
**/
if (defined('ABSPATH')) {
add_action('wp', function () {
$redirect = \AAM::getUser()->getObject(
\AAM_Core_Object_Redirect::OBJECT_TYPE
);
if ($redirect->get('frontend.redirect.type') === 'url') {
var_dump($redirect->getOption());
}
});
}
Under the hood, each declared object extends abstract class AAM_Core_Object that contains minimum required methods to handle the most common use-cases. Each individual instance of an object may have a different set of methods to do things that are specific to its domain.
AAM has several core objects included in the basic AAM version and few available with add-ons. You can find the complete list of all available objects in the Core Objects section or, if necessary, create your own object. You can learn about creating a custom object from the Create Custom Object section.
Subjects
AAM subject is the general definition for whom access is managed for. While object answers the question how, subject answers the question who.
For example, you may restrict access to the website URI /category/protected-content (object URI) for all users (subject User) that belong to role (subject Role) Subscribers.
AAM comes with 4 predefined subjects that cover all the known user-cases: User, Role, Visitor and Default.
In the majority of the cases, you will work with either subject type User or Visitor to determine if current user/visitor has access to requested resource or can perform certain action upon it.
To simplify the developer’s duty, AAM comes with a simple static method that returns a correct subject type based on the sender’s state:
// Return current user: either AAM_Core_Subject_User or AAM_Core_Subject_Visitor
AAM::getUser();
// The alternative way to retrieve current user
AAM::api()->getUser();
To learn more about each core subject and how to work with them, refer to the Core Subjects section.
ConfigPress
ConfigPress is the INI-based configuration engine for AAM core. The most complete list of available configurations you can find in the ConfigPress section, however you are free to define your own configurations and programmatically retrieve them with AAM::api()->getConfig method.
For example if you defined a custom JWT token expiration, you can retrieve it as following:
; JWT token will expire in 1 hour
authentication.jwt.expires = 3600
$expires = AAM::api()->getConfig("authentication.jwt.expires", 86400);
where the first argument is a ConfigPress option while the second argument is a default value that will be returned if option is not defined.
Note! the AAM::api()->getConfig can return only options that belong to section, so always make sure that this section is defined.
Inheritance Mechanism
AAM has a quite sophisticated and flexible access inheritance mechanism. It is something that “stitches” together objects and subjects based on how they are related to each other.
FYI! Always keep in mind that not a single object (resource) in a WordPress website is stand-alone. It either relates to other object(s) or access to it vary from user to user.
The major benefit for using AAM comes with the fact that it takes into consideration relationships between objects, users and roles, and merges settings accordingly to their’s hierarchical placement (where lower-level settings override higher-level settings).
You can learn more about inheritance mechanism from the AAM access settings inheritance mechanism article.
In the first example, we will programmatically restrict access to the backend menu “Pages” for everybody, and override it for Administrator role.
<?php
/**
* Plugin Name: AAM Cauldron
* Description: Just a playground for any functionality that is related to AAM
* Version: 0.0.1
* Author: Vasyl Martyniuk
* Author URI: https://vasyltech.com
**/
if (defined('ABSPATH')) {
register_activation_hook(__FILE__, function() {
$menu = \AAM::api()->getDefault()->getObject(
\AAM_Core_Object_Menu::OBJECT_TYPE
);
// Restricting access to the "Pages" backend menu
$menu->updateOptionItem('edit.php?post_type=page', true)->save();
// Explicitly override access only for the Administrator role
\AAM::api()->getRole('administrator')->getObject(
\AAM_Core_Object_Menu::OBJECT_TYPE
)->updateOptionItem('edit.php?post_type=page', false)->save();
});
}
API
AAM offers a single API endpoint that gives you all necessary methods to work with AAM objects, subjects and configurations.
Always use AAM::api() static method to obtain an instance of AAM API. Do not use other classes directly as they may be changed in the near future and we cannot guarantee that they’ll be backward compatible. Also do not rely on the name of the object that AAM::api() returns as the names may be changes in the future AAM releases.
AAM::api
The AAM::api() static method returns the singleton of AAM API object that has all necessary methods to work with subjects and configurations.
Description
object AAM::api()
Returns
Instance of AAM API object.
AAM:api()->getConfig
Get config option that is either set through AAM UI or managed with ConfigPress.
Description
mixed AAM::api()->getConfig(string $option, mixed $default = null)
Parameters
- option – option name
- default – value to return if option does not exist (default value is null)
Returns
Configuration value or default value if nothing was found. Typically it returns string or array.
Example
// This will print "Hello World!" on the frontend side of a website
add_action('init', function() {
if (!is_admin()) {
echo AAM::api()->getConfig('my.custom.option');
}
});
AAM:api()->getRole
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM:api()->getUser
Get the user by the specified ID or current user if none is provided.
Description
AAM_Core_Subject AAM::api()->getUser(int $id = null)
Parameters
- id – optional user Id.
Returns
If $id is not provided, AAM returns either AAM_Core_Subject_Visitor instance if user is not authenticated otherwise AAM_Core_Subject_User.
Example
// Check if current visitor has ability to see Post Categories widgets on the frontend.
// Get access settings for current user to frontend widgets
$metaboxes = AAM::api()->getUser()->getObject('metabox');
// Check if user has access to the widget that shows list of categories
if ($menu->has('widgets', 'WP_Widget_Categories')) {
echo 'The list of categories is denied. Please login to see them';
}
AAM:api()->getVisitor
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM::api()->getDefault
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
Core Objects
Object, in the context of AAM functionality, is something that you manage access to (e.g. post, page, category, backend menu) or a collection or settings/properties (e.g. login redirect, access denied redirect).
Object never exists independently from a subject (user, visitor, role or default settings) and always has to be obtained through an instance of AAM_Core_Subject with the getObject() method.
Description
AAM_Core_Object AAM_Core_Subject->getObject(string $type, mixed $id = null, bool $skipInheritance = false)
Parameters
- type – is an object type like post, menu, capability etc.
- id – optional. Some objects do not have ids (e.g. menu, login redirect) and some do (e.g. post, term, type).
- $skipInheritance – optional. If set as true, then do not invoke inheritance mechanism and return settings that defined only for current subject
Returns
Instance of AAM object that derives from AAM_Core_Object abstract class.
Example
// Get instance of Post with ID 5 that has access settings for user with ID 2
$post = AAM::api()->getUser(2)->getObject('post', 5);
AAM_Core_Object_Toolbar
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_Metabox
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_Post
The AAM_Core_Object_Post object is the abtraction layer to work with an individual post record. Under post record we mean any post, page, media attachment or custom post type. Basically anything that is stored in the wp_posts database table.
In the example below, we retrieve a post with ID 345. The retrieved object will contain already initialized access settings for the current user.
$post = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 345);
From here the $post contains the instance of AAM_Core_Object_Post that is the additional layer that wraps WP_Post object. Which means, you can access all its public properties properties (e.g. $post->post_title, $post->post_author, etc.).
This object also can be used to programmatically check all saved access settings and even set new. In the example below, we restrict access to read the post.
$post = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 345);
if ($post->updateOptionItem('restricted', true)->save()) {
// Yes! Settings are saved
}
The AAM_Core_Object_Post::updateOptionItem method sets the permission while AAM_Core_Object_Post::save persists it in the database. This type of separation was done for performance reasons.
AAM_Core_Object_Policy
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_Uri
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_Route
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_Redirect
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_LoginRedirect
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Object_LogoutRedirect
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM\AddOn\IPCheck\Object\IPCheck
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM\AddOn\PlusPackage\Object\Taxonomy
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM\AddOn\PlusPackage\Object\Term
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM\AddOn\PlusPackage\Object\Type
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
Core Subjects
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Subject_User
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Subject_Role
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Subject_Visitor
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
AAM_Core_Subject_Default
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
Filters & Actions
AAM has numerous of hooks that can be used by custom functionality to extend access management. In WordPress core hooks are divided into two categories – filters and actions so AAM hooks are named accordingly.
Please do not hesitate to contact us if you think AAM needs additional hooks or you simply can’t figure out how to hook your custom functionality.
aam_metabox_object_option_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_post_object_option_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_route_object_option_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_uri_object_option_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_token_typecast_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_post_read_access_pipeline_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_jwt_claims_filter
AAM comes with the “JWT Tokens” service that programmatically issues and maintains JWT access tokens for users. During the process of issuing a token, AAM defines the list of claims for it. You have the ability to change this list with aam_jwt_claims_filter filter.
In the example below, we are going to add the user’s email and name to the list of claims and the code is prepared as a stand-alone plugin so it should work out-of-box.
<?php
/**
* Plugin Name: AAM Cauldron
* Description: Just a playground for any AAM custom code
* Version: 0.0.1
* Author: Vasyl Martyniuk
* Author URI: https://vasyltech.com
*
* -------
* LICENSE: This file is subject to the terms and conditions defined in
* file 'LICENSE', which is part of AAM Protected Media Files source package.
**/
namespace AAM\AddOn\Cauldron;
/**
* Main add-on's bootstrap class
*
* @package AAM\AddOn\Cauldron
* @author Vasyl Martyniuk
* @version 0.0.1
*/
class Bootstrap
{
/**
* Single instance of itself
*
* @var AAM\AddOn\Cauldron\Bootstrap
*
* @access private
* @version 0.0.1
*/
private static $_instance = null;
/**
* Initialize the object
*
* @return void
*
* @access protected
* @version 0.0.1
*/
protected function __construct()
{
add_filter('aam_jwt_claims_filter', function($claims) {
$user = get_user_by('ID', $claims['userId']);
return array_merge($claims, array(
'sub' => $user->user_email,
'name' => $user->display_name
));
});
}
/**
* Activation hook
*
* @return void
*
* @access public
* @version 0.0.1
*/
public static function activate()
{
global $wp_version;
if (version_compare(PHP_VERSION, '5.6.40') === -1) {
exit(__('PHP 5.6.40 or higher is required.'));
} elseif (version_compare($wp_version, '4.7.0') === -1) {
exit(__('WP 4.7.0 or higher is required.'));
} elseif (!defined('AAM_VERSION') || (version_compare(AAM_VERSION, '6.0.0') === -1)) {
exit(__('Free Advanced Access Manager plugin 6.0.0 or higher is required.'));
}
}
/**
* Initialize and get single instance of itself
*
* @return AAM\AddOn\Cauldron\Bootstrap
*
* @access public
* @version 0.0.1
*/
public static function init()
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
return self::$_instance;
}
}
if (defined('ABSPATH')) {
// Activation hooks
register_activation_hook(__FILE__, __NAMESPACE__ . '\Bootstrap::activate');
// Initialize AAM hooks
add_action('init', function() {
\AAM\AddOn\Cauldron\Bootstrap::init();
});
}
The final set of claims will be something like this:
{
"iat": 1580820135,
"iss": "https://demo.aamplugin.com",
"exp": 1581511333,
"jti": "15572261-f177-447e-ad93-08320d7dbd2b",
"userId": 4,
"revocable": true,
"refreshable": false,
"sub": "subscriber@aamplugin.com",
"name": "Alison Brown"
}
aam_extract_jwt_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_auth_response_filter
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_post_add_role_action
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_post_update_role_action
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_policy_token_value_filter
Not yet documented. Sorry...
aam_clear_settings_action
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
aam_initialize_user_action
Documentation is under development. If you have any specific questions, please feel free to submit your question on our For Developers forum page.
ConfigPress
Not yet documented. Sorry...
How to ..?
Not yet documented. Sorry...
Create Custom Object
Not yet documented. Sorry...
Work With Custom Params
Not yet documented. Sorry...
Work With Access Policy Manager
Policy Manager is an abstract layer that takes the provided subject, fetches a list of all attached policies, parses them and creates the internal resource tree. All the objects, during initialization, use the Policy Manager to fetch access settings from the applicable statements and params. The code sample below returns the Policy Manager instance.
// Get Policy Manager that works with the current user
$manager = AAM::api()->getAccessPolicyManager();
// Get Policy Manager for a very specific subject
$manager = AAM::api()->getAccessPolicyManager(
AAM::api()->getUser($user_id)
);
The Policy Manager has two very useful public methods getParam and isAllowed and below are a couple of examples that explain how they work.
Let’s imagine that there is some ReactJS application that authenticates with WordPress core and obtains JWT token. The token contains groups claim with an array of groups that an authenticated user has. The application limits the number of posts that a user can create if she belongs to the “Trial” group.
In this case, you can define an access policy that stores the necessary param and make it conditional.
{
"Param": [
{
"Key": "limit:posts",
"Value": 5,
"Condition": {
"In": {
"trial": "(*array)${JWT.groups}"
}
}
}
]
}
This way, in the code, you do not have to worry about implementing any conditions. The getParam evaluates all the conditions on the fly and if it is applicable, the value 5 is returned, otherwise, the null value is returned.
// Get Policy Manager that works with the current user
$manager = AAM::api()->getAccessPolicyManager();
$limit = $manager->getParam('limit:posts');
if ($limit === null) {
echo 'You have no limits';
} else {
echo 'You are limited to ' . $limit;
}
The isAllowed method works directly with resources and actions and returns a boolean value true if access is allowed, false if access is denied and null if a resource was not found (not defined in all declared and applicable statements).
For example, the policy below declares one statement that denies access to read the page “Hello World!” (identified by slug hello-world).
{
"Statement": {
"Effect": "deny",
"Resource": "Post:page:hello-world",
"Action": "Read"
}
}
Following code, checks if access is allowed to the “Hello World!” page for the current user/visitor:
// Get Policy Manager that works with the current user
$manager = AAM::api()->getAccessPolicyManager();
if ($manager->isAllowed('Post:page:hello-world:Read') === false) {
echo 'You are not allowed to read the "Hello World!" page.';
}
Check Role(s) Access To Resource(s)
It is a common requirement to be able to programmatically determine if any role has access to specific resources.
AAM API object gives you the ability to instantiate any resource (aka object) within the context of any subject (role, user, visitor, or default). During the instantiation process, AAM automatically initializes access settings to the specific resource based on the selected subject.
In the example below, we will iterate over each existing WordPress role and aggregate them into two separate buckets where $allowed will contain list of roles that have access to the post and $denied do not.
$post_id = 1;
// Fetching list of all registered roles and iterating over each role to
// determine if access is allowed. The result is to a plain array with a list of allowed
// and denied roles
//
// Note! In my example "determining if access is allowed" is checking if role has
// the ability to read the post (RESTRICTED option). In you case it can be other
// option like HIDDEN or LIMITED.
$allowed = $denied = array();
// FYI! We are using `get_names` method to fetch list of role slugs. It is possible that
// in some cases this method may return actually role names. It all depends on plugins
// that are installed on the website as we do not exclude the possibility that some
// third-party functionality hijacking WP_Roles object data.
foreach(wp_roles()->get_names() as $role) {
// Getting AAM Core Object that represents the Post. This object will contain
// all the access settings to it based on the role
$post = AAM::api()->getRole($role)->getObject(
AAM_Core_Object_Post::OBJECT_TYPE, $post_id
);
if ($post->is('restricted')) {
$denied[] = $role;
} else {
$allowed[] = $role;
}
}