[OJS 3.1.2] How to add a search engine on the Archives page

Hello, I am using OJS 3.1.2 and I would like a search engine on the Archives page to allow me to search for a specific issue, perhaps by volume and year as well. I already modified the issueArchive.tpl file to be able to enter the search data but I don’t know where to implement or modify it to perform the search I am talking about. I would like it to work just like the advanced search that OJS has. Could someone guide me?

@ctgraham could you please help me one more time … i really need to search for issues…

Someone help me?

Are you familiar with PHP coding? If so, we can point you at the files where the added code would be needed. Note that this will be custom coding on your part; there won’t be an easy copy-paste solution.

Yes @ctgraham , I’m familiar with PHP, I know it would be something I would have to do from scratch. Please indicate the files I need to modify

For OJS to respond to a PHP-based request, you’ll need a handler which matches the URL endpoint. For example, the way that the “/issue/archive” URL works is:

Under pages/issue,

directs the flow to:

In IssueHandler.inc.php there is a function archive:

The $args parameter represents arguments on the URL, for example, pagination is handled here:

This allows a URL like “/issue/archive/3” to set $pages to “3” in the code.

The code fetches issues:

And then renders them via the issueArchive.tpl.

I imagine you could perform similar logic in a new search() function, taking a $param with your search string and limiting the issue retrieval to only those matching the user’s criteria.

If you want something explicitly modeled after the search handler, you can find the code here:

specific to an article-based search, of course.

Hi @ctgraham , thanks for your help and sorry for the delay but I was on vacation. After my return I have been working and I think I have achieved it although I have my doubts. I explain what I did to tell me what you think:
1- First, I created an issueArchive.tpl file inside the theme folder that I am using, so as not to touch the original that the system brings. In this file I included a form for filtering (similar to the search page) where the user can enter volume, number or year of the issue to be searched. I also added the variables where the values entered by the user for volume, number and year will be stored

2- Then in issueHandler.inc.php I did not implement a new function but I modified the archive function, so that if a filter was introduced it would search according to this and if not (by default) it would show all the issues published.
The modification consisted of:

  • before calling ServicesContainer, on line 127 add this code, in which I obtain the values entered by the user:
    $volume = $request->getUserVar(‘volume’)!= ‘’ ? (int) $request->getUserVar(‘volume’) : null;
    $number = $request->getUserVar(‘number’)!= ‘’ ? (int) $request->getUserVar(‘number’) : null;
    $year = $request->getUserVar(‘year’)!= ‘’ ? (int) $request->getUserVar(‘year’) : null;

  • then I added them to the params array

$params = array(
‘orderBy’ => ‘seq’,
‘orderDirection’ => ‘ASC’,
‘count’ => $count,
‘offset’ => $offset,
‘isPublished’ => true,
‘volumes’=> $volume, //new
‘numbers’=> $number, //new
‘years’=> $year, //new
);

  • and finally I pass them back to the template:

$templateMgr->assign(array(
‘issues’ => $issues,
‘showingStart’ => $showingStart,
‘showingEnd’ => $showingEnd,
‘total’ => $total,
‘nextPage’ => $nextPage,
‘prevPage’ => $prevPage,
‘volume’ => $volume, //new
‘number’ => $number, //new
‘year’ => $year //new
));

At the end, the function archive remained:

