Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/v1/submissions/SubmissionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ protected function getCatalogEntryForm(Request $illuminateRequest): JsonResponse
$publicFileManager = new PublicFileManager();
$baseUrl = $request->getBaseUrl() . '/' . $publicFileManager->getContextFilesPath($context->getId());

$catalogEntryForm = new CatalogEntryForm($publicationApiUrl, $locales, $publication, $submission, $baseUrl, $temporaryFileApiUrl);
$catalogEntryForm = new CatalogEntryForm($publicationApiUrl, $locales, $publication, $submission, $baseUrl, $temporaryFileApiUrl, $context);
$submissionLocale = $submission->getData('locale');

return response()->json($this->getLocalizedForm($catalogEntryForm, $submissionLocale, $locales), Response::HTTP_OK);
Expand Down
42 changes: 41 additions & 1 deletion classes/components/forms/publication/CatalogEntryForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
namespace APP\components\forms\publication;

use APP\facades\Repo;
use APP\press\Press;
use APP\publication\Publication;
use APP\submission\Submission;
use PKP\components\forms\FieldAutosuggestPreset;
use PKP\components\forms\FieldHTML;
use PKP\components\forms\FieldRichTextarea;
use PKP\components\forms\FieldSelect;
use PKP\components\forms\FieldText;
Expand All @@ -37,6 +39,7 @@ class CatalogEntryForm extends FormComponent
public const GROUP_VERSION_AND_UPDATES = 'versionAndUpdates';
public const GROUP_DISPLAY = 'display';
public const GROUP_ACCESS = 'access';
public const GROUP_PRESS_IDENTITY = 'pressIdentity';

public $id = self::FORM_CATALOG_ENTRY;
public $method = 'PUT';
Expand All @@ -53,8 +56,9 @@ class CatalogEntryForm extends FormComponent
* @param Submission $submission The submission of this publication
* @param string $baseUrl Site's base URL. Used for image previews.
* @param string $temporaryFileApiUrl The url to upload the cover image
* @param Press $press The press this publication belongs to
*/
public function __construct($action, $locales, $publication, $submission, $baseUrl, $temporaryFileApiUrl)
public function __construct($action, $locales, $publication, $submission, $baseUrl, $temporaryFileApiUrl, ?Press $press = null)
{
$this->action = $action;
$this->successMessage = __('publication.catalogEntry.success');
Expand Down Expand Up @@ -172,5 +176,41 @@ public function __construct($action, $locales, $publication, $submission, $baseU
'description' => __('publication.urlPath.description'),
'value' => $publication->getData('urlPath'),
]));

if ($press) {
$this->addStampedIdentityField($publication, $press);
}
}

protected function addStampedIdentityField(Publication $publication, Press $press): void
{
$parts = [];

if ($publication->getData('contextName')) {
$parts[] = '<li><strong>' . htmlspecialchars(__('manager.setup.contextTitle')) . ':</strong> '
. htmlspecialchars($publication->getPrimaryContextName($press)) . '</li>';
}
if ($publisher = $publication->getData('publisher')) {
$parts[] = '<li><strong>' . htmlspecialchars(__('manager.setup.publisher')) . ':</strong> '
. htmlspecialchars($publisher) . '</li>';
}
if ($publisherLocation = $publication->getData('publisherLocation')) {
$parts[] = '<li><strong>' . htmlspecialchars(__('manager.setup.publisherLocation')) . ':</strong> '
. htmlspecialchars($publisherLocation) . '</li>';
}

if (empty($parts)) {
return;
}

$this->addGroup(
['id' => self::GROUP_PRESS_IDENTITY, 'label' => __('publication.pressIdentity')]
);
$this->addField(new FieldHTML('pressIdentity', [
'groupId' => self::GROUP_PRESS_IDENTITY,
'label' => __('publication.pressIdentity'),
'description' => __('publication.pressIdentity.description')
. '<ul>' . implode('', $parts) . '</ul>',
]));
}
}
41 changes: 41 additions & 0 deletions classes/migration/upgrade/v3_6_0/I7527_IdentityMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/**
* @file classes/migration/upgrade/v3_6_0/I7527_IdentityMetadata.php
*
* Copyright (c) 2026 Simon Fraser University
* Copyright (c) 2026 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class I7527_IdentityMetadata
*
* @brief Add the press-specific identity (publisher, publisher location, publisher code) to the
* stamped publication metadata.
*/

