sebr Posted September 23, 2021 Share Posted September 23, 2021 Hi 1. By default, every fields in page are lang tabs UI. If I click on folder icon on top right of a field, the lang versions of this fields are extending. I see all version of this lang for this field. My client would like to have this behavior by default on some templates. Is there a simple way to do that ? Hook or just a Javascript added in Admin ? 2. Is there a solution to allow the publication of a page only if the mandatory fields are filled in for all languages? Thanks in advance for your help 1 Link to comment Share on other sites More sharing options...
AndZyk Posted September 23, 2021 Share Posted September 23, 2021 Hi @sebr, 1. You could just uninstall the core module "Languages Support - Tabs". But this would disable all language tabs. ? 2. Required fields should prevent you from publishing the page if not filled out. But I think it only works for the default language. Regards, Andreas 2 Link to comment Share on other sites More sharing options...
Zeka Posted September 23, 2021 Share Posted September 23, 2021 Hi @sebr As for the first point. You can copy LanguageTabs module to the site/modules folder and adopt for you needs. As for the second point. There is no ready to use solutions but it doable by hooks. I've been working on the two module. One that allows to disable default language and the second one that add reuquirement for non default langauges of multilangauge fields and check if they are filled. They are site specific but you can use them as starting point and try to addot for your needs. Spoiler <?php namespace ProcessWire; /** * LanguageDisableDefaultLanguage Module */ class LanguageDisableDefaultLanguage extends WireData implements Module { /** * Return information about the module * */ static public function getModuleInfo() { return array( 'title' => 'Disable Default Language', 'version' => 100, 'summary' => 'Adds support for disabling default language per page', 'author' => 'Eugene Briukov', 'autoload' => true, 'singular' => true, 'requires' => array( 'LanguageSupportPageNames', 'LanguageSupport', ), ); } public function init() { $defaultLang = $this->wire('languages')->getDefault(); $fields = $this->wire('fields'); $fields->setNative("status$defaultLang"); $this->addHookAfter('PageFinder::getQuery', $this, 'hookPageFinderGetQuery'); $this->addHookAfter('Page::viewable', $this, 'hookPageViewable', [ 'priority' => 200 ]); } public function ready() { $this->wire('pages')->addHookAfter('saveReady', $this, 'hookPageSaveReady'); $page = $this->wire('page'); if ($page->template == 'admin' && $page->process && in_array('WirePageEditor', wireClassImplements($page->process))) { if (!in_array('ProcessPageType', wireClassParents($page->process))) { $this->addHookBefore('InputfieldPageName::render', $this, 'hookInputfieldPageNameRenderBefore'); $this->addHookAfter('InputfieldPageName::processInput', $this, 'hookInputfieldPageNameProcess'); } } } public function hookPageFinderGetQuery(HookEvent $event) { $query = $event->return; $pageFinder = $event->object; $options = $pageFinder->getOptions(); if (!empty($options['findAll'])) return; if (!$this->wire('pages')->outputFormatting) return; $language = $this->wire('user')->language; if (!$language || !$language->isDefault()) return; $status = "status" . (int)$language->id; $query->where("pages.$status>0"); } public function hookPageViewable(HookEvent $event) { if (!$event->return) return; $page = $event->object; $languages = $this->wire('languages'); $input = $this->wire('input'); $path = $input->url(); $language = $event->arguments(0); $defaultLanguage = $languages->getDefault(); ($language == $defaultLanguage) ?: $language = $this->wire('modules')->get('LanguageSupportPageNames')->getPagePathLanguage($path, $page); if ($defaultLanguage != $language) return; $status = $page->get("status$defaultLanguage"); $event->return = $status > 0; } public function hookInputfieldPageNameRenderBefore(HookEvent $event) { /** @var InputfieldPageName $inputfield */ $inputfield = $event->object; $page = $this->process instanceof WirePageEditor ? $this->process->getPage() : $this->wire('pages')->newNullPage(); if (!$page->id && $inputfield->editPage) $page = $inputfield->editPage; $template = $page->template ? $page->template : null; if ($template && $template->noLang) return; $languages = $this->wire('languages'); $trackChanges = $inputfield->trackChanges(); $inputfield->setTrackChanges(false); $checkboxLabel = $this->_('Active?'); $editable = true; if ($page->id && !$page->editable('name', false)) $editable = false; $language = $this->wire('user')->language; $inputfield->checkboxName = "status" . $language->id; $inputfield->checkboxValue = 1; $inputfield->checkboxLabel = $checkboxLabel; if ($page->id > 0) { $inputfield->checkboxChecked = $page->get($inputfield->checkboxName) > 0; } else if ($inputfield->parentPage) { $inputfield->checkboxChecked = $inputfield->parentPage->get($inputfield->checkboxName) > 0; } if (!$editable) $inputfield->attr('disabled', 'disabled'); $inputfield->setTrackChanges($trackChanges); } public function hookPageSaveReady(HookEvent $event) { /** @var Page $page */ $page = $event->arguments[0]; /** @var Pages $pages */ $pages = $event->object; /** @var Sanitizer $sanitizer */ $sanitizer = $this->wire('sanitizer'); /** @var array $extraData */ $extraData = $event->return; $alwaysActiveTypes = array( 'User', 'UserPage', 'Role', 'RolePage', 'Permission', 'PermissionPage', 'Language', 'LanguagePage', ); if (!is_array($extraData)) $extraData = array(); foreach ($this->wire()->languages as $language) { if (!$language->isDefault()) continue; $language_id = (int)$language->id; $name = "status$language_id"; if (method_exists($page, 'getForPage')) { $value = (int)$page->getForPage()->get($name); } else if (in_array($page->className(), $alwaysActiveTypes)) { // User, Role, Permission or Language: assume active status $value = Page::statusOn; } else { // regular page $value = (int)$page->get($name); } $extraData[$name] = $value; } $event->return = $extraData; } public function hookInputfieldPageNameProcess(HookEvent $event) { $inputfield = $event->object; $process = $this->process; $page = $process instanceof WirePageEditor ? $process->getPage() : new NullPage(); if ($page->id && !$page->editable('name', false)) return; // name is not editable $input = $event->arguments[0]; $languages = $this->wire('languages'); foreach ($languages as $language) { if (!$language->isDefault()) continue; if (!$languages->editable($language)) continue; $key = "status" . (int)$language->id; $value = (int)$input->{"$key$inputfield->checkboxSuffix"}; if ($page->get($key) != $value) { $inputfield->trackChange($key); $inputfield->trackChange('value'); if ($page->id) $page->set($key, $value); else $page->setQuietly($key, $value); } } } /** * Install the module * */ public function ___install() { $languages = $this->wire('languages'); $defaultLanguage = $languages->getDefault(); if (!$defaultLanguage->id || $defaultLanguage->name != 'default') return; if ($defaultLanguage instanceof Language && $languages->findNonDefault()->has($defaultLanguage)) return; $status = "status" . (int)$defaultLanguage->id; $database = $this->wire('database'); try { $database->exec("ALTER TABLE pages ADD $status INT UNSIGNED NOT NULL DEFAULT " . Page::statusOn); } catch (\Exception $e) { $this->error($e->getMessage(), Notice::log); } } /** * Uninstall the module * */ public function ___uninstall() { $defaultLanguage = $this->wire('languages')->getDefault(); $status = "status" . (int)$defaultLanguage->id; $database = $this->wire('database'); try { $database->exec("ALTER TABLE pages DROP $status"); } catch (\Exception $e) { // $this->error($e->getMessage(), Notice::log); // error message can be ignored here } } } Spoiler <?php namespace ProcessWire; /** * LanguageFieldRequiredCheck Module */ class LanguageFieldRequiredCheck extends WireData implements Module { /** * Return information about the module * */ static public function getModuleInfo() { return array( 'title' => 'Language Field Required Check Per Language', 'version' => 100, 'summary' => 'Multi-language field required check', 'author' => 'Eugene Briukov', 'autoload' => true, 'singular' => true, 'requires' => array( 'LanguageSupportPageNames', 'LanguageDisableDefaultLanguage', 'LanguageSupport', ), ); } public function ready() { $this->addHook('Inputfield::getEmptyLanguages', $this, 'getEmptyLanguages'); $this->addHookAfter('InputfieldWrapper::getEmptyForLanguages', $this, 'getEmptyForLanguages'); $this->addHookAfter('InputfieldWrapper::processInput', $this, 'InputfieldWrapperProcessInputAfter'); $this->addHookAfter('InputfieldRepeater::processInput', $this, 'InputfieldRepeaterProcessInputAfter'); $this->addHookMethod('Inputfield::isEmptyForLanguages', $this, 'isEmptyForLanguages'); // $this->wire->addHookAfter('ProcessPageListRender::getPageLabel', $this, 'getPageLabel'); } // public function getPageLabel(HookEvent $event) // { // $page = $event->arguments[0]; // // if ($page->template->name === 'country') { // $pageLanguages = $page->getLanguages(); // $languages = $this->wire('languages'); // $defaultLanguage = $this->wire('languages')->getDefault(); // $return = ''; // // foreach ($languages as $language) { // $class = $pageLanguages->has($language) ? 'uk-label-success' : 'uk-label-warning'; // $return .= "<span class='uk-badge $class'>" . substr($language->get('title|name'), 0, 2) . "</span>"; // } // $page->setOutputFormatting(false); // $defaultLanguageTitle = $page->get('title')->getLanguageValue($defaultLanguage); // // if(!strlen("$defaultLanguageTitle")) { // $event->return = $page->get('title')->getLanguageValue($pageLanguages->first()); // $page->setOutputFormatting(true); // } // // $event->return = $return . $event->return; // } // // } public function getEmptyForLanguages(HookEvent $event) { $wrapper = $event->object; $languages = $event->arguments(0); $required = $event->arguments(1) ?: false; if (!$languages && !count($languages)) $languages = $this->wire('languages'); $a = array(); static $n = 0; foreach($wrapper->children() as $child) { if($child instanceof InputfieldWrapper) { $a = array_merge($a, $child->getEmpty($required)); } else { if($required && !$child->getSetting('required')) continue; if(!$child->isEmptyForLanguages($languages)) continue; $name = $child->attr('name'); if(empty($name)) $name = "_unknown" . (++$n); $a[$name] = $child; } } $event->return = $a; } public function isEmptyForLanguages(HookEvent $event) { $inputfield = $event->object; $post = $this->wire('input')->post(); $languages = $event->arguments(0); if (!$languages && !count($languages)) $languages = $this->wire('languages'); $empty = false; foreach ($languages as $language) { if ($language->isDefault()) { $value = $post->get($inputfield->name); } else { $value = $post->get($inputfield->name . '__' . $language->id); } if (is_array($value)) { if (count($value) == 0) $empty = true; } elseif (!strlen("$value")) $empty = true; } $event->return = $empty; } public function getEmptyLanguages(HookEvent $event) { $inputfield = $event->object; if (!$inputfield->getSetting('useLanguages')) return; if (!$inputfield->getSetting('required')) return; $languages = $this->wire('languages'); $post = $this->wire('input')->post(); $emptyLanguages = []; $forLanguages = $this->getActiveLanguages(); foreach ($languages as $language) { if (count($forLanguages) && $forLanguages->has($language)) { if ($language->isDefault()) { $value = $post->get($inputfield->name); } else { $value = $post->get($inputfield->name . '__' . $language->id); } if (is_array($value)) { if (count($value) == 0) $emptyLanguages[$language->id] = $language->get('title|name'); } elseif (!strlen("$value")) { $emptyLanguages[$language->id] = $language->get('title|name'); } } } $event->return = $emptyLanguages; } public function InputfieldRepeaterProcessInputAfter(HookEvent $event) { $repeater = $event->object; $repeater->getErrors(true); $input = $event->arguments(0); $value = $repeater->attr('value'); foreach($value as $key => $page) { $pageIDs[] = $page->id; $wrapper = $repeater->getWrappers($page->id); $wrapper->getErrors(true); $wrapper->processInput($input); $numRequiredEmpty = count($wrapper->getEmptyForLanguages($this->getActiveLanguages(), true)); if($numRequiredEmpty) { $repeater->error(sprintf($this->_('Errors in “%s” item %d'), $repeater->label, $key + 1)); $openIDs[$page->id] = $page->id; } else if(isset($openIDs[$page->id])) { unset($openIDs[$page->id]); } } } public function InputfieldWrapperProcessInputAfter(HookEvent $event) { $wrapper = $event->object; if (!$wrapper->children()->count()) return; $input = $event->arguments(0); $emptyFields = $wrapper->getEmptyForLanguages($this->wire('languages'), true); foreach ($emptyFields as $emptyField) { if($emptyField->getSetting('useLanguages') && $emptyField->getSetting('required')) { $emptyField->getErrors(true); } } foreach ($wrapper->children() as $key => $child) { // skip over the field if it is not processable if (!$wrapper->isProcessable($child)) continue; // pass along the dependencies value to child wrappers if ($child instanceof InputfieldWrapper && $wrapper->getSetting('useDependencies') === false) { $child->set('useDependencies', false); } if($child->getSetting('useLanguages') || $child instanceof InputfieldWrapper) { $child->processInput($input); } if ($child->name && $child->getSetting('useLanguages') && $child->getSetting('required') && $child->isEmptyForLanguages($this->getActiveLanguages())) { $child->getErrors(true); $emptyLanguages = $child->getEmptyLanguages(); if (count($emptyLanguages)) $child->error(sprintf(__('Missing required value for %1$s language(s)'), implode(', ', $emptyLanguages))); } } } protected function getActiveLanguages() { $post = $this->wire('input')->post; $languages = $this->wire('languages'); $activeLanguages = new PageArray(); foreach ($languages as $language) { if ($post->get("status$language")) $activeLanguages->add($language); } return $activeLanguages; } } 2 Link to comment Share on other sites More sharing options...
sebr Posted September 23, 2021 Author Share Posted September 23, 2021 Hi @AndZyk and @Zeka Thanks for these solutions. The first solution (disable Languages Support - Tabs) will indeed impact the entire back office, regardless of the template. But as said Zeka, I can fork and adapt this module. Zeka, thanks a lot for your codes. I will see how to get inspired to achieve my goal. Have a nice day Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now