<?php
/*
 * Copyright (c) 2026, Tribal Limited
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Zenario, Tribal Limited nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL TRIBAL LTD BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
if (!defined('NOT_ACCESSED_DIRECTLY')) exit('This file may not be directly accessed');


class zenario_common_features__admin_boxes__publish extends ze\moduleBaseClass {

	public function fillAdminBox($path, $settingGroup, &$box, &$fields, &$values) {
		
		$tags = ze\ray::explodeAndTrim($box['key']['id']);
		
		if ($box['key']['cID']) {
			$tagsCount = 1;
			$box['key']['id'] = $box['key']['cType']. '_'. $box['key']['cID'];
		} else {
			$tagsCount = count($tags);
			if ($tagsCount == 1) {
				ze\content::getCIDAndCTypeFromTagId($box['key']['cID'], $box['key']['cType'], $tags[0]);
			
			} else {
				$fields['publish/publish_options__unlisted']['label'] = ze\admin::phrase('Publish as unlisted content items');
			}
		}
		
		if ($tagsCount == 1) {
			$box['tabs']['publish']['notices']['are_you_sure']['message'] = 
				ze\admin::phrase('Publish the content item "[[tag]]"?', ['tag' => ze\content::formatTag($box['key']['cID'], $box['key']['cType'])]);
		} else {
			$box['tabs']['publish']['notices']['are_you_sure']['message'] = 
				ze\admin::phrase('Publish the [[count]] selected content items?', ['count' => $tagsCount]);
		}
		
		//Look for any access codes in use
		ze\contentAdm::checkForAccessCodes($box, $fields['publish/access_codes_warning'], $tags, $tagsCount,
			'This content item has an access code ([[access_code]]). This will be removed when it is published.',
			'One content item has an access code ([[access_code]]). This will be removed when it is published.',
			'[[count]] content items have an access code. These will be removed when it is published.'
		);
		
		// Scheduled publishing options
		$scheduledTaskManagerInc = ze\module::inc('zenario_scheduled_task_manager');
		if ($scheduledTaskManagerInc) {
			
			$fields['publish/publish_options__immediately']['label'] = ze\admin::phrase('Publish immediately');

			$allJobsEnabled = ze::setting('site_enabled') && ze::setting('jobs_enabled');
			$scheduledPublishingEnabled = ze\row::get('jobs', 'enabled', ['job_name' => 'jobPublishContent', 'module_class_name' => 'zenario_common_features']);
			if (!($allJobsEnabled && $scheduledPublishingEnabled)) {
				$scheduledTaskHref = ze\link::absolute() . 'organizer.php#zenario__administration/panels/zenario_scheduled_task_manager__scheduled_tasks';
				$linkStart = '<a href="' . htmlspecialchars($scheduledTaskHref) . '" target="_blank">';
				$linkEnd = "</a>";

				$string = "Scheduled publishing is not available. The Scheduled Task Manager is installed but the scheduled publishing task (jobPublishContent) is not enabled. [[link_start]]Click for more info.[[link_end]]";

				$fields['publish/publish_options__schedule']['disabled'] = true;
				$fields['publish/publish_options__schedule']['note_below'] = ze\admin::phrase($string, ['link_start' => $linkStart, 'link_end' => $linkEnd]);
			} else {
				$values['publish/publish_date'] = date('Y-m-d');
			}
		
		} else {
			$fields['publish/publish_options__schedule']['disabled'] = true;
			
			$values['publish/publish_date'] = date('Y-m-d');
			
			$scheduledTaskManagerModuleId = ze\module::id('zenario_scheduled_task_manager');
			$scheduledTaskHref = ze\link::absolute() . 'organizer.php#zenario__library/panels/modules//' . (int) $scheduledTaskManagerModuleId . '~-scheduled_task_manager';
			
			$linkStart = '<a href="' . htmlspecialchars($scheduledTaskHref) . '" target="_blank">';
			$linkEnd = "</a>";

			$string = "Scheduled publishing is not available. To enable it, please install the Scheduled Task Manager module. [[link_start]]See available modules.[[link_end]]";

			$fields['publish/publish_options__schedule']['disabled'] = true;
			$fields['publish/publish_options__schedule']['note_below'] = ze\admin::phrase($string, ['link_start' => $linkStart, 'link_end' => $linkEnd]);
		}
		
		//Display info about the content item
		if ($tagsCount == 1) {
			$version = ze\content::version($box['key']['cID'], $box['key']['cType']);
			$featuredImageId = ze\content::featureImageId($box['key']['cID'], $box['key']['cType'], $version);
			if ($featuredImageId) {
				$altTag = ze\row::get('files', 'alt_tag', $featuredImageId);
				$featuredImageHTML = ze\content::featureImageHTML(
					$box['key']['cID'], $box['key']['cType'], $version, $useFallbackImage = false, $fallbackImageId = false,
					$maxWidth = 100, $maxHeight = 100, $canvas = 'fixed_width_and_height', $retina = false, $altTag
				);
				
				if ($featuredImageHTML) {
					$fields['publish/featured_image']['snippet']['html'] = $featuredImageHTML;
				}
			} else {
				$fields['publish/featured_image']['snippet']['html'] = '<span>' . ze\admin::phrase('No featured image') . '</span>';
				$fields['publish/featured_image']['row_class'] = 'no_featured_image';
			}
			
			ze\lang::applyMergeFields($fields['publish/full_site_url']['snippet']['html'], ['full_site_url' => ze\link::toItem($box['key']['cID'], $box['key']['cType'])]);
			
			$values['publish/title'] = ze\content::title($box['key']['cID'], $box['key']['cType'], $version);
			$contentItemClassIcon = ze\contentAdm::getItemIconClass($box['key']['cID'], $box['key']['cType']);
			$fields['publish/title']['row_class'] = 'organizer_item_image ' . $contentItemClassIcon;
			
			$langId = ze\content::langId($box['key']['cID'], $box['key']['cType']);
			
			$menuFromContentItem = ze\menu::getFromContentItem($box['key']['cID'], $box['key']['cType']);
			if ($menuFromContentItem) {
				$menuPath = ze\content::menuPath($box['key']['cID'], $box['key']['cType']);
				$values['publish/menu_node_path'] = $menuPath;
				
				
				$menuDetails = ze\menu::details($menuFromContentItem['mID'], $langId);
				$menuNodeClass = ze\menuAdm::cssClass($menuDetails);
				
				$fields['publish/menu_node_path']['row_class'] = 'organizer_item_image ' . $menuNodeClass;
			} else {
				$values['publish/menu_node_path'] = ze\admin::phrase('Not in menu');
				
				$fields['publish/menu_node_path']['row_class'] = 'organizer_item_image zenario_not_at_menu';
			}
			
			if (ze\row::get('content_types', 'enable_categories', ['content_type_id'=> $box['key']['cType']])) {
				$contentItemCategories = ze\category::contentItemCategories($box['key']['cID'], $box['key']['cType'], $publicOnly = false);
				
				if ($contentItemCategories) {
					$categoryNames = [];
					foreach ($contentItemCategories as $category) {
						$categoryNames[] = $category['name'];
					}
					$values['publish/categories'] = implode(', ', $categoryNames);
					
					$fields['publish/categories']['row_class'] = 'zenario_at_icon_categories_some';
				} else {
					$values['publish/categories'] = ze\admin::phrase('Not in any categories');
					
					$fields['publish/categories']['row_class'] = 'zenario_at_icon_categories_none';
				}
			} else {
				$fields['publish/categories']['hidden'] = true;
			}
			
			if (ze\module::isRunning('zenario_extranet')) {
				$fields['publish/permissions']['hidden'] = false;
				
				$equivId = ze\content::equivId($box['key']['cID'], $box['key']['cType']);
				$translationChain = ze\row::get('translation_chains', true, ['equiv_id' => $equivId, 'type' => $box['key']['cType']]);
				
				if ($translationChain) {
					$values['publish/permissions'] = ze\contentAdm::privacyDesc($translationChain);
					$fields['publish/permissions']['row_class'] = 'content_privacy ' . $translationChain['privacy'];
				}
			}
			
			if (ze\lang::count() > 1) {
				$fields['publish/language']['hidden'] = false;
				
				$values['publish/language'] = ze\lang::name($langId);
			}
		} else {
			$fields['publish/featured_image_grouping']['hidden'] = $fields['publish/content_item_details']['hidden'] = true;
		}
		
		
		//If we're not allowed to list or delist one of the selected content items (e.g. they're special pages),
		//disable those option.
		$canList = $canUnlist = true;
		foreach ($tags as $tagId) {
			ze\content::getCIDAndCTypeFromTagId($cID, $cType, $tagId);
			
			if ($canUnlist && !ze\contentAdm::allowPublishUnlisted($cID, $cType)) {
				$canUnlist = false;
				$fields['publish/publish_options__unlisted']['disabled'] = true;
				unset($box['tabs']['publish']['fields']['publish_options__unlisted']['value']);
				
				$fields['publish/publish_options__unlisted']['note_below'] =
					ze\admin::nPhrase("You can't make this special page unlisted.", "One of the selected content items is a special page that cannot be unlisted.", $tagsCount);
			}
			
			if ($canList && !ze\contentAdm::allowPublishListed($cID, $cType)) {
				$canList = false;
				$fields['publish/publish_options__schedule']['disabled'] =
				$fields['publish/publish_options__immediately']['disabled'] = true;
				
				unset($box['tabs']['publish']['fields']['publish_options__immediately']['value'], $box['tabs']['publish']['fields']['publish_options__schedule']['value']);
				
				$fields['publish/publish_options__schedule']['note_below'] =
				$fields['publish/publish_options__immediately']['note_below'] =
					ze\admin::nPhrase("You can't make this special page listed.", "One of the selected content items is a special page that cannot be listed.", $tagsCount);
			}
		}
		
		if (!$canList && !$canUnlist) {
			echo ze\admin::phrase("You have selected a mix of special pages, one of which cannot be listed, and one of which cannot be unlisted.");
			exit;
		}
		
		if ($canUnlist) {
			if (!$canList) {
				//Default to "unlisted" if that's the only option available.
				$values['publish/publish_options__unlisted'] = 1;
		
			} else {
				//Check if all of these content items are unlisted
				$sql = "
					SELECT 1
					FROM ". DB_PREFIX. "content_items AS c
					WHERE c.tag_id IN (". ze\escape::in($tags, 'asciiInSQL'). ")
					  AND c.status NOT IN ('unlisted', 'unlisted_with_draft')";
		
				if (!ze\sql::numRows($sql)) {
					//If so, select the default option to still be "unlisted"
					$this->setPublishOption($values, 'unlisted');
				}
			}
		}
		
		
		//Show a note if any of these items are scheduled to be published
		$sql = "
			SELECT c.id, c.type, v.scheduled_publish_datetime, c.lock_owner_id
			FROM ". DB_PREFIX. "content_items AS c
			INNER JOIN ". DB_PREFIX. "content_item_versions AS v
			   ON v.id = c.id
			  AND v.type = c.type
			  AND v.version = c.admin_version
			WHERE c.tag_id in (". ze\escape::in($tags, 'asciiInSQL'). ")
			  AND v.scheduled_publish_datetime IS NOT NULL";
		
		$result = ze\sql::select($sql);
		$count = ze\sql::numRows($result);
		$row = ze\sql::fetchAssoc($result);
		
		if ($count > 0) {
			$box['tabs']['publish']['notices']['scheduled_warning']['show'] = true;
			$box['save_button_message'] = ze\admin::phrase('Submit');
			
			if ($count > 1
			 || count($tags) > 1) {
				$box['tabs']['publish']['notices']['scheduled_warning']['message'] =
					ze\admin::phrase('These items are scheduled to be published on various times. Please check each one for details.');
			
			} else {
				$row['publication_time'] = 
					ze\admin::formatDateTime($row['scheduled_publish_datetime'], 'vis_date_format_med');
				
				if ($row['lock_owner_id']) {
					$adminDetails = ze\admin::details($row['lock_owner_id']);
					$row['first_name'] = $adminDetails['first_name'];
					$row['last_name'] = $adminDetails['last_name'];

					$scheduledWarningPhrase = "This item is scheduled by [[first_name]] [[last_name]] to be published on [[publication_time]].";
				} else {
					$scheduledWarningPhrase = "This item is scheduled to be published on [[publication_time]].";
				}

				$box['tabs']['publish']['notices']['scheduled_warning']['message'] = ze\admin::phrase($scheduledWarningPhrase, $row);
				
				$this->setPublishOption($values, 'schedule');
				
				$sdate = ze\date::new($row['scheduled_publish_datetime']);
				$values['publish/publish_hours'] = $sdate->format('G');
				$values['publish/publish_mins'] = $sdate->format('i');
				$values['publish/publish_date'] = $sdate->format('Y-m-d');
			}
		} else {
			$fields['publish/publish_options__cancel']['hidden'] = true;
			
			if ($scheduledTaskManagerInc && $allJobsEnabled && $scheduledPublishingEnabled) {
				//Set the default date to be +5 min in the future. Round up to the nearest 5 mins.
				//This will push the date +1 day forward if needed.
				$sdate = ze\date::new(ze\date::now());
				$sdate->modify('+5 minutes');
				$sdate->setTime($sdate->format('H'), ceil($sdate->format('i') / 5) * 5, 0);
				
				$values['publish/publish_hours'] = $sdate->format('G');
				$values['publish/publish_mins'] = $sdate->format('i');
				$values['publish/publish_date'] = $sdate->format('Y-m-d');
			}
		}
		
		//Settings for IndexNow
// 		if (ze::setting('enable_indexnow') && ze::setting('indexnow_api_key')) {
// 			if ($tagsCount == 1) {
// 				unset($box['tabs']['publish']['fields']['publish_multiple_indexnow_snippet']);
// 				$values['publish/notify_indexnow'] = true;
// 			} elseif ($tagsCount > 1) {
// 				unset($box['tabs']['publish']['fields']['notify_indexnow']);
// 			}
// 		} else {
// 			unset($box['tabs']['publish']['fields']['notify_indexnow'], $box['tabs']['publish']['fields']['publish_multiple_indexnow_snippet']);
// 		}
	}
	
	protected static function checkForClashingPublicationDates($tagIds, $date = false) {
		$sql = "
			SELECT DATE(v.release_date) AS release_date, c.id, c.type
			FROM ". DB_PREFIX. "content_items AS c
			INNER JOIN ". DB_PREFIX. "content_types AS ct
			   ON ct.content_type_id = c.type
			  AND ct.release_date_field != 'hidden'
			INNER JOIN ". DB_PREFIX. "content_item_versions AS v
			   ON v.id = c.id
			  AND v.type = c.type
			  AND v.version = c.admin_version
			WHERE c.tag_id IN (". ze\escape::in($tagIds, 'asciiInSQL'). ")
			  AND v.release_date IS NOT NULL
			  AND DATE(v.release_date) <> ";
		
		if ($date) {
			$sql .= "DATE('". ze\escape::sql($date). "')";
		} else {
			$sql .= "DATE(NOW())";
		}
		
		$sql .= "
			ORDER BY release_date DESC
			LIMIT 1";
		
		if (($result = ze\sql::select($sql)) && ($clash = ze\sql::fetchAssoc($result))) {
			
			$clash['tag'] = ze\content::formatTag($clash['id'], $clash['type']);
			$clash['date'] = ze\admin::formatDate($clash['release_date'], 'vis_date_format_med');
			return $clash;
		
		} else {
			return false;
		}
	}
	
	//In version 10.0 we rewrote code a bit, and turned the publish_options list
	//from a radios field to multiple radio fields.
	//These two functions are just to help convert old code.
	protected function getPublishOption(&$values) {
		foreach (['unlisted', 'immediately', 'schedule', 'cancel'] as $option) {
			if (!empty($values['publish/publish_options__'. $option])) {
				return $option;
			}
		}
		return '';
	}
	
	protected function setPublishOption(&$values, $option) {
		$values['publish/publish_options__unlisted'] =
		$values['publish/publish_options__immediately'] =
		$values['publish/publish_options__schedule'] =
		$values['publish/publish_options__cancel'] = '';
		
		$values['publish/publish_options__'. $option] = 1;
	}
	
	public function formatAdminBox($path, $settingGroup, &$box, &$fields, &$values, $changes) {
		$tags = ze\ray::explodeAndTrim($box['key']['id']);
		
		if ($box['key']['cID']) {
			$tagsCount = 1;
		} else {
			$tagsCount = count($tags);
		}
		
		$date = false;
		if ($values['publish/publish_options__schedule'] && $values['publish/publish_date']) {
			$date = $values['publish/publish_date'];
		}
		
		$clash = static::checkForClashingPublicationDates($box['key']['id'], $date);
		
		$fields['publish/release_date']['notices_below']['release_date_is_not_the_scheduled_publishing_date']['hidden'] =
		$fields['publish/release_date']['notices_below']['release_date_is_not_today']['hidden'] =
		$fields['publish/multiple_items__publishing_date_not_set_correctly']['notices_above']['notice']['hidden'] = true;
		
		if ($tagsCount == 1) {
			$version = ze\content::version($box['key']['cID'], $box['key']['cType']);
			$cTypeDetails = ze\contentAdm::cTypeDetails($box['key']['cType']);
			
			if ($cTypeDetails['release_date_field'] == 'optional') {
				$fields['publish/release_date']['hidden'] = false;
				
				$dateToday = ze\date::now();
				$dateTodayFormatted = ze\date::format($dateToday);
				
				$releaseDate = ze\row::get('content_item_versions', 'release_date', ['id' => $box['key']['cID'], 'type' => $box['key']['cType'], 'version' => $version]);
				$releaseDateFormatted = ze\date::format($releaseDate);
				
				$href = ze\link::absolute() . 'organizer.php#zenario__content/panels/content/refiners/content_type//' . $box['key']['cType'] . '//' . $box['key']['id'] . '~.zenario_content~tmeta_data~k{"id"%3A"' . $box['key']['id'] . '"}';
				$linkStart = '<a href="' . htmlspecialchars($href) . '" target="blank">';
				$linkEnd = '</a>';
				
				if ($releaseDate) {
					$values['publish/release_date'] = ze\admin::phrase('Release date [[release_date]]', ['release_date' => $releaseDateFormatted]);
					
					if ($clash) {						
						$replace = [
							'intended_date' => $dateTodayFormatted,
							'link_start' => $linkStart,
							'date' => $clash['date'],
							'link_end' => $linkEnd
						];
						
						if ($values['publish/publish_options__schedule'] && $values['publish/publish_date']) {
							$fields['publish/release_date']['notices_below']['release_date_is_not_the_scheduled_publishing_date']['hidden'] = false;
							
							$replace['intended_date'] = ze\date::format($values['publish/publish_date']);
							
							$fields['publish/release_date']['notices_below']['release_date_is_not_the_scheduled_publishing_date']['message'] =
								ze\admin::phrase(
									"The release date is not set to the scheduled publishing date ([[intended_date]]). If that is not correct, [[link_start]]edit the meta data[[link_end]].",
									$replace
								);
						} else {
							$fields['publish/release_date']['notices_below']['release_date_is_not_today']['hidden'] = false;
							
							if (!$date) {
								$date = ze\date::now();
							}
							
							$intendedReleaseDateTimestamp = strtotime($date);
							$releaseDateTimestamp = strtotime($releaseDate);
							
							$replace['release_date'] = $releaseDateFormatted;
							
							if ($releaseDateTimestamp < $intendedReleaseDateTimestamp) {
								$message = 'The release date is in the past ([[release_date]]). If that is not correct, [[link_start]]edit the meta data[[link_end]].';
							} else {
								$message = 'The release date is in the future ([[release_date]]). If that is not correct, [[link_start]]edit the meta data[[link_end]].';
							}
							
							$fields['publish/release_date']['notices_below']['release_date_is_not_today']['message'] = ze\admin::phrase($message, $replace);
						}
					}
				} else {
					if ($cTypeDetails['auto_set_release_date']) {
						if ($values['publish/publish_options__schedule']) {
							$values['publish/release_date'] = ze\admin::phrase('Release date will be set to the date of publishing ([[date_of_publishing]])', ['date_of_publishing' => ze\date::format($values['publish/publish_date'])]);
						} else {
							$values['publish/release_date'] = ze\admin::phrase('Release date will be set to today ([[today]])', ['today' => $dateTodayFormatted]);
						}
					} else {
						$values['publish/release_date'] = ze\admin::phrase('Release date not set');
						
						$replace = [
							'today' => $dateTodayFormatted,
							'link_start' => $linkStart,
							'link_end' => $linkEnd
						];
						ze\lang::applyMergeFields($fields['publish/release_date']['notices_below']['release_date_not_set']['message'], $replace);
						$fields['publish/release_date']['notices_below']['release_date_not_set']['hidden'] = false;
					}
				}
			}
		} elseif ($tagsCount > 1 && $clash) {
			if ($values['publish/publish_options__schedule'] && $values['publish/publish_date']) {
				$message = 'At least one selected content item has a release date that is not set to the scheduled publishing date. If that is not correct, edit the meta data to change the release date.';
			} else {
				$message = 'At least one selected content item has a release date that is not set to today. If that is not correct, edit the meta data to change the release date.';
			}
			
			$fields['publish/multiple_items__publishing_date_not_set_correctly']['notices_above']['notice']['message'] = ze\admin::nPhrase($message);
			$fields['publish/multiple_items__publishing_date_not_set_correctly']['notices_above']['notice']['hidden'] = false;
		}
	}

	public function validateAdminBox($path, $settingGroup, &$box, &$fields, &$values, $changes, $saving) {
		
		$option = $this->getPublishOption($values);
		
		// Make sure chosen time is not in the past
		if ($option == 'schedule') {
			if (empty($values['publish/publish_date'])) {
				$box['tabs']['publish']['errors'][] = ze\admin::phrase('Please enter a date.');
			
			} else {
				$now = strtotime('now');
				$scheduledDate = strtotime($values['publish/publish_date'].' '. $values['publish/publish_hours'].':'.$values['publish/publish_mins']);
				if ($scheduledDate < $now) {
					$box['tabs']['publish']['errors'][] = ze\admin::phrase('The scheduled publishing time cannot be in the past.');
				}
			}
		}
	}
	
	public function saveAdminBox($path, $settingGroup, &$box, &$fields, &$values, $changes) {
		
		$option = $this->getPublishOption($values);
		$ids = (($box['key']['id']) ? $box['key']['id'] : $box['key']['cID']);
		
		$ids = ze\ray::explodeAndTrim($ids);
		$tagsCount = count($ids);
		
		//Settings for IndexNow
// 		$notifyIndexNow = false;
// 		$indexNowApiKey = '';
// 		if (ze::setting('enable_indexnow') && ($indexNowApiKey = ze::setting('indexnow_api_key'))) {
// 			if ($tagsCount == 1 && isset($fields['publish/notify_indexnow']) && $values['publish/notify_indexnow']) {
// 				if (!(ze\module::inc('zenario_user_timers') && $option != 'immediately')) {
// 					$notifyIndexNow = true;
// 				}
// 			}
// 		}
		
		foreach ($ids as $id) {
			$cID = $cType = false;
			if (!empty($box['key']['cID']) && !empty($box['key']['cType'])) {
				$cID = $box['key']['cID'];
				$cType = $box['key']['cType'];
			} else {
				ze\content::getCIDAndCTypeFromTagId($cID, $cType, $id);
			}
			
			if ($cID && $cType && ze\priv::check('_PRIV_PUBLISH_CONTENT_ITEM', $cID, $cType)) {
				$adminId = $_SESSION['admin_userid'] ?? false;
				if (($option == 'immediately' && ze\contentAdm::allowPublishListed($cID, $cType))
				 || ($option == 'unlisted' && ze\contentAdm::allowPublishUnlisted($cID, $cType))) {
					// Publish now
					if ($box['tabs']['publish']['notices']['scheduled_warning']['show']) {
						//If this content item was scheduled for publishing, but now an admin immediately publishes it,
						//remove all the scheduled information.
						$cVersion = ze\row::get('content_items', 'admin_version', ['id' => $cID, 'type' => $cType]);
						ze\row::update('content_item_versions', ['scheduled_publish_datetime' => NULL], ['id' => $cID, 'type' => $cType, 'version' => $cVersion]);

						//Unlock content item
						ze\row::update('content_items', ['lock_owner_id' => 0, 'locked_datetime' => NULL], ['id' => $cID, 'type' => $cType]);
					}
					
					$shouldBeUnlisted = $option == 'unlisted';
					ze\contentAdm::publishContent($cID, $cType, false, $shouldBeUnlisted);
					
					if (ze\ring::chopPrefix($cType. '_'. $cID. '.', ze::session('last_item'))) {
						unset($_SESSION['last_item'], $_SESSION['page_mode'], $_SESSION['page_toolbar']);
					}
					
					//If a content item was previously scheduled, but an admin has published it immediately,
					//send email notifications.
					if ($box['tabs']['publish']['notices']['scheduled_warning']['show']) {
						
						$addressFrom = ze::setting('email_address_from');
						$nameFrom = ze::setting('email_name_from');
						$subject = ze\admin::phrase('Content item publishing schedule cancelled, published immediately');
						$text = self::getEmailTextContentItemScheduleCancelledButItemPublishedImmediately();
						zenario_common_features::putBodyInTemplate($text);
					
						$tag = ze\content::formatTag($cID, $cType);
						$cVersion = ze\row::get('content_items', 'admin_version', ['id' => $cID, 'type' => $cType]);
						$contentItemTitle = ze\content::title($cID, $cType, $cVersion);
						$currentStatus = ze\admin::phrase('Scheduled publishing cancelled, item published immediately');
					
						$lockingAdminDetails = ze\admin::details($adminId);
					
						$mergeFields = [
							'admin_first_name' => $lockingAdminDetails['first_name'],
							'admin_last_name' => $lockingAdminDetails['last_name'],
							'content_type' => ze\row::get('content_types', 'content_type_name_en', ['content_type_id' => $cType]),
							'content_item_title' => $contentItemTitle,
							'requesting_admin' => ze\admin::formatName($lockingAdminDetails),
							'content_item' => $tag,
							'content_item_url' => ze\link::toItem($cID, $cType),
							'current_status' => $currentStatus
						];
				
						zenario_common_features::sendEmails($lockingAdminDetails['email'], $subject, $addressFrom, $nameFrom, $text, $mergeFields);
					
						$citemLastAuthorAndCreatingAuthor = ze\row::get('content_item_versions', ['last_author_id', 'creating_author_id'], ['id' => $cID, 'type' => $cType, 'version' => $cVersion]);
						if ($citemLastAuthorAndCreatingAuthor['last_author_id'] != 0) {
							$lastEditAdminId = $citemLastAuthorAndCreatingAuthor['last_author_id'];
						} else {
							$lastEditAdminId = $citemLastAuthorAndCreatingAuthor['creating_author_id'];
						}
			
						$lastEditingAdminDetails = ze\admin::details($lastEditAdminId);
					
						if ($lastEditingAdminDetails['email'] != $lockingAdminDetails['email']) {
							$mergeFields = [
								'admin_first_name' => $lastEditingAdminDetails['first_name'],
								'admin_last_name' => $lastEditingAdminDetails['last_name'],
								'content_type' => ze\row::get('content_types', 'content_type_name_en', ['content_type_id' => $cType]),
								'content_item_title' => $contentItemTitle,
								'date_and_time' => ze\date::formatDateTime($scheduled_publish_datetime),
								'requesting_admin' => ze\admin::formatName($lockingAdminDetails),
								'content_item' => $tag,
								'content_item_url' => ze\link::toItem($cID, $cType),
								'current_status' => $currentStatus
							];
				
							zenario_common_features::sendEmails($lastEditingAdminDetails['email'], $subject, $addressFrom, $nameFrom, $text, $mergeFields);
						}
					}
					
// 					if ($notifyIndexNow && $indexNowApiKey) {
// 						$urlChanged = ze\link::toItem($cID, $cType, $fullPath = true);
// 						$indexNowUrl = 'https://www.bing.com/indexnow?url=' . urlencode($urlChanged) . '&key=' . urlencode($indexNowApiKey);
// 						var_dump($indexNowUrl);
// 						
// 						$keyLocation = CMS_ROOT . 'zenario_custom/' . $indexNowApiKey . '.txt';
// 						$indexNowUrl = 'https://api.indexnow.org/indexnow?url=' . urlencode($urlChanged) . '&key=' . urlencode($indexNowApiKey) . '&keyLocation=' . $keyLocation;
// 						
// 						$indexNowCallResult = ze\curl::fetch($indexNowUrl, $post = true);
// 					}
				} elseif ($option == 'schedule' && ze\contentAdm::allowPublishListed($cID, $cType)) {
					// Publish on a later date
					$scheduled_publish_datetime = $values['publish/publish_date'].' '.$values['publish/publish_hours'].':'.$values['publish/publish_mins'].':00';
					$cVersion = ze\row::get('content_items', 'admin_version', ['id' => $cID, 'type' => $cType]);
					ze\row::update('content_item_versions', ['scheduled_publish_datetime' => $scheduled_publish_datetime], ['id' => $cID, 'type' => $cType, 'version' => $cVersion]);
					
					// Lock content item
					ze\row::update('content_items', ['lock_owner_id' => $adminId, 'locked_datetime'=>date('Y-m-d H:i:s')], ['id' => $cID, 'type' => $cType]);
					
					//Inform the admins: the one who requested the scheduling, and the last editor (or creator if never edited).
					
					$addressFrom = ze::setting('email_address_from');
					$nameFrom = ze::setting('email_name_from');
					$subject = ze\admin::phrase('Content item scheduled for publishing');
					$text = self::getEmailTextContentItemScheduledForPublishing();
					zenario_common_features::putBodyInTemplate($text);
					
					$tag = ze\content::formatTag($cID, $cType);
					$contentItemTitle = ze\content::title($cID, $cType, $cVersion);
					
					$lockingAdminDetails = ze\admin::details($adminId);
					
					$mergeFields = [
						'admin_first_name' => $lockingAdminDetails['first_name'],
						'admin_last_name' => $lockingAdminDetails['last_name'],
						'content_type' => ze\row::get('content_types', 'content_type_name_en', ['content_type_id' => $cType]),
						'content_item_title' => $contentItemTitle,
						'date_and_time' => ze\date::formatDateTime($scheduled_publish_datetime),
						'requesting_admin' => ze\admin::formatName($lockingAdminDetails),
						'content_item' => $tag,
						'content_item_url' => ze\link::toItem($cID, $cType)
					];
				
					zenario_common_features::sendEmails($lockingAdminDetails['email'], $subject, $addressFrom, $nameFrom, $text, $mergeFields);
					
					$citemLastAuthorAndCreatingAuthor = ze\row::get('content_item_versions', ['last_author_id', 'creating_author_id'], ['id' => $cID, 'type' => $cType, 'version' => $cVersion]);
					if ($citemLastAuthorAndCreatingAuthor['last_author_id'] != 0) {
						$lastEditAdminId = $citemLastAuthorAndCreatingAuthor['last_author_id'];
					} else {
						$lastEditAdminId = $citemLastAuthorAndCreatingAuthor['creating_author_id'];
					}
			
					$lastEditingAdminDetails = ze\admin::details($lastEditAdminId);
					
					if ($lastEditingAdminDetails['email'] != $lockingAdminDetails['email']) {
						$mergeFields = [
							'admin_first_name' => $lastEditingAdminDetails['first_name'],
							'admin_last_name' => $lastEditingAdminDetails['last_name'],
							'content_type' => ze\row::get('content_types', 'content_type_name_en', ['content_type_id' => $cType]),
							'content_item_title' => $contentItemTitle,
							'date_and_time' => ze\date::formatDateTime($scheduled_publish_datetime),
							'requesting_admin' => ze\admin::formatName($lockingAdminDetails),
							'content_item' => $tag,
							'content_item_url' => ze\link::toItem($cID, $cType)
						];
				
						zenario_common_features::sendEmails($lastEditingAdminDetails['email'], $subject, $addressFrom, $nameFrom, $text, $mergeFields);
					}
				} elseif ($option == 'cancel') {
					//Cancel publishing
					$cVersion = ze\row::get('content_items', 'admin_version', ['id' => $cID, 'type' => $cType]);
					ze\row::update('content_item_versions', ['scheduled_publish_datetime' => NULL], ['id' => $cID, 'type' => $cType, 'version' => $cVersion]);

					// Unlock content item
					ze\row::update('content_items', ['lock_owner_id' => 0, 'locked_datetime' => NULL], ['id' => $cID, 'type' => $cType]);
					
					//Inform the admins: the one who requested the scheduling, and the last editor (or creator if never edited).
					
					$addressFrom = ze::setting('email_address_from');
					$nameFrom = ze::setting('email_name_from');
					$subject = ze\admin::phrase('Content item publishing schedule cancelled');
					$text = self::getEmailTextContentItemScheduleCancelled();
					zenario_common_features::putBodyInTemplate($text);
					
					$tag = ze\content::formatTag($cID, $cType);
					$contentItemTitle = ze\content::title($cID, $cType, $cVersion);
					$currentStatus = ze\admin::phrase('Scheduled publishing cancelled');
					
					$lockingAdminDetails = ze\admin::details($adminId);
					
					$mergeFields = [
						'admin_first_name' => $lockingAdminDetails['first_name'],
						'admin_last_name' => $lockingAdminDetails['last_name'],
						'content_type' => ze\row::get('content_types', 'content_type_name_en', ['content_type_id' => $cType]),
						'content_item_title' => $contentItemTitle,
						'requesting_admin' => ze\admin::formatName($lockingAdminDetails),
						'content_item' => $tag,
						'content_item_url' => ze\link::toItem($cID, $cType),
						'current_status' => $currentStatus
					];
				
					zenario_common_features::sendEmails($lockingAdminDetails['email'], $subject, $addressFrom, $nameFrom, $text, $mergeFields);
					
					$citemLastAuthorAndCreatingAuthor = ze\row::get('content_item_versions', ['last_author_id', 'creating_author_id'], ['id' => $cID, 'type' => $cType, 'version' => $cVersion]);
					if ($citemLastAuthorAndCreatingAuthor['last_author_id'] != 0) {
						$lastEditAdminId = $citemLastAuthorAndCreatingAuthor['last_author_id'];
					} else {
						$lastEditAdminId = $citemLastAuthorAndCreatingAuthor['creating_author_id'];
					}
			
					$lastEditingAdminDetails = ze\admin::details($lastEditAdminId);
					
					if ($lastEditingAdminDetails['email'] != $lockingAdminDetails['email']) {
						$mergeFields = [
							'admin_first_name' => $lastEditingAdminDetails['first_name'],
							'admin_last_name' => $lastEditingAdminDetails['last_name'],
							'content_type' => ze\row::get('content_types', 'content_type_name_en', ['content_type_id' => $cType]),
							'content_item_title' => $contentItemTitle,
							'requesting_admin' => ze\admin::formatName($lockingAdminDetails),
							'content_item' => $tag,
							'content_item_url' => ze\link::toItem($cID, $cType),
							'current_status' => $currentStatus
						];
				
						zenario_common_features::sendEmails($lastEditingAdminDetails['email'], $subject, $addressFrom, $nameFrom, $text, $mergeFields);
					}
				}
			}
		}
	}
	
	public function adminBoxSaveCompleted($path, $settingGroup, &$box, &$fields, &$values, $changes) {
		$ids = (($box['key']['id']) ? $box['key']['id'] : $box['key']['cID']);
		$tags = ze\ray::explodeAndTrim($ids);

		//If it looks like this was opened from the front-end
		//(i.e. there's no sign of any of Organizer's variables)
		//then try to redirect the admin to whatever the visitor URL should be.
		
		if (!isset($_GET['refinerName']) && count($tags) == 1) {
			$link = ze\link::toItemWithAlias(
				$box['key']['cID'], $box['key']['cType'],
				$fullPath = true
			);
			
			$flags = [];
			$flags['GO_TO_URL'] = $link;
			ze\tuix::closeWithFlags($flags);
			exit;
		}
	}
	
	public static function getEmailTextContentItemScheduledForPublishing() {
		$emailText = "
Dear [[admin_first_name]] [[admin_last_name]],

You are receiving this email because a content item ([[content_type]], \"[[content_item_title]]\") has been scheduled for publishing.

Content item: [[content_item]]
Date and time for publishing: [[date_and_time]]
Requesting admin: [[requesting_admin]]

<p style=\"text-align: center;\"><a style=\"background: #015ca1; color: white; text-decoration: none; padding: 20px 40px; font-size: 16px;\" href=\"[[content_item_url]]\">View content item</a></p>";
		
		return nl2br($emailText);
	}
	
	public static function getEmailTextContentItemScheduleCancelled() {
		$emailText = "
Dear [[admin_first_name]] [[admin_last_name]],

You are receiving this email because a content item ([[content_type]], \"[[content_item_title]]\") is no longer scheduled for publishing.

Content item: [[content_item]]
Requesting admin: [[requesting_admin]]
Current status: [[current_status]]

<p style=\"text-align: center;\"><a style=\"background: #015ca1; color: white; text-decoration: none; padding: 20px 40px; font-size: 16px;\" href=\"[[content_item_url]]\">View content item</a></p>";
		
		return nl2br($emailText);
	}
	
	public static function getEmailTextContentItemScheduleCancelledButItemPublishedImmediately() {
		$emailText = "
Dear [[admin_first_name]] [[admin_last_name]],

You are receiving this email because a content item ([[content_type]], \"[[content_item_title]]\") is no longer scheduled for publishing.

Content item: [[content_item]]
Requesting admin: [[requesting_admin]]
Current status: [[current_status]]

<p style=\"text-align: center;\"><a style=\"background: #015ca1; color: white; text-decoration: none; padding: 20px 40px; font-size: 16px;\" href=\"[[content_item_url]]\">View content item</a></p>";
		
		return nl2br($emailText);
	}
}
