Допустим сайт объявлений с 2-мя словарями: города и услуги.
Есть ли в Drupal 8 возможность создания страниц на основании этих словарей?
Не в смысле создать ноды и указывать в них 2 словаря, а в мысле, что создаем новый термин Грузоперевозки. И сразу же есть страницы:
Грузоперевозки в Москве
Грузоперевозки в Твери
Грузоперевозки в Саратове
Если добавить новый регион - добавятся все услуги в этом регионе:
Выгул собак в Регионе
Проведение праздников в Регионе
Комментарии
Ох уже эти SEO-задачки
Заюзай хук создания нового термина. Там получай список городов и создавай ноды в цикле
Аргументы умел вьюс даже в пятом друпале.
А в шестом и панели.
В седьмом умели почти все.
А восьмой умеет всё.
Жди девятого, он сам за тебя всё сделает
Не очень понятно что понимается под "страницами".
Делается вьюха с двумя контекстными фильтрами. В принципе вызов вьюхи с любым сочетанием значений этих двух фильтров есть новая "страница". То есть создавать-то ничего и не надо, кроме одной вьюхи и двух словарей. Ну и само собой самих предложений услуг в виде типа материала с двумя ER-полями на эти словари.
Да, нужна вьюха с двумя аргументами. Но если нужны ещё и красивые урлы, то можно к примеру в препроцессе вьюхи менять урлы на алиасы, создавая их, если их нет.
PS: не факт, что красивые урлы сейчас хоть как-то влияют на сео, т.к. во всю идут разговоры о том, чтобы в браузере по умолчанию показывать только домен.
Но есть же ещё хлебные крошки, которые на основе урлов по умолчанию строятся.
Плюс в браузере - да. Но ссылку же можно копировать и куда-то вставить, например в документ и там она уже вся видна будет.
На крошки можно свой билдер сделать и воротить, что угодно.
Что касается того, что ссылка всё же видна при копировании - это вообще пофиг. Среди людей старше сорока большинство даже не знает, что такое ссылка. А каждый третий не знает, что такое браузер, хоть и пользуется им каждый день. И вот реально очень сомнительно, что поисковики могут учитывать при ранжировании столь малозначительный фактор, который в принципе может увидеть только кучка задротов вроде нас.
Можно делать через аргументы + например https://www.drupal.org/project/views_pretty_path
Допустим мне нужно не столько фильтр, сколько страницы. Вот вьюха. Выводит материалы по термину (список заказов в городе).


Все работает, если перейти на адрес
sitename.com/zakazy/3257
что сделать, чтобы работало по адресу
sitename.com/zakazy/moskva
?
Views URL Path Arguments не поможет?
Может и поможет, но пока не понял как. Установил. Во вьюхе выше указал:


