Jump to content

Questions about admin with multi-lang


sebr
 Share

Recommended Posts

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

  • Like 1
Link to comment
Share on other sites

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

  • Like 2
Link to comment
Share on other sites

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.

chrome_ijXxx6axeF.thumb.jpg.403e70f3f18b282bda8a8435db6f24f2.jpg

508791436_chrome_WfEuhogMaN(1).thumb.jpg.6619ea4843d102e04cd4ff7c73920f0e.jpg

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;
	}
}

 

 

  • Like 2
Link to comment
Share on other sites

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...