namespace APP\migration\upgrade\v3_6_0;

use Illuminate\Support\Facades\DB;

class I7527_IdentityMetadata extends \PKP\migration\upgrade\v3_6_0\I7527_IdentityMetadata
{
protected function getIdentitySettings(string $settingsTable, string $idColumn, int $contextId): array
{
$settings = parent::getIdentitySettings($settingsTable, $idColumn, $contextId);

// publisher, codeType, codeValue share their name between press settings and publication fields.
// location is the press setting name; it is stamped as 'publisherLocation'.
$rename = ['location' => 'publisherLocation'];
$rows = DB::table($settingsTable)
->where($idColumn, $contextId)
->whereIn('setting_name', ['publisher', 'codeType', 'codeValue', 'location'])
->where('setting_value', '!=', '')
->pluck('setting_value', 'setting_name');

foreach ($rows as $name => $value) {
$settings[$rename[$name] ?? $name] = $value;
}

return $settings;
}
}
47 changes: 47 additions & 0 deletions classes/publication/HasContextIdentityMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

/**
* @file classes/publication/HasContextIdentityMetadata.php
*
* Copyright (c) 2026 Simon Fraser University
* Copyright (c) 2026 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @trait HasContextIdentityMetadata
*
* @brief Press-specific extension of the generic identity resolver: adds publisher,
* publisher code, and code value getters on top of the shared name getters.
*/

namespace APP\publication;

use PKP\context\Context;

trait HasContextIdentityMetadata
{
use \PKP\publication\HasContextIdentityMetadata;

/**
* Get the stamped publisher name, falling back to the live context value.
*/
public function getPublisher(Context $context): ?string
{
return $this->getData('publisher') ?: $context->getData('publisher');
}

/**
* Get the stamped publisher code type, falling back to the live context value.
*/
public function getCodeType(Context $context): ?string
{
return $this->getData('codeType') ?: $context->getData('codeType');
}

/**
* Get the stamped publisher code value, falling back to the live context value.
*/
public function getCodeValue(Context $context): ?string
{
return $this->getData('codeValue') ?: $context->getData('codeValue');
}
}
24 changes: 24 additions & 0 deletions classes/publication/Publication.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
use APP\facades\Repo;
use APP\file\PublicFileManager;
use APP\publication\enums\VersionStage;
use PKP\context\Context;
use PKP\publication\PKPPublication;

class Publication extends PKPPublication
{
use HasContextIdentityMetadata;

public const DEFAULT_VERSION_STAGE = VersionStage::VERSION_OF_RECORD;

/**
Expand Down Expand Up @@ -111,4 +114,25 @@ public function getLocalizedCoverImageThumbnailUrl(int $contextId)
Repo::publication()->getThumbnailFilename($pathParts['basename']),
]);
}

/**
* Stamp press identity onto the publication.
*/
public function stampContextIdentity(?Context $context = null): void
{
$context ??= $this->getStampingContext();
parent::stampContextIdentity($context);
$this->setData('publisher', $context->getData('publisher'));
$this->setData('publisherLocation', $context->getData('location'));
$this->setData('codeType', $context->getData('codeType'));
$this->setData('codeValue', $context->getData('codeValue'));
}

public function clearIdentityMetadata(): void
{
parent::clearIdentityMetadata();
$this->setData('publisher', null);
$this->setData('codeType', null);
$this->setData('codeValue', null);
}
}
1 change: 1 addition & 0 deletions dbscripts/xml/upgrade.xml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
<migration class="PKP\migration\upgrade\v3_6_0\I12772_UserCommentForeignKeys" />
<migration class="PKP\migration\upgrade\v3_6_0\I12584_AddPublicationUpdateType" />
<migration class="PKP\migration\upgrade\v3_6_0\I12800_ReviewPublicationAssociationNullable" />
<migration class="APP\migration\upgrade\v3_6_0\I7527_IdentityMetadata" />
<code function="rebuildSearchIndex" />
<note file="docs/release-notes/README-3.6.0" />
</upgrade>
Expand Down
3 changes: 3 additions & 0 deletions locale/en/manager.po
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,9 @@ msgstr "Publisher"
msgid "manager.setup.publisherDescription"
msgstr "The name of the organization publishing the press will appear in About the Press."

