diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index eb0438a68..0bdd79af4 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -92,6 +92,12 @@ class Context */ public $meta_tags = array(); + /** + * OpenGraph metadata + * @var array + */ + public $opengraph_metadata = array(); + /** * path of Xpress Engine * @var string @@ -810,24 +816,46 @@ class Context } /** - * Add string to browser title + * Append string to browser title * - * @param string $site_title Browser title to be added + * @param string $site_title Browser title to be appended * @return void */ - public static function addBrowserTitle($site_title) + public static function addBrowserTitle($title) { - if(!$site_title) + if(!$title) { return; } if(self::$_instance->site_title) { - self::$_instance->site_title .= ' - ' . $site_title; + self::$_instance->site_title .= ' - ' . $title; } else { - self::$_instance->site_title = $site_title; + self::$_instance->site_title = $title; + } + } + + /** + * Prepend string to browser title + * + * @param string $site_title Browser title to be prepended + * @return void + */ + public static function prependBrowserTitle($title) + { + if(!$title) + { + return; + } + if(self::$_instance->site_title) + { + self::$_instance->site_title = $title . ' - ' . self::$_instance->site_title; + } + else + { + self::$_instance->site_title = $title; } } @@ -835,15 +863,22 @@ class Context * Set string to browser title * * @param string $site_title Browser title to be set + * @param array $vars * @return void */ - public static function setBrowserTitle($site_title) + public static function setBrowserTitle($title, $vars = array()) { - if(!$site_title) + if (!$title) { return; } - self::$_instance->site_title = $site_title; + if (count($vars)) + { + $title = preg_replace_callback('/\\$(\w+)/', function($matches) use($vars) { + return isset($vars[strtolower($matches[1])]) ? $vars[strtolower($matches[1])] : $matches[0]; + }, $title); + } + self::$_instance->site_title = $title; } /** @@ -853,26 +888,52 @@ class Context */ public static function getBrowserTitle() { - $oModuleController = getController('module'); - $oModuleController->replaceDefinedLangCode(self::$_instance->site_title); - + if (!self::$_instance->site_title) + { + return ''; + } + getController('module')->replaceDefinedLangCode(self::$_instance->site_title); return htmlspecialchars(self::$_instance->site_title, ENT_COMPAT | ENT_HTML401, 'UTF-8', FALSE); } /** - * Return layout's title - * @return string layout's title + * Return site title + * + * @return string */ public static function getSiteTitle() { - $oModuleModel = getModel('module'); - $moduleConfig = $oModuleModel->getModuleConfig('module'); - - if(isset($moduleConfig->siteTitle)) + $moduleConfig = getModel('module')->getModuleConfig('module'); + if (isset($moduleConfig->siteTitle)) { - return $moduleConfig->siteTitle; + $title = trim($moduleConfig->siteTitle); + getController('module')->replaceDefinedLangCode($title); + return $title; + } + else + { + return ''; + } + } + + /** + * Return site subtitle + * + * @return string + */ + public static function getSiteSubtitle() + { + $moduleConfig = getModel('module')->getModuleConfig('module'); + if (isset($moduleConfig->siteSubtitle)) + { + $subtitle = trim($moduleConfig->siteSubtitle); + getController('module')->replaceDefinedLangCode($subtitle); + return $subtitle; + } + else + { + return ''; } - return ''; } /** @@ -2660,33 +2721,91 @@ class Context /** * Get meta tag + * + * @param string $name (optional) * @return array The list of meta tags */ - public static function getMetaTag() + public static function getMetaTag($name = null) { - $ret = array(); - foreach(self::$_instance->meta_tags as $key => $val) + if ($name !== null) { - list($name, $is_http_equiv) = explode("\t", $key); - $ret[] = array('name' => $name, 'is_http_equiv' => $is_http_equiv, 'content' => $val); + return isset(self::$_instance->meta_tags[$name]) ? self::$_instance->meta_tags[$name]['content'] : null; + } + + $ret = array(); + foreach(self::$_instance->meta_tags as $name => $content) + { + $ret[] = array('name' => $name, 'is_http_equiv' => $content['is_http_equiv'], 'content' => escape($content['content'], false)); } return $ret; } /** - * Add the meta tag + * Add meta tag * * @param string $name name of meta tag * @param string $content content of meta tag * @param mixed $is_http_equiv value of http_equiv * @return void */ - public static function addMetaTag($name, $content, $is_http_equiv = FALSE) + public static function addMetaTag($name, $content, $is_http_equiv = false) { - self::$_instance->meta_tags[$name . "\t" . ($is_http_equiv ? '1' : '0')] = $content; + getController('module')->replaceDefinedLangCode($content); + self::$_instance->meta_tags[$name] = array('is_http_equiv' => (bool)$is_http_equiv, 'content' => $content); + } + + /** + * Get OpenGraph metadata + * + * @return array + */ + public static function getOpenGraphData() + { + $ret = array(); + foreach(self::$_instance->opengraph_metadata as $key => $val) + { + if ($val[1] === false || $val[1] === null) + { + continue; + } + $ret[] = array('property' => escape($val[0], false), 'content' => escape($val[1], false)); + } + return $ret; + } + + /** + * Add OpenGraph metadata + * + * @param string $name + * @param mixed $content + * @return void + */ + public static function addOpenGraphData($name, $content) + { + if (is_array($content)) + { + foreach ($content as $key => $val) + { + self::addOpenGraphData("$name:$key", $val); + } + } + else + { + self::$_instance->opengraph_metadata[] = array($name, $content); + } + } + + /** + * Set canonical URL + * + * @param string $url + * @return void + */ + public static function setCanonicalURL($url) + { + self::addHtmlHeader(sprintf('', escape($url))); } - } /* End of file Context.class.php */ /* Location: ./classes/context/Context.class.php */ diff --git a/classes/display/HTMLDisplayHandler.php b/classes/display/HTMLDisplayHandler.php index b106ef3cf..3ea37395e 100644 --- a/classes/display/HTMLDisplayHandler.php +++ b/classes/display/HTMLDisplayHandler.php @@ -213,6 +213,12 @@ class HTMLDisplayHandler // Remove unnecessary information $output = preg_replace('/member\_\-([0-9]+)/s', 'member_0', $output); + + // Add OpenGraph metadata + if (config('seo.og_enabled') && Context::get('module') !== 'admin') + { + $this->_addOpenGraphMetadata(); + } // set icon $oAdminModel = getAdminModel('admin'); @@ -380,6 +386,140 @@ class HTMLDisplayHandler } Context::loadFile($matches[2]); } + + /** + * Add OpenGraph metadata tags. + * + * @param string $output + * @return void + */ + function _addOpenGraphMetadata() + { + // Get information about the current request. + $page_type = 'website'; + $current_module_info = Context::get('current_module_info'); + $site_module_info = Context::get('site_module_info'); + $document_srl = Context::get('document_srl'); + if ($document_srl) + { + $oDocument = Context::get('oDocument') ?: getModel('document')->getDocument($document_srl, false, false); + if ($oDocument instanceof documentItem && $oDocument->document_srl == $document_srl && !$oDocument->isSecret()) + { + $page_type = 'article'; + } + } + + // Add basic metadata. + Context::addOpenGraphData('og:title', Context::getBrowserTitle()); + Context::addOpenGraphData('og:site_name', Context::getSiteTitle()); + if ($page_type === 'article' && config('seo.og_extract_description')) + { + Context::addOpenGraphData('og:description', trim(utf8_normalize_spaces($oDocument->getContentText(200)))); + } + else + { + Context::addOpenGraphData('og:description', Context::getMetaTag('description')); + } + + // Add metadata about this page. + Context::addOpenGraphData('og:type', $page_type); + if ($page_type === 'article') + { + $document_canonical_url = getFullUrl('', 'mid', $current_module_info->mid, 'document_srl', $document_srl); + Context::addOpenGraphData('og:url', $document_canonical_url); + } + elseif (($page = Context::get('page')) > 1) + { + Context::addOpenGraphData('og:url', getFullUrl('', 'mid', $current_module_info->mid, 'page', $page)); + } + elseif ($current_module_info->module_srl == $site_module_info->module_srl) + { + Context::addOpenGraphData('og:url', Rhymix\Framework\URL::getCurrentDomainURL(\RX_BASEURL)); + } + else + { + Context::addOpenGraphData('og:url', getFullUrl('', 'mid', $current_module_info->mid)); + } + + // Add metadata about the locale. + $lang_type = Context::getLangType(); + $locales = (include \RX_BASEDIR . 'common/defaults/locales.php'); + if (isset($locales[$lang_type])) + { + Context::addOpenGraphData('og:locale', $locales[$lang_type]); + } + if ($page_type === 'article' && $oDocument->getLangCode() !== $lang_type && isset($locales[$oDocument->getLangCode()])) + { + Context::addOpenGraphData('og:locale:alternate', $locales[$oDocument->getLangCode()]); + } + + // Add image. + if ($page_type === 'article' && config('seo.og_extract_images')) + { + if (($document_images = Rhymix\Framework\Cache::get("seo:document_images:$document_srl")) === null) + { + $document_images = array(); + if ($oDocument->hasUploadedFiles()) + { + foreach ($oDocument->getUploadedFiles() as $file) + { + if ($file->isvalid !== 'Y' || !preg_match('/\.(?:bmp|gif|jpe?g|png)$/i', $file->uploaded_filename)) + { + continue; + } + list($width, $height) = @getimagesize($file->uploaded_filename); + if ($width < 100 && $height < 100) + { + continue; + } + $image = array('filepath' => $file->uploaded_filename, 'width' => $width, 'height' => $height); + if ($file->cover_image === 'Y') + { + array_unshift($document_images, $image); + } + else + { + $document_images[] = $image; + } + if (count($document_images) >= 1) + { + break; + } + } + } + Rhymix\Framework\Cache::set("seo:document_images:$document_srl", $document_images, 0, true); + } + } + else + { + $document_images = null; + } + + if ($document_images) + { + $first_image = reset($document_images); + $first_image['filepath'] = preg_replace('/^.\\/files\\//', \RX_BASEURL . 'files/', $first_image['filepath']); + Context::addOpenGraphData('og:image', Rhymix\Framework\URL::getCurrentDomainURL($first_image['filepath'])); + Context::addOpenGraphData('og:image:width', $first_image['width']); + Context::addOpenGraphData('og:image:height', $first_image['height']); + } + elseif ($default_image = getAdminModel('admin')->getSiteDefaultImageUrl($width, $height)) + { + Context::addOpenGraphData('og:image', Rhymix\Framework\URL::getCurrentDomainURL($default_image)); + if ($width && $height) + { + Context::addOpenGraphData('og:image:width', $width); + Context::addOpenGraphData('og:image:height', $height); + } + } + + // Add datetime for articles. + if ($page_type === 'article' && config('seo.og_use_timestamps')) + { + Context::addOpenGraphData('article:published_time', $oDocument->getRegdate('c')); + Context::addOpenGraphData('article:modified_time', $oDocument->getUpdate('c')); + } + } /** * import basic .js files. diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php index 4ffe9e363..b58e18bf1 100644 --- a/classes/module/ModuleHandler.class.php +++ b/classes/module/ModuleHandler.class.php @@ -285,7 +285,41 @@ class ModuleHandler extends Handler $this->module = $module_info->module; $this->mid = $module_info->mid; $this->module_info = $module_info; - Context::setBrowserTitle($module_info->browser_title); + if ($module_info->mid == $site_module_info->mid) + { + $seo_title = config('seo.main_title') ?: '$SITE_TITLE - $SITE_SUBTITLE'; + } + else + { + $seo_title = config('seo.subpage_title') ?: '$SITE_TITLE - $SUBPAGE_TITLE'; + } + + getController('module')->replaceDefinedLangCode($seo_title); + Context::setBrowserTitle($seo_title, array( + 'site_title' => Context::getSiteTitle(), + 'site_subtitle' => Context::getSiteSubtitle(), + 'subpage_title' => $module_info->browser_title, + 'page' => Context::get('page') ?: 1, + )); + + $module_config = $oModuleModel->getModuleConfig('module'); + if ($module_info->meta_keywords) + { + Context::addMetaTag('keywords', $module_info->meta_keywords); + } + elseif($module_config->meta_keywords) + { + Context::addMetaTag('keywords', $module_config->meta_keywords); + } + + if ($module_info->meta_description) + { + Context::addMetaTag('description', $module_info->meta_description); + } + elseif($module_config->meta_description) + { + Context::addMetaTag('description', $module_config->meta_description); + } $viewType = (Mobile::isFromMobilePhone()) ? 'M' : 'P'; $targetSrl = (Mobile::isFromMobilePhone()) ? 'mlayout_srl' : 'layout_srl'; @@ -764,8 +798,7 @@ class ModuleHandler extends Handler } if($module_config->siteTitle) { - $siteTitle = Context::getBrowserTitle(); - if(!$siteTitle) + if(!Context::getBrowserTitle()) { Context::setBrowserTitle($module_config->siteTitle); } diff --git a/common/defaults/blacklist.php b/common/defaults/blacklist.php index fed12c706..6706f0ea6 100644 --- a/common/defaults/blacklist.php +++ b/common/defaults/blacklist.php @@ -10,6 +10,7 @@ return array( 'errorlogger' => true, 'fix_mysql_utf8' => true, 'member_communication' => true, + 'seo' => true, 'smartphone' => true, 'zipperupper' => true, ); diff --git a/common/defaults/config.php b/common/defaults/config.php index 6e614bf75..d01ac2f4f 100644 --- a/common/defaults/config.php +++ b/common/defaults/config.php @@ -98,6 +98,15 @@ return array( 'display_to' => 'admin', 'allow' => array(), ), + 'seo' => array( + 'main_title' => '', + 'subpage_title' => '', + 'document_title' => '', + 'og_enabled' => false, + 'og_extract_description' => false, + 'og_extract_images' => false, + 'og_use_timestamps' => false, + ), 'mediafilter' => array( 'iframe' => array(), 'object' => array(), diff --git a/common/defaults/locales.php b/common/defaults/locales.php new file mode 100644 index 000000000..c6cd3a69b --- /dev/null +++ b/common/defaults/locales.php @@ -0,0 +1,21 @@ + 'ko_KR', + 'en' => 'en_US', + 'ja' => 'ja_JP', + 'zh-CN' => 'zh_CN', + 'zh-TW' => 'zh_TW', + 'de' => 'de_DE', + 'es' => 'es_ES', + 'fr' => 'fr_FR', + 'mn' => 'mn_MN', + 'ru' => 'ru_RU', + 'tr' => 'tr_TR', + 'vi' => 'vi_VN', +); diff --git a/common/lang/en.php b/common/lang/en.php index 7b4343e1f..60dcb24f6 100644 --- a/common/lang/en.php +++ b/common/lang/en.php @@ -165,6 +165,8 @@ $lang->first_page = 'First Page'; $lang->last_page = 'Last Page'; $lang->search_target = 'Target for Search'; $lang->search_keyword = 'Keyword'; +$lang->meta_keywords = 'SEO Keywords'; +$lang->meta_description = 'SEO Description'; $lang->is_default = 'Default'; $lang->no_documents = 'No Articles'; $lang->board_manager = 'Board Settings'; diff --git a/common/lang/ko.php b/common/lang/ko.php index ca37fe186..33e922dcd 100644 --- a/common/lang/ko.php +++ b/common/lang/ko.php @@ -165,6 +165,8 @@ $lang->first_page = '첫 페이지'; $lang->last_page = '끝 페이지'; $lang->search_target = '검색대상'; $lang->search_keyword = '검색어'; +$lang->meta_keywords = 'SEO 키워드'; +$lang->meta_description = 'SEO 설명'; $lang->is_default = '기본'; $lang->no_documents = '등록된 글이 없습니다.'; $lang->board_manager = '게시판 관리'; diff --git a/common/tpl/common_layout.html b/common/tpl/common_layout.html index cb70b9c19..5d08f452d 100644 --- a/common/tpl/common_layout.html +++ b/common/tpl/common_layout.html @@ -8,7 +8,7 @@ - + @@ -39,6 +39,9 @@ + + + {Context::getHtmlHeader()} diff --git a/modules/addon/tpl/setup_addon.html b/modules/addon/tpl/setup_addon.html index 399936fa6..b793b1ee7 100644 --- a/modules/addon/tpl/setup_addon.html +++ b/modules/addon/tpl/setup_addon.html @@ -2,6 +2,7 @@

