Jump to table of contents

Release Notebook for OJS/OMP v3.2

OJS and OMP v3.2 were released on 29 February, 2020. This release notebook provides technical guidance on changes that will impact software developers, plugin and theme authors, and anyone who works with the application codebase.

Versioning for articles and monographs #

This release introduces article and monograph versioning. This is a significant breaking change that will impact almost all third-party code. When a submission is published, changes to the publication can only be made by creating and publishing a new version of that submission.

To accomplish this, a new Publication object has been introduced which stores a submission’s title, metadata, contributors, galleys and any data related to the published submission.

When a new version is created, a deep copy of the publication is created including attached objects such as authors and galleys. Hooks are available to clone additional objects which you may need to associate with the publication.

Read our guidance on working with publication versions. Learn how this will impact custom themes. And view the documentation for changes to the REST API endpoints.

PublishedArticle and PublishedMonograph removed #

The PublishedArticle and PublishedMonograph objects have been removed. Check the submission’s status to determine if it is published.

if ($submission->getData('status') === STATUS_PUBLISHED) {
	// submission is published

The PublishedArticleDAO and PublishedMonographDAO DAOs have also been removed. Published submissions should be retrieved by using the status argument of the submission service.

$publishedSubmissions = Services::get('submission')
	->getMany(['status' => STATUS_PUBLISHED]);

The data of a PublishedArticle or PublishedMonograph has been migrated to the Publication object. See publication versions.

Submission helper methods deprecated #

Most of the helper methods for the Submission class have been deprecated and may be removed in the near future.

// Deprecated
$abstract = $submission->getLocalizedAbstract();

// Use this instead
$abstract = $submission->getCurrentPublication()->getLocalizedData('abstract');

Some helper methods are still available on the Publication object.

// Deprecated
$title = $submission->getLocalizedTitle();

// Use this instead
$title = $submission->getCurrentPublication()->getLocalizedTitle();

Database schema changes #

The published_submissions table has been removed. Most of the data is now available in the publications table. The following table names have changed:

  • submission_categories is now publication_categories
  • submission_galley_settings is now publication_galley_settings
  • submission_galleys is now publication_galleys

Translations now use .po files #

Translation files have been converted from xml to po files and all translations should be submitted through our Weblate translation server.

Existing xml translation files will continue to work, but compatibility may be removed at any time in the future. Convert an xml translation file to po format by using lib/pkp/tools/xmlToPo.php (for the locale files) and lib/pkp/tools/xmlEmailsToPo.php (for email templates).

Using translations in the application has not changed and should still use the __('example.phrase') syntax.

Email templates now use .po files #

Email templates have been converted to po format so that they can be translated using our Weblate translation server. This effects all email templates shipped with OJS and OMP as well as any email templates in plugins.

Existing XML email templates will continue to work, but compatibility may be removed at any time in the future. The following pull request shows how the email templates were converted for the Orcid plugin.

New status introduced: STATUS_SCHEDULED #

In OJS, a Submission or Publication will be set to STATUS_SCHEDULED when it has been approved for publication in an issue that is not yet published. It will be granted STATUS_PUBLISHED when the issue is published.

In OMP, STATUS_SCHEDULED will be set when a Publication has been approved for publication with a datePublished that is in the future. A scheduled task has been introduced to grant STATUS_PUBLISHED when the date has been reached.

A Submission’s status will be updated automatically when any of its Publication objects have been published or unpublished. Never set the status directly for submissions and publications. Instead, use Services::get('publication')->publish($publication) and Services::get('publication')->unpublish($publication) to ensure the correct hooks are fired and the submission’s status is kept in sync.

Once a Submission has been published, it will remain STATUS_PUBLISHED as long as one Publication object is published.

Integration testing migrated to Cypress #

We now use Cypress for our integration testing. This applies to the full suite of tests for OJS and OMP as well as plugin integration tests (see Static Pages).

Learn more in our documentation on testing.

Changes to Service and QueryBuilder syntax #

A Service class’s getMany() method now returns a DAOResultIterator instead of an array. The iterator can be used like an array in foreach loops:

$contextsIterator = Services::get('context')->getMany(['isEnabled' => true]);
foreach ($contextsIterator as $context) {
    $names[] = $context->getLocalizedData('name');

However, a DAOResultIterator is not an array. It can not be looped over twice and it can not be used with the array_map, array_filter or array_reduce functions.

Use count() instead of !empty() to check if any results were found.

$contextsIterator = Services::get('context')->getMany(['isEnabled' => true]);
if (count($contextsIterator)) {
	// one or more contexts were found

Our documentation has been updated to reflect this change as well as new methods for the Service and QueryBuilder classes to help you retrieve data.

Service class to retrieve usage and editorial stats #

New service classes are available to help you retrieve and calculate statistics about your journal or press. The PKPStatsService will help extract data on visits to journals, articles and galleys. And the PKPStatsEditorialService will help you calculate data on submissions received, accepted and published, and how long authors must wait for editorial decisions.

Read more about working with reader and editorial statistics. You may also retrieve stats through the API.

New API endpoints #

Several new API endpoints have been introduced. Endpoints are now available to:

  • Add, edit, version and publish submissions
  • Create journals and presses and modify their settings
  • Retrieve reader and editorial stats
  • Add, edit and delete email templates

Read the API Reference.

Config settings #

A new setting, api_secret_key, must be set in the config.inc.php file in order to use the API with an API Token.

An unsubscribe link is now sent with each automated email. A new setting, signed_page_key_secret must be set in the config.inc.php file in order for this link to work.

New forms for context settings and submission metadata #

Our new architecture for building forms is now in use. These forms can be found in the journal settings as well as the new publication forms in the workflow.

Forms using this architecture can be built field-by-field from PHP classes on the server side.

$exampleForm = new \PKP\components\forms\FormComponent(
	'exampleForm',          // unique form id
	'PUT',                  // POST or PUT
	'http://...',           // URL to API endpoint to process the form
	__('success.message'),	// Message to display on success
	$locales,               // Array of locales to support
$exampleForm->addField(new FieldText('name', [
		'label' => __('manager.setup.contextTitle'),
		'value' => $context->getData('name'),
	->addField(new FieldText('acronym', [
		'label' => __('manager.setup.contextInitials'),
		'value' => $context->getData('acronym'),

Each form provides a hook so that you can extend it in a plugin.

\HookRegistry::register('Form::config::before', function($hookName, $form) {
	if ($form->id === 'exampleForm') {
		$form->addField(new FieldText('itemsPerPage', [
			'label' => __('common.itemsPerPage'),
			'value' => $context->getData('itemsPerPage'),

	return false;

All supported form fields extend the Field class. A class can be found for each field component described in the UI Library.

Our plan is to migrate all of our forms to this architecture. Further documentation is in progress which will describe how the forms interact with the Vue.js components and the REST API.

Article and Monograph objects renamed #

The Article and Monograph objects were renamed to Submission. This should help us share code between the applications.

More theme options #

Theme options now support all of the form field types in our UI Library except the image and file upload fields. Read our updated theming guide.

Languages, Countries and Currencies #

We have replaced our local tools for deriving ISO codes for languages, countries and currencies with php-isocodes.

New components in UI Library #

Our UI Library is growing rapidly as we transition our editorial backend to Vue.js. Explore all of the components available in the UI Library.