msgid "manager.setup.publisherLocation"
msgstr "Publisher Location"

msgid "manager.setup.referenceLinking"
msgstr "Reference Linking"

Expand Down
6 changes: 6 additions & 0 deletions locale/en/submission.po
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,12 @@ msgstr "Catalog Entry"
msgid "publication.catalogEntry.success"
msgstr "The catalog entry details have been updated."

msgid "publication.pressIdentity"
msgstr "Press Identity"

msgid "publication.pressIdentity.description"
msgstr "This metadata was recorded when the publication was published and will not change if the press updates its identity settings."

msgid "publication.invalidSeries"
msgstr "The series for this publication could not be found."

Expand Down
2 changes: 1 addition & 1 deletion pages/workflow/WorkflowHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function setupIndex($request)
$baseUrl = $request->getBaseUrl() . '/' . $publicFileManager->getContextFilesPath($submissionContext->getId());

$audienceForm = new \APP\components\forms\submission\AudienceForm($submissionApiUrl, $submission);
$catalogEntryForm = new \APP\components\forms\publication\CatalogEntryForm($latestPublicationApiUrl, $locales, $latestPublication, $submission, $baseUrl, $temporaryFileApiUrl);
$catalogEntryForm = new \APP\components\forms\publication\CatalogEntryForm($latestPublicationApiUrl, $locales, $latestPublication, $submission, $baseUrl, $temporaryFileApiUrl, $submissionContext);
$publicationDatesForm = new \APP\components\forms\submission\PublicationDatesForm($submissionApiUrl, $submission);

$publicationLicenseForm = new \APP\components\forms\publication\PublicationLicenseForm($latestPublicationApiUrl, $locales, $latestPublication, $submissionContext);
Expand Down
2 changes: 1 addition & 1 deletion plugins/generic/googleScholar/GoogleScholarPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public function monographView($hookName, $args)
}

// Publisher
$templateMgr->addHeader('googleScholarPublisher', '<meta name="citation_publisher" content="' . htmlspecialchars($press->getName($press->getPrimaryLocale())) . '"/>');
$templateMgr->addHeader('googleScholarPublisher', '<meta name="citation_publisher" content="' . htmlspecialchars($publication->getPrimaryContextName($press)) . '"/>');

// Series ISSN (online)
if ($series && $issn = $series->getOnlineISSN()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ public function handleChildElement($n, $publication)
$nativeFilterHelper->parsePublicationCovers($this, $n, $publication),
],
'series' => $this->parseSeries($this, $n, $publication),
'publisher' => $publication->setData('publisher', $n->textContent),
'codeType' => $publication->setData('codeType', $n->textContent),
'codeValue' => $publication->setData('codeValue', $n->textContent),
default => parent::handleChildElement($n, $publication)
};
}
Expand Down
10 changes: 10 additions & 0 deletions plugins/importexport/native/filter/PublicationNativeXmlFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ public function createEntityNode($doc, $entity)
$this->addChapters($doc, $entityNode, $entity);
}

if ($publisher = $entity->getData('publisher')) {
$entityNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'publisher', htmlspecialchars($publisher, ENT_COMPAT, 'UTF-8')));
}
if ($codeType = $entity->getData('codeType')) {
$entityNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'codeType', htmlspecialchars($codeType, ENT_COMPAT, 'UTF-8')));
}
if ($codeValue = $entity->getData('codeValue')) {
$entityNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'codeValue', htmlspecialchars($codeValue, ENT_COMPAT, 'UTF-8')));
}