{$lang->installed_addons}

{$addon_info->title}

+ @@ -30,6 +31,9 @@
+
+

{$lang->msg_warning} {$lang->msg_blacklisted_module}

+

{$XE_VALIDATOR_MESSAGE}

diff --git a/modules/admin/admin.admin.controller.php b/modules/admin/admin.admin.controller.php index ba8c9ce5c..ce0d1a4f1 100644 --- a/modules/admin/admin.admin.controller.php +++ b/modules/admin/admin.admin.controller.php @@ -511,6 +511,7 @@ class adminAdminController extends admin // Site title and HTML footer $args = new stdClass; $args->siteTitle = $vars->site_title; + $args->siteSubtitle = $vars->site_subtitle; $args->htmlFooter = $vars->html_footer; $oModuleController->updateModuleConfig('module', $args); @@ -521,11 +522,6 @@ class adminAdminController extends admin $site_args->default_language = $vars->default_lang; $oModuleController->updateSite($site_args); - // Thumbnail settings - $args = new stdClass; - $args->thumbnail_type = $vars->thumbnail_type === 'ratio' ? 'ratio' : 'crop'; - $oModuleController->insertModuleConfig('document', $args); - // Default and enabled languages $enabled_lang = $vars->enabled_lang; if (!in_array($vars->default_lang, $enabled_lang)) @@ -545,6 +541,7 @@ class adminAdminController extends admin // Favicon and mobicon $this->_saveFavicon('favicon.ico', $vars->is_delete_favicon); $this->_saveFavicon('mobicon.png', $vars->is_delete_mobicon); + $this->_saveDefaultImage($vars->is_delete_site_default_image); // Save Rhymix\Framework\Config::save(); @@ -693,6 +690,12 @@ class adminAdminController extends admin Rhymix\Framework\Config::set('cache', array()); } + // Thumbnail settings + $args = new stdClass; + $args->thumbnail_type = $vars->thumbnail_type === 'ratio' ? 'ratio' : 'crop'; + $oModuleController = getController('module'); + $oModuleController->insertModuleConfig('document', $args); + // Other settings Rhymix\Framework\Config::set('use_rewrite', $vars->use_rewrite === 'Y'); Rhymix\Framework\Config::set('use_sso', $vars->use_sso === 'Y'); @@ -768,6 +771,35 @@ class adminAdminController extends admin $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigDebug')); } + /** + * Update SEO configuration. + */ + function procAdminUpdateSEO() + { + $vars = Context::getRequestVars(); + + $args = new stdClass; + $args->meta_keywords = $vars->site_meta_keywords ? implode(', ', array_map('trim', explode(',', $vars->site_meta_keywords))) : ''; + $args->meta_description = trim(utf8_normalize_spaces($vars->site_meta_description)); + $oModuleController = getController('module'); + $oModuleController->updateModuleConfig('module', $args); + + Rhymix\Framework\Config::set('seo.main_title', trim(utf8_normalize_spaces($vars->seo_main_title))); + Rhymix\Framework\Config::set('seo.subpage_title', trim(utf8_normalize_spaces($vars->seo_subpage_title))); + Rhymix\Framework\Config::set('seo.document_title', trim(utf8_normalize_spaces($vars->seo_document_title))); + + Rhymix\Framework\Config::set('seo.og_enabled', $vars->og_enabled === 'Y'); + Rhymix\Framework\Config::set('seo.og_extract_description', $vars->og_extract_description === 'Y'); + Rhymix\Framework\Config::set('seo.og_extract_images', $vars->og_extract_images === 'Y'); + Rhymix\Framework\Config::set('seo.og_use_timestamps', $vars->og_use_timestamps === 'Y'); + + // Save + Rhymix\Framework\Config::save(); + + $this->setMessage('success_updated'); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigSEO')); + } + /** * Update sitelock configuration. */ @@ -910,6 +942,11 @@ class adminAdminController extends admin $name = 'mobicon'; $tmpFileName = $this->_saveFaviconTemp($mobicon, 'mobicon.png'); } + elseif ($default_image = Context::get('default_image')) + { + $name = 'default_image'; + $tmpFileName = $this->_saveFaviconTemp($default_image, 'default_image.png'); + } else { $name = $tmpFileName = ''; @@ -922,7 +959,7 @@ class adminAdminController extends admin $this->setTemplateFile("favicon_upload.html"); } - private function _saveFaviconTemp($icon, $iconname) + protected function _saveFaviconTemp($icon, $iconname) { $site_info = Context::get('site_module_info'); $virtual_site = ''; @@ -934,9 +971,9 @@ class adminAdminController extends admin $original_filename = $icon['tmp_name']; $type = $icon['type']; $relative_filename = 'files/attach/xeicon/'.$virtual_site.'tmp/'.$iconname; - $target_filename = RX_BASEDIR . $relative_filename; + $target_filename = \RX_BASEDIR . $relative_filename; - if ($iconname !== 'favicon.ico' && $iconname !== 'mobicon.png') + if (!preg_match('/^(favicon|mobicon|default_image)\.(ico|png|jpe?g)$/', $iconname)) { Context::set('msg', lang('msg_invalid_format')); return; @@ -946,28 +983,63 @@ class adminAdminController extends admin return $relative_filename; } - private function _saveFavicon($iconname, $deleteIcon = false) + protected function _saveFavicon($iconname, $deleteIcon = false) { + $image_filepath = 'files/attach/xeicon/'; $site_info = Context::get('site_module_info'); - $virtual_site = ''; - if ($site_info->site_srl) + if ($site_info->site_srl) { - $virtual_site = $site_info->site_srl . '/'; + $image_filepath .= $site_info->site_srl . '/'; } - $image_filepath = RX_BASEDIR . 'files/attach/xeicon/' . $virtual_site; - if ($deleteIcon) { - Rhymix\Framework\Storage::delete($image_filepath.$iconname); + Rhymix\Framework\Storage::delete(\RX_BASEDIR . $image_filepath . $iconname); return; } - $tmpicon_filepath = $image_filepath.'tmp/'.$iconname; - $icon_filepath = $image_filepath.$iconname; + $tmpicon_filepath = $image_filepath . 'tmp/' . $iconname; + $icon_filepath = $image_filepath . $iconname; + if (file_exists(\RX_BASEDIR . $tmpicon_filepath)) + { + Rhymix\Framework\Storage::move(\RX_BASEDIR . $tmpicon_filepath, \RX_BASEDIR . $icon_filepath); + } + } + + protected function _saveDefaultImage($deleteIcon = false) + { + $image_filepath = 'files/attach/xeicon/'; + $site_info = Context::get('site_module_info'); + if ($site_info->site_srl) + { + $image_filepath .= $site_info->site_srl . '/'; + } + + if ($deleteIcon) + { + $info = Rhymix\Framework\Storage::readPHPData($image_filepath . 'default_image.php'); + if ($info['filename']) + { + Rhymix\Framework\Storage::delete(\RX_BASEDIR . $info['filename']); + } + Rhymix\Framework\Storage::delete($image_filepath . 'default_image.php'); + return; + } + + $tmpicon_filepath = \RX_BASEDIR . $image_filepath . 'tmp/default_image.png'; if (file_exists($tmpicon_filepath)) { - Rhymix\Framework\Storage::move($tmpicon_filepath, $icon_filepath); + list($width, $height, $type) = @getimagesize($tmpicon_filepath); + switch ($type) + { + case 'image/gif': $target_filename = $image_filepath . 'default_image.gif'; break; + case 'image/jpeg': $target_filename = $image_filepath . 'default_image.jpg'; break; + case 'image/png': default: $target_filename = $image_filepath . 'default_image.png'; + } + Rhymix\Framework\Storage::move($tmpicon_filepath, \RX_BASEDIR . $target_filename); + Rhymix\Framework\Storage::writePHPData(\RX_BASEDIR . 'files/attach/xeicon/' . $virtual_site . 'default_image.php', array( + 'filename' => $target_filename, 'width' => $width, 'height' => $height, + )); } } } diff --git a/modules/admin/admin.admin.model.php b/modules/admin/admin.admin.model.php index 838073e25..bf3e652ef 100644 --- a/modules/admin/admin.admin.model.php +++ b/modules/admin/admin.admin.model.php @@ -940,6 +940,31 @@ class adminAdminModel extends admin { return $this->iconUrlCheck('mobicon.png', 'mobiconSample.png', $default); } + + function getSiteDefaultImageUrl(&$width = 0, &$height = 0) + { + $site_info = Context::get('site_module_info'); + if ($site_info->site_srl) + { + $virtual_site = $site_info->site_srl . '/'; + } + else + { + $virtual_site = ''; + } + + $info = Rhymix\Framework\Storage::readPHPData(\RX_BASEDIR . 'files/attach/xeicon/' . $virtual_site . 'default_image.php'); + if ($info && Rhymix\Framework\Storage::exists(\RX_BASEDIR . $info['filename'])) + { + $width = $info['width']; + $height = $info['height']; + return \RX_BASEURL . $info['filename'] . '?' . date('YmdHis', filemtime(\RX_BASEDIR . $info['filename'])); + } + else + { + return false; + } + } function iconUrlCheck($iconname, $default_icon_name, $default) { diff --git a/modules/admin/admin.admin.view.php b/modules/admin/admin.admin.view.php index 1447d1df0..d39096b9c 100644 --- a/modules/admin/admin.admin.view.php +++ b/modules/admin/admin.admin.view.php @@ -203,7 +203,7 @@ class adminAdminView extends admin $gnbTitleInfo->adminTitle = $objConfig->adminTitle ? $objConfig->adminTitle : 'Admin'; $gnbTitleInfo->adminLogo = $objConfig->adminLogo ? $objConfig->adminLogo : ''; - $browserTitle = ($subMenuTitle ? $subMenuTitle : 'Dashboard') . ' - ' . $gnbTitleInfo->adminTitle; + $browserTitle = $gnbTitleInfo->adminTitle . ' - ' . ($subMenuTitle ? $subMenuTitle : 'Dashboard'); // Get list of favorite $oAdminAdminModel = getAdminModel('admin'); @@ -255,7 +255,7 @@ class adminAdminView extends admin Context::set('gnbUrlList', $menu->list); Context::set('parentSrl', $parentSrl); Context::set('gnb_title_info', $gnbTitleInfo); - Context::setBrowserTitle($browserTitle); + Context::addBrowserTitle($browserTitle); } /** @@ -416,7 +416,8 @@ class adminAdminView extends admin // Site title and HTML footer $oModuleModel = getModel('module'); $config = $oModuleModel->getModuleConfig('module'); - Context::set('site_title', escape($config->siteTitle)); + Context::set('var_site_title', escape($config->siteTitle)); + Context::set('var_site_subtitle', escape($config->siteSubtitle)); Context::set('all_html_footer', escape($config->htmlFooter)); // Index module @@ -424,11 +425,6 @@ class adminAdminView extends admin $start_module = $oModuleModel->getSiteInfo(0, $columnList); Context::set('start_module', $start_module); - // Thumbnail settings - $oDocumentModel = getModel('document'); - $config = $oDocumentModel->getDocumentConfig(); - Context::set('thumbnail_type', $config->thumbnail_type ?: 'crop'); - // Default time zone Context::set('timezones', Rhymix\Framework\DateTime::getTimezoneList()); Context::set('selected_timezone', Rhymix\Framework\Config::get('locale.default_timezone')); @@ -436,12 +432,14 @@ class adminAdminView extends admin // Mobile view Context::set('use_mobile_view', config('use_mobile_view') ? 'Y' : 'N'); - // Favicon and mobicon + // Favicon and mobicon and site default image $oAdminModel = getAdminModel('admin'); $favicon_url = $oAdminModel->getFaviconUrl(false) ?: $oAdminModel->getFaviconUrl(); $mobicon_url = $oAdminModel->getMobileIconUrl(false) ?: $oAdminModel->getMobileIconUrl(); + $site_default_image_url = $oAdminModel->getSiteDefaultImageUrl(); Context::set('favicon_url', $favicon_url); Context::set('mobicon_url', $mobicon_url); + Context::set('site_default_image_url', $site_default_image_url); $this->setTemplateFile('config_general'); } @@ -523,6 +521,11 @@ class adminAdminView extends admin Context::set('object_cache_port', null); } + // Thumbnail settings + $oDocumentModel = getModel('document'); + $config = $oDocumentModel->getDocumentConfig(); + Context::set('thumbnail_type', $config->thumbnail_type ?: 'crop'); + // Other settings Context::set('use_mobile_view', Rhymix\Framework\Config::get('use_mobile_view')); Context::set('use_rewrite', Rhymix\Framework\Config::get('use_rewrite')); @@ -561,6 +564,32 @@ class adminAdminView extends admin $this->setTemplateFile('config_debug'); } + /** + * Display Debug Settings page + * @return void + */ + function dispAdminConfigSEO() + { + // Meta keywords and description + $oModuleModel = getModel('module'); + $config = $oModuleModel->getModuleConfig('module'); + Context::set('site_meta_keywords', escape($config->meta_keywords)); + Context::set('site_meta_description', escape($config->meta_description)); + + // Titles + Context::set('seo_main_title', escape(Rhymix\Framework\Config::get('seo.main_title') ?: '$SITE_TITLE - $SITE_SUBTITLE')); + Context::set('seo_subpage_title', escape(Rhymix\Framework\Config::get('seo.subpage_title') ?: '$SITE_TITLE - $SUBPAGE_TITLE')); + Context::set('seo_document_title', escape(Rhymix\Framework\Config::get('seo.document_title') ?: '$SITE_TITLE - $DOCUMENT_TITLE')); + + // OpenGraph metadata + Context::set('og_enabled', Rhymix\Framework\Config::get('seo.og_enabled')); + Context::set('og_extract_description', Rhymix\Framework\Config::get('seo.og_extract_description')); + Context::set('og_extract_images', Rhymix\Framework\Config::get('seo.og_extract_images')); + Context::set('og_use_timestamps', Rhymix\Framework\Config::get('seo.og_use_timestamps')); + + $this->setTemplateFile('config_seo'); + } + /** * Display Sitelock Settings page * @return void diff --git a/modules/admin/conf/module.xml b/modules/admin/conf/module.xml index 0c51c531e..b6fd159a4 100644 --- a/modules/admin/conf/module.xml +++ b/modules/admin/conf/module.xml @@ -8,6 +8,7 @@ + @@ -26,6 +27,7 @@ + diff --git a/modules/admin/lang/en.php b/modules/admin/lang/en.php index e857f3b9b..85c7df284 100644 --- a/modules/admin/lang/en.php +++ b/modules/admin/lang/en.php @@ -5,6 +5,7 @@ $lang->subtitle_primary = 'General Settings'; $lang->subtitle_security = 'Security Settings'; $lang->subtitle_advanced = 'Advanced Settings'; $lang->subtitle_debug = 'Debug Settings'; +$lang->subtitle_seo = 'SEO Settings'; $lang->subtitle_etc = 'Other Settings'; $lang->current_state = 'Current state'; $lang->latest_documents = 'Latest Documents'; @@ -15,10 +16,9 @@ $lang->favorites = 'Favorites'; $lang->admin_info = 'Administrator Info'; $lang->admin_index = 'Index Admin Page'; $lang->control_panel = 'Dashboard'; -$lang->site_title = 'Site title'; +$lang->site_title = 'Site Title'; +$lang->site_title = 'Site Subtitle'; $lang->start_module = 'Homepage'; -$lang->about_site_title = 'This is the title which is exposed when the site title is not set at detail setting.'; -$lang->about_start_module = 'You can specify the default page for the site.'; $lang->select_site = 'Site'; $lang->select_module_type = 'Module Type'; $lang->select_module_instance = 'Select Page'; @@ -60,6 +60,12 @@ $lang->cmd_shortcut_management = 'Edit Menu'; $lang->msg_is_not_administrator = 'Only administrator can access this page.'; $lang->msg_manage_module_cannot_delete = 'Shortcuts of module, addon, layout, widget cannot be removed.'; $lang->msg_default_act_is_null = 'Shortcut cannot be registered because the default admin Action is not set.'; +$lang->msg_blacklisted_plugin = 'This plugin has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.'; +$lang->msg_blacklisted_module = 'This module has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.'; +$lang->msg_blacklisted_addon = 'This addon has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.'; +$lang->msg_blacklisted_widget = 'This widget has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.'; +$lang->msg_blacklisted_layout = 'This layout has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.'; +$lang->msg_warning = 'Warning'; $lang->welcome_to_xe = 'Welcome to the Rhymix admin page.'; $lang->about_lang_env = 'If you want to make the language setting same for first-time visitors, change the language setting to what you want and click [Save] button below.'; $lang->xe_license = 'Rhymix complies with the GPL.'; @@ -137,6 +143,22 @@ $lang->debug_log_filename = 'Log filename'; $lang->about_debug_log_filename = 'YYYYMMDD in the filename will be replaced with the current date.
It is recommended to split the log file by date to prevent it from getting too large.'; $lang->msg_debug_log_filename_not_writable = 'Rhymix cannot write log files in the specified path.'; $lang->debug_allowed_ip = 'Allowed IP addresses'; +$lang->seo_main_title = 'Main Page Title'; +$lang->about_seo_main_title = 'This format will be used for the title of the main page.
The following variables are available: $SITE_TITLE, $SITE_SUBTITLE, $SUBPAGE_TITLE.'; +$lang->seo_subpage_title = 'Subpage Title'; +$lang->about_seo_subpage_title = 'This format will be used for the title of lists and other major components of your website.
In additions to the variables above, you can use $PAGE.'; +$lang->seo_document_title = 'Document Page Title'; +$lang->about_seo_document_title = 'This format will be used for the title of individual documents.
In additions to the variables above, you can use $DOCUMENT_TITLE.'; +$lang->site_meta_keywords = 'SEO Keywords'; +$lang->about_site_meta_keywords = 'These keywords will be used on pages that do not have their own keywords.'; +$lang->site_meta_description = 'SEO Description'; +$lang->about_site_meta_description = 'This description will be used on pages that do not have their own description.'; +$lang->og_enabled = 'Add OpenGraph Tags'; +$lang->og_extract_description = 'Extract Description from Document'; +$lang->og_extract_description_fallback = 'Use general description only'; +$lang->og_extract_images = 'Extract Images from Document'; +$lang->og_extract_images_fallback = 'Use site default image only'; +$lang->og_use_timestamps = 'Include Timestamps'; $lang->autoinstall = 'EasyInstall'; $lang->last_week = 'Last Week'; $lang->this_week = 'This Week'; @@ -151,8 +173,8 @@ $lang->about_use_mobile_view = 'Show mobile page when visitors access with mobil $lang->thumbnail_type = 'Select thumbnail type.'; $lang->input_footer_script = 'Footer script'; $lang->detail_input_footer_script = 'The script is inserted into the bottom of body. It does not work at admin page.'; -$lang->corp = 'Crop(Cut)'; -$lang->ratio = 'Ratio(Keep Aspect)'; +$lang->corp = 'Crop (Cut)'; +$lang->ratio = 'Ratio (Keep Aspect Ratio)'; $lang->admin_ip_allow = 'IP addresses allowed to log in as administrator'; $lang->admin_ip_deny = 'IP addresses forbidden to log in as administrator'; $lang->local_ip_address = 'Local IP address'; @@ -160,10 +182,12 @@ $lang->about_admin_ip_allow = 'If this list is not empty, the administrator will $lang->about_admin_ip_deny = 'This list can be used to designate IP addresses that are not allowed to log in as administrator.'; $lang->msg_current_ip_will_be_denied = 'The given IP list cannot be applied, as they would block your own IP address.'; $lang->detail_about_ftp_info = 'FTP information is needed for easyinstall when save_mode = on.'; -$lang->allow_use_favicon = 'Do you want to use favicon?'; +$lang->allow_use_favicon = 'Favicon'; $lang->about_use_favicon = 'The favicon should be 16x16 or 32x32, either ico or png format.'; -$lang->allow_use_mobile_icon = 'Do you want to use the mobile home screen icon?'; +$lang->allow_use_mobile_icon = 'Home Screen Icon'; $lang->detail_use_mobile_icon = 'The mobile icon should be 57x57 or 114x114, only png format.'; +$lang->cmd_site_default_image = 'Default Image'; +$lang->about_site_default_image = 'This image will be shown when your site is linked to in various social networks. It should be 200x200, either jpg or png format.'; $lang->use_sso = 'Use SSO?'; $lang->about_use_sso = 'SSO will enable users to sign in just once for both default and virtual site. You will need this only if you are using virtual sites.'; $lang->about_arrange_session = 'Do you want to clean up session?'; diff --git a/modules/admin/lang/ko.php b/modules/admin/lang/ko.php index dd7ffffe7..c18857d87 100644 --- a/modules/admin/lang/ko.php +++ b/modules/admin/lang/ko.php @@ -5,6 +5,7 @@ $lang->subtitle_primary = '기본 설정'; $lang->subtitle_security = '보안 설정'; $lang->subtitle_advanced = '고급 설정'; $lang->subtitle_debug = '디버그 설정'; +$lang->subtitle_seo = 'SEO 설정'; $lang->subtitle_etc = '기타'; $lang->current_state = '현황'; $lang->latest_documents = '최근 글'; @@ -16,9 +17,8 @@ $lang->admin_info = '관리자 정보'; $lang->admin_index = '관리자 초기 페이지'; $lang->control_panel = '대시보드'; $lang->site_title = '사이트 제목'; -$lang->start_module = '홈페이지'; -$lang->about_site_title = '세부 설정에서 사이트제목을 설정하지 않았을 경우 노출되는 제목입니다.'; -$lang->about_start_module = '사이트 접속 시 기본으로 호출될 페이지 지정할 수 있습니다.'; +$lang->site_subtitle = '사이트 부제목'; +$lang->start_module = '메인화면 모듈 선택'; $lang->select_site = '사이트 선택'; $lang->select_module_type = '분류 선택'; $lang->select_module_instance = '페이지 선택'; @@ -60,6 +60,12 @@ $lang->cmd_shortcut_management = '메뉴 편집하기'; $lang->msg_is_not_administrator = '관리자만 접속이 가능합니다.'; $lang->msg_manage_module_cannot_delete = '모듈, 애드온, 레이아웃, 위젯 모듈의 바로가기는 삭제 불가능합니다.'; $lang->msg_default_act_is_null = '기본 관리자 Action이 지정되어 있지 않아 바로가기 등록을 할 수 없습니다.'; +$lang->msg_blacklisted_plugin = '이 플러그인은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.'; +$lang->msg_blacklisted_module = '이 모듈은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.'; +$lang->msg_blacklisted_addon = '이 애드온은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.'; +$lang->msg_blacklisted_widget = '이 위젯은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.'; +$lang->msg_blacklisted_layout = '이 레이아웃은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.'; +$lang->msg_warning = '경고'; $lang->welcome_to_xe = 'Rhymix 관리자'; $lang->about_lang_env = '처음 방문하는 사용자들의 언어 설정을 동일하게 하려면, 원하는 언어로 변경 후 아래 [저장] 버튼을 클릭하면 됩니다.'; $lang->xe_license = 'Rhymix는 GPL을 따릅니다.'; @@ -140,6 +146,22 @@ $lang->debug_log_filename = '디버그 정보 기록 파일'; $lang->about_debug_log_filename = '파일명에 YYYYMMDD가 포함된 경우 날짜별로 파일을 분리하여 기록합니다.
파일을 분리하지 않으면 용량이 매우 커질 수 있으니 주의하십시오.'; $lang->msg_debug_log_filename_not_writable = '지정한 경로에 로그 파일을 작성할 수 없습니다.'; $lang->debug_allowed_ip = '디버그 허용 IP'; +$lang->seo_main_title = '메인화면 제목'; +$lang->about_seo_main_title = '사이트 메인 화면에 표시되는 제목 형태입니다. 아래와 같은 변수를 사용할 수 있습니다.
$SITE_TITLE (사이트 제목), $SITE_SUBTITLE (사이트 부제목), $SUBPAGE_TITLE (서브페이지 제목)'; +$lang->seo_subpage_title = '서브페이지 제목'; +$lang->about_seo_subpage_title = '문서 목록, 페이지 등 주요 메뉴를 방문하면 표시되는 제목 형태입니다. 위의 변수들과 함께 $PAGE (페이지)도 사용할 수 있습니다.'; +$lang->seo_document_title = '개별 문서 페이지 제목'; +$lang->about_seo_document_title = '게시물을 읽는 화면에서 표시되는 제목 형태입니다. 위에 변수들과 함께 $DOCUMENT_TITLE (문서 제목)도 사용할 수 있습니다.'; +$lang->site_meta_keywords = 'SEO 키워드'; +$lang->about_site_meta_keywords = '별도의 키워드를 지정하지 않은 페이지에서는 이 키워드 목록이 표시됩니다.'; +$lang->site_meta_description = 'SEO 설명'; +$lang->about_site_meta_description = '별도의 설명을 지정하지 않은 페이지에서는 이 설명이 표시됩니다.'; +$lang->og_enabled = 'OpenGraph 태그 사용'; +$lang->og_extract_description = '본문에서 설명 추출'; +$lang->og_extract_description_fallback = '모듈 또는 사이트 전체 설명만 사용'; +$lang->og_extract_images = '본문에서 이미지 추출'; +$lang->og_extract_images_fallback = '사이트 대표 이미지 사용'; +$lang->og_use_timestamps = '글 작성/수정 시각 표시'; $lang->autoinstall = '쉬운 설치'; $lang->last_week = '지난주'; $lang->this_week = '이번주'; @@ -154,8 +176,8 @@ $lang->about_use_mobile_view = '모바일 기기로 접속시 모바일 페이 $lang->thumbnail_type = '썸네일 생성 방식'; $lang->input_footer_script = '하단(footer) 스크립트'; $lang->detail_input_footer_script = '최하단에 코드를 삽입합니다. 관리자 페이지에서는 수행되지 않습니다.'; -$lang->corp = 'Crop(잘라내기)'; -$lang->ratio = 'Ratio(비율 맞추기)'; +$lang->corp = 'Crop (잘라내기)'; +$lang->ratio = 'Ratio (비율 맞추기)'; $lang->admin_ip_allow = '관리자 로그인 허용 IP'; $lang->admin_ip_deny = '관리자 로그인 금지 IP'; $lang->local_ip_address = '로컬 IP 주소'; @@ -163,10 +185,12 @@ $lang->about_admin_ip_allow = '여기에 IP 주소를 나열하면 해당 IP에 $lang->about_admin_ip_deny = '여기에 나열된 IP 주소에서는 관리자 로그인이 금지됩니다.'; $lang->msg_current_ip_will_be_denied = '주어진 설정에 따르면 현재 로그인하신 관리자의 IP 주소도 차단됩니다. 다시 확인해 주십시오.'; $lang->detail_about_ftp_info = 'safe_mode = on 상태에서 쉬운설치를 사용하려면 FTP 정보를 입력해야 합니다.'; -$lang->allow_use_favicon = '파비콘 지정'; +$lang->allow_use_favicon = '파비콘'; $lang->about_use_favicon = '16x16 또는 32x32 크기의 ico 또는 png 파일을 권장합니다.'; $lang->allow_use_mobile_icon = '모바일 홈 화면 아이콘'; $lang->detail_use_mobile_icon = '57x57 또는 114x114 크기의 png 파일을 권장합니다.'; +$lang->cmd_site_default_image = '사이트 대표 이미지'; +$lang->about_site_default_image = 'SNS 등에 이 사이트가 링크되었을 때 표시되는 이미지입니다. 200x200 크기의 jpg 또는 png 파일을 권장합니다.'; $lang->use_sso = 'SSO 사용'; $lang->about_use_sso = '사용자가 한 번만 로그인하면 기본 사이트와 가상 사이트에 동시에 로그인이 됩니다. 가상 사이트를 사용할 때만 필요합니다.'; $lang->about_arrange_session = '세션을 정리하시겠습니까?'; diff --git a/modules/admin/tpl/config_advanced.html b/modules/admin/tpl/config_advanced.html index cdfc01614..85619aab7 100644 --- a/modules/admin/tpl/config_advanced.html +++ b/modules/admin/tpl/config_advanced.html @@ -58,6 +58,19 @@ +
+ +
+ + +
+
diff --git a/modules/admin/tpl/config_general.html b/modules/admin/tpl/config_general.html index 76f7bc620..a865bd9d2 100644 --- a/modules/admin/tpl/config_general.html +++ b/modules/admin/tpl/config_general.html @@ -11,13 +11,19 @@
- +
- +
- + +
+ +
+
+
+
@@ -81,25 +87,12 @@
-
- -
- - -
-

