public function registerTagCombination($blogKey, $tags) { if (!is_array($tags)) { // Temporary warning for a change in how multi-tags // are specified. $log = $this->pieCrust->getEnvironment()->getLog(); if (strpos($tags, '/') !== false) { $log->warning("A link to tag {$tags} was specified in this page. " . "If this is a tag that contains a slash character ('/') then ignore this warning. " . "However, if this was intended to be a multi-tags link, you'll need to " . "now pass an array of tags like so: `{{pctagurl(['tag1', 'tag2'])}}`. " . "Your current link won't work!"); } return; } if ($blogKey == null) { $blogKey = PieCrustDefaults::DEFAULT_BLOG_KEY; } if (!array_key_exists($blogKey, $this->tagCombinations)) { $this->tagCombinations[$blogKey] = array(); } // Slugify tags and sort them alphabetically. $flags = $this->pieCrust->getConfig()->getValue('site/slugify_flags'); $tags = array_map(function ($t) use($flags) { return UriBuilder::slugify($t, $flags); }, $tags); sort($tags); // Only add combination if it's not already there. if (!in_array($tags, $this->tagCombinations[$blogKey])) { $this->tagCombinations[$blogKey][] = $tags; } }
/** * @dataProvider tagSlugifyDataProvider */ public function testTagSlugify($value, $expectedValue, $slugifyMode = null, $locale = null) { $fs = MockFileSystem::create(); if ($slugifyMode) { $fs->withConfig(array('site' => array('slugify' => $slugifyMode))); } $pc = $fs->getApp(); $flags = $pc->getConfig()->getValue('site/slugify_flags'); $actualValue = UriBuilder::slugify($value, $flags); $this->assertEquals($expectedValue, $actualValue); }
public function addPageClauses(IPage $page, array $userFilterInfo = null) { // If the current page is a tag/category page, add filtering // for that. $pageClause = null; $pieCrust = $page->getApp(); $flags = $pieCrust->getConfig()->getValue('site/slugify_flags'); switch ($page->getPageType()) { case IPage::TYPE_TAG: $pageKey = $page->getPageKey(); if (is_array($pageKey)) { $pageClause = new AndBooleanClause(); foreach ($pageKey as $k) { $pageClause->addClause(new HasFilterClause('tags', $k, function ($t) use($flags) { return UriBuilder::slugify($t, $flags); })); } } else { $pageClause = new HasFilterClause('tags', $pageKey, function ($t) use($flags) { return UriBuilder::slugify($t, $flags); }); } break; case IPage::TYPE_CATEGORY: $pageClause = new IsFilterClause('category', $page->getPageKey(), function ($c) use($flags) { return UriBuilder::slugify($c, $flags); }); break; } if ($pageClause != null) { // Combine the default page filters with some user filters, // if any. if ($userFilterInfo != null) { $combinedClause = new AndBooleanClause(); $combinedClause->addClause($pageClause); $this->addClausesRecursive($userFilterInfo, $combinedClause); $this->addClause($combinedClause); } else { $this->addClause($pageClause); } } }
/** * Builds the URL of a category listing. */ public static function buildCategoryUri(IPieCrust $pieCrust, $blogKey, $category, $slugify = true) { $categoryUrlFormat = $pieCrust->getConfig()->getValue($blogKey . '/category_url'); if ($slugify) { $flags = $pieCrust->getConfig()->getValue('site/slugify_flags'); $category = UriBuilder::slugify($category, $flags); } return str_replace('%category%', $category, $categoryUrlFormat); }
private static function tryParseCategoryUri(IPieCrust $pieCrust, $blogKey, $uri, array &$pageInfo) { $blogKeyDir = ''; if ($blogKey != PieCrustDefaults::DEFAULT_BLOG_KEY) { $blogKeyDir = $blogKey . '/'; } $categoryPageName = array(); $themeCategoryPageName = array(); $autoFormats = $pieCrust->getConfig()->getValueUnchecked('site/auto_formats'); foreach ($autoFormats as $ext => $format) { $categoryPageName[] = $blogKeyDir . PieCrustDefaults::CATEGORY_PAGE_NAME . '.' . $ext; $themeCategoryPageName[] = PieCrustDefaults::CATEGORY_PAGE_NAME . '.' . $ext; } $path = PathHelper::getUserOrThemePath($pieCrust, $categoryPageName, $themeCategoryPageName); if ($path === false) { return false; } $flags = $pieCrust->getConfig()->getValueUnchecked('site/slugify_flags'); $categoryPattern = UriBuilder::buildCategoryUriPattern($pieCrust->getConfig()->getValueUnchecked($blogKey . '/category_url')); if (preg_match($categoryPattern, $uri, $matches)) { $cat = rawurldecode($matches['cat']); $cat = UriBuilder::slugify($cat, $flags); $pageInfo['type'] = IPage::TYPE_CATEGORY; $pageInfo['blogKey'] = $blogKey; $pageInfo['key'] = $cat; $pageInfo['path'] = $path; $pageInfo['was_path_checked'] = true; return true; } return false; }
protected function bakeTaxonomies() { // Get some global stuff we'll need. $slugifyFlags = $this->pieCrust->getConfig()->getValue('site/slugify_flags'); $pageRepository = $this->pieCrust->getEnvironment()->getPageRepository(); // Get the taxonomies. $taxonomies = array('tags' => array('multiple' => true, 'singular' => 'tag', 'page' => PieCrustDefaults::TAG_PAGE_NAME . '.html'), 'category' => array('multiple' => false, 'page' => PieCrustDefaults::CATEGORY_PAGE_NAME . '.html')); // Get which terms we need to bake. $allDirtyTaxonomies = $this->bakeRecord->getDirtyTaxonomies($taxonomies); $allUsedCombinations = $this->bakeRecord->getUsedTaxonomyCombinations($taxonomies); // Get the taxonomy listing pages, if they exist. $taxonomyPages = array(); $blogKeys = $this->pieCrust->getConfig()->getValue('site/blogs'); foreach ($taxonomies as $name => $taxonomyMetadata) { $taxonomyPages[$name] = array(); foreach ($blogKeys as $blogKey) { $prefix = ''; if ($blogKey != PieCrustDefaults::DEFAULT_BLOG_KEY) { $prefix = $blogKey . DIRECTORY_SEPARATOR; } $termPageName = $prefix . $taxonomyMetadata['page']; $themeTermPageName = $taxonomyMetadata['page']; $termPagePath = PathHelper::getUserOrThemePath($this->pieCrust, $termPageName, $themeTermPageName); $taxonomyPages[$name][$blogKey] = $termPagePath; } } foreach ($allDirtyTaxonomies as $name => $dirtyTerms) { $taxonomyMetadata = $taxonomies[$name]; foreach ($dirtyTerms as $blogKey => $dirtyTermsForBlog) { // Check that we have a term listing page to bake. $termPagePath = $taxonomyPages[$name][$blogKey]; if (!$termPagePath) { continue; } // We have the terms that need to be rebaked. $termsToBake = $dirtyTermsForBlog; // Look at the combinations of terms we need to consider. if ($taxonomyMetadata['multiple']) { // User-specified combinations. $forcedCombinations = array(); $forcedCombinationParameters = array($name . '_combinations'); if (isset($taxonomyMetadata['singular'])) { $forcedCombinationParameters[] = $taxonomyMetadata['singular'] . '_combinations'; } foreach ($forcedCombinationParameters as $param) { if (isset($this->parameters[$param])) { $forcedCombinations = $this->parameters[$param]; if (array_key_exists($blogKey, $forcedCombinations)) { $forcedCombinations = $forcedCombinations[$blogKey]; } elseif (count($blogKeys > 1)) { $forcedCombinations = array(); } break; } } // Collected combinations in use. $usedCombinations = array(); if (isset($allUsedCombinations[$name]) && isset($allUsedCombinations[$name][$blogKey])) { $usedCombinations = $allUsedCombinations[$name][$blogKey]; } // Get all the combinations together (forced and used) and keep // those that include a term that we have to rebake. $combinations = array_merge($forcedCombinations, $usedCombinations); if ($combinations) { $combinationsToBake = array(); foreach ($combinations as $comb) { if (count(array_intersect($comb, $termsToBake)) > 0) { $combinationsToBake[] = $comb; } } $termsToBake = array_merge($termsToBake, $combinationsToBake); } } // Order terms so it looks nice when we bake. usort($termsToBake, function ($t1, $t2) { if (is_array($t1)) { $t1 = implode('+', $t1); } if (is_array($t2)) { $t2 = implode('+', $t2); } return strcmp($t1, $t2); }); // Bake! foreach ($termsToBake as $term) { $start = microtime(true); if ($taxonomyMetadata['multiple'] && is_array($term)) { $slugifiedTerm = array_map(function ($t) use($slugifyFlags) { return UriBuilder::slugify($t, $slugifyFlags); }, $term); $formattedTerm = implode('+', array_map('rawurldecode', $term)); } else { $slugifiedTerm = UriBuilder::slugify($term, $slugifyFlags); $formattedTerm = rawurldecode($term); } if ($name == 'tags') { $uri = UriBuilder::buildTagUri($this->pieCrust, $blogKey, $slugifiedTerm, false); $pageType = IPage::TYPE_TAG; } else { if ($name == 'category') { $uri = UriBuilder::buildCategoryUri($this->pieCrust, $blogKey, $slugifiedTerm, false); $pageType = IPage::TYPE_CATEGORY; } } $page = $pageRepository->getOrCreatePage($uri, $termPagePath, $pageType, $blogKey); $page->setPageKey($slugifiedTerm); $this->callAssistants('onPageBakeStart', array($page)); $baker = $this->getPageBaker(); $baker->bake($page); $this->callAssistants('onPageBakeEnd', array($page, new BakeResult(true))); $pageCount = $baker->getPageCount(); $this->logger->info(self::formatTimed($start, "{$name}:{$formattedTerm}" . ($pageCount > 1 ? " [{$pageCount}]" : ""))); } } } }
/** * Gets the page's data for page rendering. * * It's better to call IPage::getData, which calls this function, because it * will also cache the results. It's useful for example when pagination * results needs to be re-used. */ public static function getPageData(IPage $page) { $pieCrust = $page->getApp(); $paginator = new Paginator($page); $assetor = new Assetor($page); $linker = new Linker($page); $recursiveLinker = new RecursiveLinkerIterator($linker); if ($page->getPaginationDataSource() != null) { $paginator->setPaginationDataSource($page->getPaginationDataSource()); } $data = array('page' => $page->getConfig()->get(), 'assets' => $assetor, 'pagination' => $paginator, 'siblings' => $linker, 'family' => $recursiveLinker); $data['page']['url'] = PieCrustHelper::formatUri($pieCrust, $page->getUri()); $data['page']['slug'] = $page->getUri(); $data['page']['timestamp'] = $page->getDate(true); $dateFormat = PageHelper::getConfigValueUnchecked($page, 'date_format', $page->getConfig()->getValueUnchecked('blog')); $data['page']['date'] = date($dateFormat, $page->getDate(true)); switch ($page->getPageType()) { case IPage::TYPE_TAG: if (is_array($page->getPageKey())) { $data['tag'] = implode(' + ', $page->getPageKey()); } else { $data['tag'] = $page->getPageKey(); } if (strpos($data['tag'], '-') >= 0) { // The tag may have been slugified. Let's cheat a bit by looking at // the first tag that matches in the first pagination post, and // using that instead. $paginationPosts = $paginator->posts(); if (count($paginationPosts) > 0) { $firstPost = $paginationPosts[0]; $firstPostTags = $firstPost['tags']; if (!is_array($firstPostTags)) { $firstPostTags = array($firstPostTags); } $flags = $pieCrust->getConfig()->getValue('site/slugify_flags'); if (is_array($page->getPageKey())) { $pageKey = $page->getPageKey(); foreach ($firstPostTags as $t) { $st = UriBuilder::slugify($t, $flags); foreach ($pageKey as &$pk) { if ($st == $pk) { $pk = $t; break; } } } if ($page->getPageKey() == null) { $page->setPageKey($pageKey); } $data['tag'] = implode(' + ', $pageKey); } else { foreach ($firstPostTags as $t) { if (UriBuilder::slugify($t, $flags) == $data['tag']) { if ($page->getPageKey() == null) { $page->setPageKey($t); } $data['tag'] = $t; break; } } } } } break; case IPage::TYPE_CATEGORY: $data['category'] = $page->getPageKey(); if (strpos($page->getPageKey(), '-') >= 0) { // Same remark as for tags. $paginationPosts = $paginator->posts(); if (count($paginationPosts) > 0) { $firstPost = $paginationPosts[0]; if ($page->getPageKey() == null) { $page->setPageKey($firstPost['category']); } $data['category'] = $firstPost['category']; } } break; } $extraData = $page->getExtraPageData(); if ($extraData) { if (is_array($extraData)) { $data = Configuration::mergeArrays($data, $extraData); } else { $data['extra'] = $extraData; } } return $data; }