📋 Content Models
Content Approvals
📖 Docs

Content Approvals - Optimizely CMS 12

Exam Area: Content Area 5 – Content Models (25%)
Reference: https://docs.developers.optimizely.com/content-management-system/docs/content-approvals


1. What Are Content Approvals?

Content Approvals is a feature that lets you define approval sequences (review workflows) before content is published. Editors must request approval → reviewers approve/reject → content is published.


2. Approval Sequence

Editor saves/requests approval
    │
    ├── Step 1: Approver 1 (e.g., Marketing Lead)
    │       └── Approved? → Next step
    │
    ├── Step 2: Approver 2 (e.g., Legal Team)
    │       └── Approved? → Next step
    │
    └── Step N: Final Approver
            └── Approved? → Content Published

3. IApprovalDefinitionRepository (Code)

using EPiServer.Approvals;

public class ApprovalSetupService
{
    private readonly IApprovalDefinitionRepository _approvalRepository;
    private readonly IContentRepository _contentRepository;

    public ApprovalSetupService(
        IApprovalDefinitionRepository approvalRepository,
        IContentRepository contentRepository)
    {
        _approvalRepository = approvalRepository;
        _contentRepository = contentRepository;
    }

    public async Task SetupApprovalAsync(ContentReference contentLink)
    {
        // Create approval definition
        var definition = new ContentApprovalDefinition
        {
            ContentLink = contentLink,
            Steps = new List<ApprovalDefinitionStep>
            {
                new ApprovalDefinitionStep
                {
                    Name = "Marketing Review",
                    Approvers = new List<ApprovalDefinitionReviewer>
                    {
                        new ApprovalDefinitionReviewer
                        {
                            Name = "marketing-team",  // Role or username
                            Type = ApprovalDefinitionReviewerType.Role
                        }
                    }
                },
                new ApprovalDefinitionStep
                {
                    Name = "Legal Approval",
                    Approvers = new List<ApprovalDefinitionReviewer>
                    {
                        new ApprovalDefinitionReviewer
                        {
                            Name = "legal.reviewer@company.com",
                            Type = ApprovalDefinitionReviewerType.User
                        }
                    }
                }
            }
        };

        await _approvalRepository.SaveAsync(definition);
    }
}

4. IApprovalRepository

using EPiServer.Approvals;

public class ApprovalManagementService
{
    private readonly IApprovalRepository _approvalRepository;

    public ApprovalManagementService(IApprovalRepository approvalRepository)
    {
        _approvalRepository = approvalRepository;
    }

    // Get all pending approvals for current user
    public async Task<IEnumerable<Approval>> GetPendingApprovalsAsync()
    {
        return await _approvalRepository.ListAsync(
            new ApprovalQuery 
            { 
                Status = ApprovalStatus.InReview 
            });
    }

    // Approve a content item
    public async Task ApproveAsync(int approvalId, string comment = null)
    {
        await _approvalRepository.ApproveAsync(approvalId, comment);
    }

    // Reject a content item
    public async Task RejectAsync(int approvalId, string reason)
    {
        await _approvalRepository.RejectAsync(approvalId, reason);
    }
}

5. ApprovalStatus Enum

public enum ApprovalStatus
{
    Unknown = 0,
    InReview = 1,     // Awaiting approval
    Approved = 2,     // Has been approved
    Rejected = 3,     // Rejected
    Cancelled = 4,    // Cancelled
    Aborted = 5       // Aborted
}

6. Content Approval Events

[InitializableModule]
public class ApprovalEventHandler : IInitializableModule
{
    private IContentEvents _contentEvents;

    public void Initialize(InitializationEngine context)
    {
        _contentEvents = context.Locate.Advanced.GetInstance<IContentEvents>();
        _contentEvents.RequestingApproval += OnRequestingApproval;
        _contentEvents.PublishedContent += OnPublished;
    }

    public void Uninitialize(InitializationEngine context)
    {
        _contentEvents.RequestingApproval -= OnRequestingApproval;
        _contentEvents.PublishedContent -= OnPublished;
    }

    private void OnRequestingApproval(object sender, ContentEventArgs e)
    {
        // Notify approvers - can use INotificationRepository
        var contentLink = e.ContentLink;
        // Send notification to reviewers...
    }
    
    private void OnPublished(object sender, ContentEventArgs e)
    {
        // Content approved and published
        if (e.Action == SaveAction.Publish)
        {
            // Post-publish actions...
        }
    }
}

7. Admin UI

/episerver/cms/admin → Content Approvals
  → View approval sequences
  → Setup sequences per content item or tree
  → Manage approvers

Edit View:
  → When editor clicks "Request Approval"
  → Notification sent to reviewers
  → Reviewers access the Approvals gadget/notification

8. Integrated Notifications

// CMS automatically sends notifications when:
// 1. Editor requests approval
// 2. Reviewer approves/rejects
// 3. Content is published

// Custom notification - see 04_Framework_Components\08_notifications.md

Review Questions

  1. What are Content Approvals? (An approval workflow before content is published)
  2. What does IApprovalDefinitionRepository do? (Creates/manages approval sequences)
  3. What does ApprovalStatus.InReview mean? (Content is awaiting approval)
  4. How many steps can an approval sequence have? (Multiple steps, each with one or more approvers)
  5. When does the CMS send notifications automatically? (When approval is requested, when approved/rejected)