- favicon - favicon Image + Favicon + Favicon

@@ -132,6 +125,24 @@ {$lang->detail_use_mobile_icon}
+
+ +
+

+ Default Image +

+ + + + +

+ + +

+ + {$lang->about_site_default_image} +
+
@@ -142,10 +153,10 @@ diff --git a/modules/admin/tpl/js/admin.js b/modules/admin/tpl/js/admin.js index 0eee8ae5b..a7e498e7a 100644 --- a/modules/admin/tpl/js/admin.js +++ b/modules/admin/tpl/js/admin.js @@ -1627,7 +1627,7 @@ jQuery(function($){ $textareas.each(function(){ var $this = $(this); var value = data.langs[$this.data('lang')]; - var pattern = /^\$user_lang->/; + var pattern = /^\$user_lang-(?:>|&(?:amp;)?gt;)/; if(pattern.test(value)){ $this.val('').data('value', ''); @@ -1911,7 +1911,7 @@ jQuery(function($){ //var $displayInput = $this.siblings('.lang_code'); if($displayInput.data('active')){ - $multilingualWindow.trigger('before-open.g11n', $displayInput.prev('.lang_code').val().replace('$user_lang->', '')); + $multilingualWindow.trigger('before-open.g11n', $displayInput.prev('.lang_code').val().replace(/\$user_lang-(?:>|&(?:amp;)?gt;)/, '')); }else{ $multilingualWindow.trigger('before-open.g11n'); } @@ -1964,7 +1964,7 @@ jQuery(function($){ // load value function loadValue(){ reset(); - var pattern = /^\$user_lang->/; + var pattern = /^\$user_lang-(?:>|&(?:amp;)?gt;)/; function on_complete2(data){ if(!data || !data.langs) return; @@ -1977,7 +1977,7 @@ jQuery(function($){ if(pattern.test($displayInput.val())){ $.exec_json('module.getModuleAdminLangCode', { - 'name': $displayInput.val().replace('$user_lang->', ''), + 'name': $displayInput.val().replace(pattern, ''), 'mid': current_url.getQuery('mid') }, on_complete2); } diff --git a/modules/admin/tpl/layout.html b/modules/admin/tpl/layout.html index 06f1a97cb..12ca3ea4b 100644 --- a/modules/admin/tpl/layout.html +++ b/modules/admin/tpl/layout.html @@ -1,5 +1,8 @@
+
+

{$lang->msg_warning} {$lang->msg_blacklisted_module}

+
{$content}
diff --git a/modules/board/board.admin.controller.php b/modules/board/board.admin.controller.php index 9218bcee3..dfe68ab91 100644 --- a/modules/board/board.admin.controller.php +++ b/modules/board/board.admin.controller.php @@ -49,6 +49,10 @@ class boardAdminController extends board { if($args->protect_content!= 'Y') $args->protect_content = 'N'; if(!in_array($args->order_target,$this->order_target) && !array_key_exists($args->order_target, $extra_order_target)) $args->order_target = 'list_order'; if(!in_array($args->order_type, array('asc', 'desc'))) $args->order_type = 'asc'; + + $args->browser_title = trim(utf8_normalize_spaces($args->browser_title)); + $args->meta_keywords = $args->meta_keywords ? implode(', ', array_map('trim', explode(',', $args->meta_keywords))) : ''; + $args->meta_description = trim(utf8_normalize_spaces($args->meta_description)); // if there is an existed module if($args->module_srl) { diff --git a/modules/board/board.view.php b/modules/board/board.view.php index c6db99834..43761aa77 100644 --- a/modules/board/board.view.php +++ b/modules/board/board.view.php @@ -317,7 +317,16 @@ class boardView extends board else { // add the document title to the browser - Context::addBrowserTitle($oDocument->getTitleText()); + Context::setCanonicalURL($oDocument->getPermanentUrl()); + $seo_title = config('seo.document_title') ?: '$SITE_TITLE - $DOCUMENT_TITLE'; + getController('module')->replaceDefinedLangCode($seo_title); + Context::setBrowserTitle($seo_title, array( + 'site_title' => Context::getSiteTitle(), + 'site_subtitle' => Context::getSiteSubtitle(), + 'subpage_title' => $module_info->browser_title, + 'document_title' => $oDocument->getTitleText(), + 'page' => Context::get('page') ?: 1, + )); // update the document view count (if the document is not secret) if(!$oDocument->isSecret() || $oDocument->isGranted()) diff --git a/modules/board/tpl/board_insert.html b/modules/board/tpl/board_insert.html index d7b3ae8da..39a4ab1b3 100644 --- a/modules/board/tpl/board_insert.html +++ b/modules/board/tpl/board_insert.html @@ -29,6 +29,18 @@
+
+ +
+ +
+
+
+ +
+ +
+
diff --git a/modules/document/document.item.php b/modules/document/document.item.php index 9b38b216a..c50d8accc 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -626,7 +626,7 @@ class documentItem extends Object function getPermanentUrl() { - return getFullUrl('','document_srl',$this->get('document_srl')); + return getFullUrl('', 'mid', $this->getDocumentMid(), 'document_srl', $this->get('document_srl')); } function getTrackbackUrl() diff --git a/modules/page/page.admin.controller.php b/modules/page/page.admin.controller.php index 5255b972a..9e130dcd6 100644 --- a/modules/page/page.admin.controller.php +++ b/modules/page/page.admin.controller.php @@ -31,6 +31,10 @@ class pageAdminController extends page unset($args->page_name); if($args->use_mobile != 'Y') $args->use_mobile = ''; + $args->browser_title = trim(utf8_normalize_spaces($args->browser_title)); + $args->meta_keywords = $args->meta_keywords ? implode(', ', array_map('trim', explode(',', $args->meta_keywords))) : ''; + $args->meta_description = trim(utf8_normalize_spaces($args->meta_description)); + // Check if an original module exists by using module_srl if($args->module_srl) { diff --git a/modules/page/tpl/page_info.html b/modules/page/tpl/page_info.html index c61bb5298..c64ec02c8 100644 --- a/modules/page/tpl/page_info.html +++ b/modules/page/tpl/page_info.html @@ -39,6 +39,18 @@
+
+ +
+ +
+
+
+ +
+ +
+