Ready to upgrade? Read our guide on how to upgrade.
OJS, OMP and OPS version 3.4 were released on June 9, 2023. 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.
The following changes may effect anyone who hosts or deploys one of the applications, as well as those who develop plugins or themes for the applications.
The minimum required version of PHP is 8.0 or above, following PHP’s version support schedule.
The country code has been dropped from many locale keys. For example, en_US
is now en
. You may need to update the locale
setting in the [i18n]
section of config.inc.php
. Supported locales can be found in the locale
directory.
mysqli
and postgres9
are the only valid values for the driver
setting in the [database]
section of config.inc.php
.
The client_charset
setting has been removed from config.inc.php
. Only the UTF-8 charset is supported.
PHPMailer
was replaced with Laravel’s Mailer. Add the preferred method for sending emails, such as sendmail
or smtp
, to the [email]
section of your config.inc.php
:
; Default method to send emails
; Available options: sendmail, smtp, log, phpmailer
default = sendmail
Servers that use sendmail
may need to add the path to the sendmail binary:
; Path to the sendmail, -bs argument is for using SMTP protocol
sendmail_path = "/usr/sbin/sendmail -bs"
It is now possible to send mail through third-party service providers like Mailgun. For sandbox environments, you can redirect mail to log files. Read Utilities > Email to learn more.
Jobs and queues are now used to manage long-running tasks. By default, these jobs will be processed during normal web requests, which may impact your site’s performance. We recommend setting up a worker daemon to process jobs.
A new time_zone
setting has been added to the [general]
section of config.inc.php
. See config.TEMPLATE.inc.php
for supported timezones.
Valid date and time formats in config.inc.php
must now be specified in PHP DateTime formatting. Recommended defaults can be found in the config.TEMPLATE.inc.php
file.
date_format_short = "Y-m-d"
date_format_long = "F j, Y"
datetime_format_short = "Y-m-d h:i A"
datetime_format_long = "F j, Y - h:i A"
time_format = "h:i A"
The old formats are deprecated and support may be removed in a future version.
A new user_validation_period
setting has been added to the [general]
section of config.inc.php
. Use this setting to automatically delete accounts from users who never validated their account. See config.TEMPLATE.inc.php
for a recommended default.
The following changes effect anyone who creates a plugin or theme for one of the applications, or wishes to integrate with the application through the REST API.
Namespaces are now used in all PHP code in the software and many global constants have been replaced with class constants. This is a major change to our codebase that will require changes in most plugins or themes.
We strongly encourage you to use a code editor that supports autocomplete to help you import classes, discover methods and constants, and identify syntax errors. Type hinting is used throughout more of the codebase now in order to make it easier to understand and write code for our applications.
The import()
statements and global constants like this are no longer used:
import('classes.submission.Submission');
import('lib.pkp.classes.author.PKPAuthor');
$submission = new Submission();
$author = new PKPAuthor();
$submission->setData('status', STATUS_PUBLISHED);
Replace this code with use
statements and class constants:
use APP\submission\Submission;
use PKP\author\Author;
$submission = new Submission();
$author = new PKPAuthor();
$submission->setData('status', Submission::STATUS_PUBLISHED);
Plugin and theme developers who want to use namespaces in their own code should read the instructions on how to adapt plugins.
The HookRegistry
class has been deprecated. Prepare for it to be removed in a future version by replacing this code:
HookRegistry::register('...', function($hookName, $args) {});
HookRegistry::call('...', [$a, $b]);
With this code:
use PKP\plugins\Hook;
Hook::add('...', function($hookName, $args) {});
Hook::call('...', [$a, $b]);
Plugin and theme developers should rename the locale
directories in their plugin according to the new locale codes mentioned above under Locales.
We have replaced the PKPLocale
and APPLocale
classes with a new facade class. Read the Utilities > Translation section of the developer docs to learn more about working with translations.
There is also a detailed description of changes.
There are new date and time formats specified in the config.inc.php
. Also, every journal, press or preprint server can configure different formats for every supported locale.
To show a date or time to a user, use one of the helper methods on the Context
(journal, press or preprint server).
$locale = Locale::getLocale();
$dateFormatShort = $context->getLocalizedDateFormatShort($locale);
$dateFormatLong = $context->getLocalizedDateFormatLong($locale);
$dateTimeFormatShort = $context->getLocalizedDateTimeFormatShort($locale);
$dateTimeFormatLong = $context->getLocalizedDateTimeFormatLong($locale);
$timeFormatShort = $context->getLocalizedTimeFormatShort($locale);
$timeFormatLong = $context->getLocalizedTimeFormatLong($locale);
Use the following to convert an old date/time format to the new format.
use PKP\core\PKPString;
$newFormat = PKPString::convertStrftimeFormat($oldOrNewFormat);
Use the format with a timestamp to convert a date into the format desired by the journal, press or preprint.
echo date($format, $timestamp);
Repositories were introduced to replace the entity Service
class pattern that was introduced in 3.4. Repositories provided a better type-hinted interface to read and write data for many entities, such as submissions and authors. Learn more about Repositories.
When a Repository
class exists, plugin and theme developers should use the Repo
facade instead of the DAO
class to read and write data. Replace code like this:
$submissionDao = DAORegistry::getDAO('SubmissionDAO');
$submission = $submissionDao->getById($id, $contextId);
$submission->setData('locale', 'en_US');
$submissionDao->updateObject($submission);
With code like this:
use APP\facades\Repo;
$submission = Repo::submission()->get($id, $contextId);
Repo::submission()->edit(
$submission,
[
'locale' => 'en',
]
);
Direct access to the DAO
is discouraged. If you need to access the DAO
, it is available through the Repository
.
- $submissionDao = DAORegistry::getDAO('SubmissionDAO');
+ use APP\facades\Repo;
+
+ $submissionDao = Repo::submission()->dao;
Many of the service classes have been replaced by a repository. These often have the same or similar methods, but the function signatures may have changed. For example, the add()
, edit()
, and delete()
methods no longer return the object that was added.
- $submission = Services::get('submission')->add($submission, $request);
+ use APP\facades\Repo;
+
+ $submissionId = Repo::submission()->add($submission);
+ $submission = Repo::submission()->get($submissionId);
+
- $submission = Services::get('submission')->edit($submission, $params, $request);
+ Repo::submission()->edit($submission, $params);
+ $submission = Repo::submission()->get($submission->getId());
The following service classes have been replaced by a repository.
- Services::get('announcement');
+ Repo::announcement()
- Services::get('author');
+ Repo::author();
- Services::get('submission');
+ Repo::submission();
- Services::get('publication');
+ Repo::publication();
- Services::get('issue');
+ Repo::publication();
- Services::get('galley');
+ Repo::galley();
- Services::get('user');
+ Repo::user();
This is a more disruptive change than we typically like to make. Modernizing our patterns in this way has significantly improved the experience of working with the codebase and detecting errors early. We recommend using an editor with autocomplete to benefit from this.
The submissionProgress
property of a submission is now a string
. This property used to be an int
and was used to track the current step of the submission wizard for each submission. It now refers to the current step by one of the following: start
, details
, files
, contributors
, editors
, review
.
The title
, fullTitle
, and subtitle
properties of a Publication
may now include the following inline HTML tags <i>
, <b>
, <u>
, <sup>
, and <sub>
. To get the HTML version of the title, pass html
to the second argument of several publication methods.
$title = $publication->getLocalizedFullTitle(null, 'html');
$title = $publication->getLocalizedTitle(null, 'html');
$subtitle = $publication->getLocalizedSubTitle(null, 'html');
Laravel’s Jobs have been adopted to implement a jobs queue for long-running tasks. Plugin developers who want to use this feature should read how to create and dispatch jobs.
Laravel’s Events have been adopted to implement the observer pattern. Learn more about how to use events and listeners. Plugin developers can see an example listener.
The Usage Stats plugin has been removed and statistics are now part of the core application. It has been rewritten from the ground up to support COUNTER R5, protect user privacy when compiling geographic stats, and support institutional stats by IP range. Many stats are now available through the REST API in JSON or CSV format.
System administrators may want to read about how to configure and download statistics. Plugin developers and contributors may want to review the new documentation on how statistics are logged and compiled.
Editorial decisions have been refactored. If you have a plugin or theme which records an editorial decision or modifies the UI for recording an editorial decision, read the documentation about decisions.
The submission wizard has been rebuilt to use the REST API and the form components. Plugins that modify the submission wizard should use one of the following methods:
TemplateManager::display
, Template::SubmissionWizard::Section
, and Template::SubmissionWizard::Section::Review
hooks to add new forms or other components to a step in the submission wizard. An example can be found in the funding plugin.The submissionProgress
property has been changed from an integer to a string. View the REST API documentation for the new specification.
Several new endpoints were added to the REST API for working with statistics, editorial decisions, contributors and submissions. See what’s changed in the 3.4 API Reference.
New components were added to the UI Library, such as Dialog, Composer, FileAttacher, Steps, and more. View everything in the UI Library.
The following hooks were removed. In most cases, these hooks were removed because code was refactored in a way that made the hooks obsolete.
The Mail::send
hook was removed as part of a major update to how emails are sent. To intervene when an email is sent, add a listener to the MessageSendingFromContext
and MessageSendingFromSite
events. Learn more about the new email system.
The EditorAction::modifyDecisionOptions
hook was removed as part of a major refactor of Decisions. Use the following to change the decision options available to an editor.
use PKP\plugins\Hook;
Hook::add('Workflow::Decisions', function(string $hookName, array $args) {
$decisionTypes = $args[0];
$stageId = $args[1]; // eg - WORKFLOW_STAGE_ID_*
// ...
});
The EditorAction::recordDecision
hook was removed as part of a major refactor of Decisions. Add a listener to the DecisionAdded
event to perform some action when a decision is recorded.
Several hooks which let you append data to API results have been removed. Replace these by extending the entity’s map.
- Announcement::getProperties
- Author::getProperties::values
- EmailTemplate::getProperties
- Galley::getProperties::values
- Issue::getProperties::fullProperties
- Issue::getProperties::summaryProperties
- Issue::getProperties::values
- Publication::getProperties
- Section::getProperties::fullProperties
- Section::getProperties::summaryProperties
- Section::getProperties::values
- Submission::getProperties::values
- SubmissionFile::getProperties
- User::getProperties::fullProperties
- User::getProperties::reviewerSummaryProperties
- User::getProperties::summaryProperties
- User::getProperties::values
Several hooks which let you customize the database queries for entities have been removed. They have been replaced with the Collector
classes. Use the *::Collector
hook to modify the query. For example, code which registered functions on Author::getMany::queryBuilder
and Author::getMany::queryObject
should be adapted to the hook Author::Collector
.
The following hooks were removed.
- Announcement::getMany::queryBuilder
- Announcement::getMany::queryObject
- Author::getMany::queryBuilder
- Author::getMany::queryObject
- EmailTemplate::getMany::queryBuilder
- EmailTemplate::getMany::queryObject::custom
- EmailTemplate::getMany::queryObject::default
- Galley::getMany::queryBuilder
- Issue::getMany::queryBuilder
- Publication::getMany::queryBuilder
- Publication::getMany::queryObject
- Stats::getOrderedObjects::queryBuilder
- Stats::getRecords::queryBuilder
- Stats::queryBuilder
- Stats::queryObject
- Submission::getMany::queryBuilder
- Submission::getMany::queryObject
- SubmissionFile::getMany::queryBuilder
- SubmissionFile::getMany::queryObject
- User::getMany::queryBuilder
- User::getMany::queryObject
- User::getReviewers::queryBuilder
Several hooks in the code that turns database results into a DataObject
have been removed. Extend the properties of a DataObject
by extending its entity schema.
- CategoryDAO::_fromRow
- IssueDAO::_fromRow
- IssueDAO::_returnIssueFromRow
- SectionDAO::_fromRow
- UserDAO::_returnUserFromRow
- UserDAO::_returnUserFromRowWithData
- UserDAO::_returnUserFromRowWithReviewerStats
- UserGroupDAO::_returnFromRow
The following hook was removed because the ReviewerSubmissionDAO
object was removed.
- ReviewerSubmissionDAO::_fromRow
Several hooks in the stats API have been removed as part of major changes to the stats system.
- API::stats::publication::abstract::params
- API::stats::publication::galley::params
- API::stats::publications::abstract::params
- API::stats::publications::galley::params
The hook PKPLocale::installLocale
was replaced with Locale::installLocale
. The following hooks were removed.
- PKPLocale::installLocale
- PKPLocale::registerLocaleFile
- PKPLocale::registerLocaleFile::isValidLocaleFile
- PKPLocale::translate
Some hooks have been removed because the related code was removed.
- API::submissions::files::params
- ArticleGalleyDAO::getLocalizedGalleysByArticle
- PluginGridHandler::plugin
- PluginGridHandler::plugin
- SubmissionFile::assignedFileStages
- SubmissionHandler::saveSubmit
As part of our efforts to modernize the code, several functions were removed, deprecated or replaced.
Get galley file ids from the new Galley
object.
- ArticleGalley::getFileId();
- ArticleGalley::setFileId();
- PreprintGalley::getFileId();
- PreprintGalley::setFileId();
+ PKP\galley\Galley::getData('submissionFileId');
Don’t use these methods to work with submission cover images. Get the cover image info from the Publication
object instead.
- Submission::getCoverImage();
- Submission::getLocalizedCoverImage();
- Submission::getCoverImageAltText();
- Submission::getLocalizedCoverImageAltText();
- Submission::getLocalizedCoverImageUrl();
+ APP\publication\Publication::getLocalizedData('coverImage');
+ APP\publication\Publication::getLocalizedCoverImageUrl($contextId);
Several deprecated Submission
methods have been removed. Use Publication
methods instead.
- Submission::getAuthorString()
- Submission::getShortAuthorString()
- Submission::getPrimaryAuthor()
+ APP\publication\Publication::getAuthorString($userGroups)
+ APP\publication\Publication::getShortAuthorString()
+ APP\publication\Publication::getPrimaryAuthor()
For theme templates, this will require a change like this:
- {$article->getAuthorString()|escape}
+ {$article->getCurrentPublication()->getAuthorString($authorUserGroups)|escape}
Use getSignature()
to get a user’s contact signature:
- User::getContactSignature()
+ PKP\user\User::getSignature(Locale::getLocale())
Use Repo::section()
to get section data:
- DAORegistry('UserGroupDAO')->...;
+ Repo::section()->...
Use DB
facade instead of Capsule
to access Laravel’s QueryBuilder:
- use Illuminate\Database\Capsule\Manager as Capsule;
- Capsule::table('submissions')->...
+ use Illuminate\Support\Facades\DB;
+ DB::table('submissions')->...
The Mail
and SubmissionMail
classes were removed in favor of Mailables
. Read Utilities > Email to learn more.
Deprecated shims for Smarty2 functions within PKPTemplateManager
, including get_template_vars()
and register_function()
were removed. Legacy usage should move to Smarty3-compatible functions PKPTemplateManager::getTemplateVars()
and PKPTemplateManager::registerPlugin()
.