sitename.com/zakazy/moskva не находит ничего
А moskva точно является path alias для 3257?
moskva - урл термина с этим ИД
Значит не повезло...
В описании упомянуто, что должно работать с nodes, а про термины ничего не сказано. При этом в коде не вижу никаких завязок на node, то есть по идее должно бы работать...
Я глянул в код модуля - там ошибка дурацкая. Попробуй заменить содержимое файла src/Plugin/views/argument_validator/UrlPath.php вот на этот код:
namespace Drupal\views_url_path_arguments\Plugin\views\argument_validator;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\views\Plugin\views\argument_validator\ArgumentValidatorPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Convert an entity id to its url path.
*
* @ViewsArgumentValidator(
* id = "views_url_path",
* title = @Translation("Entity ID from URL path alias")
* )
*/
class UrlPath extends ArgumentValidatorPluginBase {
/**
* The route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Language manager for retrieving the default langcode when none is specified.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Constructs a new Tid instance.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $pluginId
* The plugin_id for the plugin instance.
* @param mixed $pluginDefinition
* The plugin implementation definition. *
* @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch
* The route match.
* @param \Drupal\Core\Language\LanguageManagerInterface $languageManager
* The language manager.
*/
public function __construct(array $configuration, $pluginId, $pluginDefinition, RouteMatchInterface $routeMatch, LanguageManagerInterface $languageManager) {
parent::__construct($configuration, $pluginId, $pluginDefinition);
$this->routeMatch = $routeMatch;
$this->languageManager = $languageManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
return new static(
$configuration,
$pluginId,
$pluginDefinition,
$container->get('current_route_match'),
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['provide_static_segments'] = ['default' => TRUE];
$options['segments'] = ['default' => ''];
return $options;
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $formState) {
$form['provide_static_segments'] = [
'#type' => 'checkbox',
'#title' => $this->t('Provide a static url segment as the prefix to the alias?'),
'#default_value' => $this->options['provide_static_segments'],
];
$form['segments'] = [
'#type' => 'textfield',
'#title' => $this->t('Segments'),
'#description' => $this->t('Without leading and/or trailing slashes.'),
'#default_value' => $this->options['segments'],
'#states' => [
'visible' => [
':input[name="options[argument_default][views_url_path][provide_static_segments]"]' => ['checked' => TRUE],
],
],
];
}
/**
* {@inheritdoc}
*/
public function validateArgument($argument) {
// Is it already the entity id?
if (ctype_digit($argument)) {
$this->argument->argument = $argument;
return TRUE;
}
$alias = '/';
if ($this->options['provide_static_segments']) {
$alias .= $this->options['segments'] . '/';
}
$alias .= $argument;
$langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId();
$canonicalPath = '';
if (\Drupal::hasService('path_alias.repository')) {
if ($alias = \Drupal::service('path_alias.repository')->lookupByAlias($alias, $langcode)) {
$canonicalPath = $alias['path'];
}
}
else {
$canonicalPath = \Drupal::service('path.alias_storage')->lookupPathSource($alias, $langcode);
}
$entity_id = substr($canonicalPath, strrpos($canonicalPath, '/') + 1);
if (ctype_digit($entity_id)) {
$this->argument->argument = $entity_id;
return TRUE;
}
else {
return FALSE;
}
}
}
Если заработает, сделаю патч и закину на орг.
Послал патч на орг и его немедленно закомиттили в dev, так что теперь уж проще установить dev.
Поставил дев версию. update.php/selection пишет:
Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mydb.url_alias' doesn't exist: SELECT ua.source AS source, ua.alias AS alias FROM {url_alias} ua; Array ( ) in views_url_alias_rebuild() (line 214 of modules\contrib\views_url_alias\views_url_alias.module).
views_url_alias_rebuild()
views_url_alias_rebuild', Array) (Line: 403)call_user_func_array('
Drupal\Core\Extension\ModuleHandler->invokeAll('rebuild') (Line: 1079)
drupal_flush_all_caches() (Line: 350)
Drupal\system\Controller\DbUpdateController->selection(Object) (Line: 164)
Drupal\system\Controller\DbUpdateController->handle('selection', Object)
call_user_func_array(Array, Array) (Line: 115)
Drupal\Core\Update\UpdateKernel->handleRaw(Object) (Line: 76)
Drupal\Core\Update\UpdateKernel->handle(Object) (Line: 28)
Изменений не вижу. На моем последнем скрине никаких галок снимать ставить не надо?
Контекстный фильтр и путь вьюхи правильно прописаны?
Упс, значит совет поставить дев был неправильным - там что-то ещё наколбашено... А если всё же поставить мой патч на релиз? Там всего-то нужно убрать несколько символов в двух местах, из которых нам важно одно.
У меня работает. Настройки правильные за исключением последней галки "Provide a static URL segment", которая кстати может и быть причиной неработы! Я бы прежде всего попробовал убрать дев, вернуть релиз и для начала просто убрать лишнюю галку. На свежей версии ядра может заработать и без моего патча (я пробовал на 8.6 где всё немножко иначе с алиасами).
Спасибо, marassa!
Ваш патч уже в последней желтой версии и все работает!
Попробовал этим модулем сделать вьюху берущую аргументы от 2-х словарей (тип работ и регион).
Путь вьюхе оставил тот же: zakazy/%taxonomy_term и ввожу еще один аналогичный контекстный фильтр.
После этого становятся доступными страницы:
zakazy/moskva
zakazy/gruzopervozki
zakazy/moskva/gruzopervozki
zakazy/gruzopervozki/moskva
Надеюсь эту возможность не уберут в следующих версиях.
Недавно связывал два словаря. Ссылка типа /brands/alias_brand/alias_catalog
В общем дали мне вьюху где через агрегацию и php поле были сформированы ссылки:
<?php print drupal_get_path_alias("taxonomy/term/$row->tid"); ?>
<?php
$full_url = drupal_get_path_alias("taxonomy/term/$row->tid_1");
$url_array = explode('/',$full_url);
echo '/'.$url_array['1'];
if (!empty($url_array['2'])) {echo '/'.$url_array['2'];}
if (!empty($url_array['3'])) {echo '/'.$url_array['3'];}
if (!empty($url_array['4'])) {echo '/'.$url_array['4'];}
?>
А так как views работать любит с tid, то потребовалось по алиасу выловить ИД термина и вместо алиаса с сформированной ссылки в аргумент поставить ИД термина
<?php
/*
* hook_views_pre_view
*/
function custom_views_pre_view(&$view, &$display_id, &$args)
{
if ($view->name == 'brand_facet' && $view->current_display == 'page_2') {
$arg = arg();
$view->args[0] = custom_viewsarg_viewsbrand_brand($arg);
$view->args[1] = custom_viewsarg_viewsbrand_catalog($arg);
}
} //Поиск ид термина для аргумента 1 /brands/%/%
function custom_viewsarg_viewsbrand_brand($arg) {
$brand_sin = 'brands/'.$arg[1];
foreach ($arg as $ar_k) {
if (!preg_match("#^[aA-zZ0-9\-_]+$#",$ar_k)) {
exit('error adress');
}
}
$result = db_select('url_alias', 'n')
->fields('n', array('source'))
->condition('n. alias', $brand_sin)
->execute()
->fetchField();
if(isset($result) and !empty($result)) {
$term_sourse = explode('/', $result);
return $term_sourse[2];
}
return;
}
?>
Рецепт от marassa, оказался более чем работоспособен, но я еще перебираю варианты.
https://www.drupal.org/project/page_manager - кто нибудь использовал для подобных или других задач?
Использовал раньше. Проблем с ним довольно много, но вообще работает.