// cover images
$nativeFilterHelper = new PKPNativeFilterHelper();
$coversNode = $nativeFilterHelper->createPublicationCoversNode($this, $doc, $entity);
Expand Down
4 changes: 4 additions & 0 deletions plugins/importexport/native/native.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@
<element ref="pkp:series" maxOccurs="1" minOccurs="0" />
<element ref="pkp:chapters" maxOccurs="1" minOccurs="0" />
<element ref="pkp:covers" minOccurs="0" maxOccurs="1" />
<!-- Stamped identity fields specific to OMP -->
<element name="publisher" type="string" minOccurs="0" maxOccurs="1" />
<element name="codeType" type="string" minOccurs="0" maxOccurs="1" />
<element name="codeValue" type="string" minOccurs="0" maxOccurs="1" />
</sequence>
<attribute name="series" type="normalizedString" />
<attribute name="series_position" type="normalizedString" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ public function createProductNode(DOMDocument $doc, Submission $submission, Publ
$publishingDetailNode->appendChild($publisherNode);

$publisherNode->appendChild($this->buildTextNode($doc, 'PublishingRole', '01')); // Publisher
$publisherNode->appendChild($this->buildTextNode($doc, 'PublisherName', $context->getData('publisher')));
$publisherNode->appendChild($this->buildTextNode($doc, 'PublisherName', $publication->getPublisher($context)));

$websiteNode = $doc->createElementNS($deployment->getNamespace(), 'Website');
$publisherNode->appendChild($websiteNode);
Expand Down Expand Up @@ -612,8 +612,8 @@ public function createProductNode(DOMDocument $doc, Submission $submission, Publ
}
}

if ($context->getData('location') != '') {
$publishingDetailNode->appendChild($this->buildTextNode($doc, 'CityOfPublication', $context->getData('location')));
if ($publisherLocation = $publication->getData('publisherLocation') ?: $context->getData('location')) {
$publishingDetailNode->appendChild($this->buildTextNode($doc, 'CityOfPublication', $publisherLocation));
}

/* --- Publishing Dates --- */
Expand Down Expand Up @@ -838,7 +838,7 @@ public function createProductNode(DOMDocument $doc, Submission $submission, Publ
$supplierWebsiteNode->appendChild($this->buildTextNode($doc, 'WebsiteLink', $request->url($context->getPath(), 'catalog', 'book', [$submissionBestId])));
} else { // No suppliers specified, use the Press settings instead.
$supplierNode->appendChild($this->buildTextNode($doc, 'SupplierRole', '09')); // Publisher supplying to end customers
$supplierNode->appendChild($this->buildTextNode($doc, 'SupplierName', $context->getData('publisher')));
$supplierNode->appendChild($this->buildTextNode($doc, 'SupplierName', $publication->getPublisher($context)));

if ($context->getData('contactEmail') != '') {
$supplierNode->appendChild($this->buildTextNode($doc, 'EmailAddress', $context->getData('contactEmail')));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ public function extractMetadataFromDataObject(&$publicationFormat)
$this->_addLocalizedElements($dc11Description, 'dc:description', $publication->getData('abstract'));

// Publisher
$publisher = $press->getSetting('publisher');
$publisher = $publication->getPublisher($press);
if (!empty($publisher)) {
$publishers = [$press->getPrimaryLocale() => $publisher];
} else {
$publishers = $press->getName(null); // Default
$publishers = $publication->getData('contextName', null) ?: $press->getName(null); // Default
}
$this->_addLocalizedElements($dc11Description, 'dc:publisher', $publishers);

Expand Down Expand Up @@ -195,7 +195,7 @@ public function extractMetadataFromDataObject(&$publicationFormat)
}

// Source (press title and pages)
$sources = $press->getName(null);
$sources = $publication->getData('contextName') ?: $press->getName(null);
$pages = $publication->getData('pages');
if (!empty($pages)) {
$pages = '; ' . $pages;
Expand Down
Loading
Loading