/**
	 * Display the issue archive listings
	 * @param $args array
	 * @param $request PKPRequest
	 */
	function archive($args, $request) {
		$this->setupTemplate($request);
		
		$page = isset($args[0]) ? (int) $args[0] : 1;
		$templateMgr = TemplateManager::getManager($request);
		$context = $request->getContext();

		$count = $context->getSetting('itemsPerPage') ? $context->getSetting('itemsPerPage') : Config::getVar('interface', 'items_per_page');
		$offset = $page > 1 ? ($page - 1) * $count : 0;		
		 //new
		$volume = $request->getUserVar('volume')!= '' ? (int) $request->getUserVar('volume') : null;
		$number = $request->getUserVar('number')!= '' ? (int) $request->getUserVar('number') : null;
		$year = $request->getUserVar('year')!= '' ? (int) $request->getUserVar('year') : null;
		
		import('classes.core.ServicesContainer');
		$issueService = ServicesContainer::instance()->get('issue');
		$params = array(
			'orderBy' => 'seq',
			'orderDirection' => 'ASC',
			'count' => $count,
			'offset' => $offset,
			'isPublished' => true,
			'volumes'=> $volume, //new
			'numbers'=> $number, //new
			'years'=> $year, //new
		);
		
		$issues = $issueService->getIssues($context->getId(), $params);
		$total = $issueService->getIssuesMaxCount($context->getId(), $params);

		$showingStart = $offset + 1;
		$showingEnd = min($offset + $count, $offset + count($issues));
		$nextPage = $total > $showingEnd ? $page + 1 : null;
		$prevPage = $showingStart > 1 ? $page - 1 : null;

		$templateMgr->assign(array(
			'issues' => $issues,
			'showingStart' => $showingStart,
			'showingEnd' => $showingEnd,
			'total' => $total,
			'nextPage' => $nextPage,
			'prevPage' => $prevPage,
			'volume' => $volume, //new
			'number' => $number ,//new
			'year' => $year, //new
		));
		
		$templateMgr->display('frontend/pages/issueArchive.tpl');
	}

3- Then, in the template on the page I pass the variables of volume, number and year:

{if $prevPage > 1}
		{capture assign=prevUrl}{url router=$smarty.const.ROUTE_PAGE page="issue" op="archive" path=$prevPage volume=$volume number=$number year=$year}{/capture}
		{elseif $prevPage === 1}
			{capture assign=prevUrl}{url router=$smarty.const.ROUTE_PAGE page="issue" op="archive" volume=$volume number=$number year=$year}{/capture}
		{/if}
		{if $nextPage}
			{capture assign=nextUrl}{url router=$smarty.const.ROUTE_PAGE page="issue" op="archive" path=$nextPage volume=$volume number=$number year=$year}{/capture}
		{/if}

but this produces for example the following result:

http: //.../issue/archive/2?volume=14&number=2&year=2016

The question I have is how to make this part not appear like this in the URL:
?volume=14&number=2&year=2016

but it will be shown, for example, as the page number, only the value, not the name of the variable and the value, more or less like this:
http: //…/issue/archive/2/14/2/2016

The use of the querystring here is probably your best option. You could change this to pass these as URL arguments instead of querystring parameters, but how would you represent a search with only two of the three filters? With a querystring, you can make each element optional.

If you did want to convert these to URL arguments, you would need have the form in issueArchive.tpl reconstruct the query in that format; then you could have the archve() function read these out of the $args[] variable. This line reads the first of the arguments as the page:

$page = isset($args[0]) ? (int) $args[0] : 1;

Additional elements of this array would represent subsequent URL components. E.g. for /issue/archive/2/14/2/2016:

$volume = $args[1]

would set $volume to “14”.

Dear @ctgraham, dear @yusmelvis

would it be possible to filter the archive page by passing certain issue_ids via URL-parameter? As far as I can see and without any modification, at the moment, this only works with pages.
I’d like to build archive-like lists of issues according to arrays of certain issue_ids. So, listing specific but unsystematic issues, a thematic collection of issues.

I am familiar with php. Using OJS 3.1.2-4 (preparing to upgrade to 3.2)

Thanks and all the best
Klaus

PS.: This is like the new feature of “categories” but with issues…

Unless you can format your issue grouping within the existing filters of Volumes, Numbers, and Years, you’ll need to add a new parameter for processing within IssueService::getQueryBuilder:

and a new method for processing the parameter in the IssueQueryBuilder:

Beyond that, you can use the advice described above to read and process the querystring.

Note, though, that anyone can construct an arbitrary querystring. It would be better, if possible, to represent this categorization in metadata rather than on the URI.

See: GitHub - ajnyga/themeIssues

Thanks so much @ctgraham. I’ll try the plugin first as this seems pretty much what I was looking for.

Dear @ctgraham, dear @ajnyga

I’m preparing to upgrade to OJS 3.2.1.2 and realised that

$issueService = ServicesContainer::instance()->get('issue');

doesn’t work any more. Could you please have a look at themeIssues/ThemeIssuesHandler.inc.php at master · ajnyga/themeIssues · GitHub to help me upgrading?

Thank you very much and all the best
Klaus

Got it! See pull request: