gle string. * @since 1.8.0 */ public function getTestViews(PostBot $postBot, $postData, $viewVars = []) { // Get a valid instance from the given value $postSettings = $this->getPostSettingsImplInstanceFromPostBot($postBot); // Add views defined for the custom post details $postDetailViews = ''; $this->walkRegisteredFactories(function($factory) use (&$postData, &$postSettings, &$viewVars, &$postDetailViews) { /** @var BasePostDetailFactory $factory */ // Check availability if (!$factory->isAvailableForPost($postSettings)) return; $detailTester = $factory->getTester(); if (!$detailTester || !is_a($detailTester, BasePostDetailTester::class)) return; $detailView = $detailTester->getTesterView(); if (!$detailView) return; // Inject required variables to the view, render, and combine with other views $postDetailViews .= $detailView->with($viewVars)->with([ 'detailData' => $factory->getDetailData(), 'postData' => $postData, ])->render(); }, $postBot); return $postDetailViews; } /** * Adds site tester assets of each available detail factory * * @since 1.8.0 */ public function addSiteTesterAssets() { $this->walkRegisteredFactories(function($factory) { /** @var BasePostDetailFactory $factory */ $service = $factory->getService(); if (!$service || !is_a($service, BasePostDetailService::class)) return; $service->addSiteTesterAssets(); }); } /** * Get duplicate check options from the factories. * * @param SettingsImpl $postSettings * @return array|null An array having "values" and "defaults" keys, each having an array. If there is no option, * returns null. * @since 1.8.0 */ public function getDuplicateOptions(SettingsImpl $postSettings) { $allOptions = [ "values" => [], "defaults" => [], ]; $this->walkRegisteredFactories(function($factory) use (&$postSettings, &$allOptions) { /** @var BasePostDetailFactory $factory */ // Check availability if (!$factory->isAvailableForPost($postSettings)) return; // Get the duplicate checker $duplicateChecker = $factory->getDuplicateChecker(); if (!$duplicateChecker) return; // Get the options $options = $duplicateChecker->getOptions(); if (!$options) return; // Check for validity: // 1. Values must exist // 2. If defaults exist, they must have the same number of items as the values // 3. If defaults exist, the values and the defaults have to have the same keys. if (!isset($options["values"]) || (isset($options["defaults"]) && sizeof($options["values"]) !== sizeof($options["defaults"])) || (isset($options["defaults"]) && array_keys($options["values"]) !== array_keys($options["defaults"])) ) { return; } // Get the values $values = $options['values']; // Get the defaults and prepare if they do not exist $defaults = Utils::array_get($options, 'defaults'); if (!$defaults) { $defaults = []; foreach($values as $k => $v) { $defaults[$k] = 0; } } // Add the values and defaults to all options $allOptions["values"] = array_merge($allOptions["values"], $values); $allOptions["defaults"] = array_merge($allOptions["defaults"], $defaults); }); // If the values array is not empty, return the results. Otherwise, return null. return !empty($allOptions["values"]) ? $allOptions : null; } /** * Calls the deleters of the registered factories. * * @since 1.8.0 * @param SettingsImpl $postSettings * @param PostSaverData|null $saverData */ public function delete(SettingsImpl $postSettings, $saverData) { $this->walkRegisteredFactories(function($factory) use (&$postSettings, $saverData) { /** @var BasePostDetailFactory $factory */ // Check availability if (!$factory->isAvailableForPost($postSettings)) return; // Get the deleter $deleter = $factory->getDeleter(); if (!$deleter || !is_a($deleter, BasePostDetailDeleter::class)) return; // Check if the factory has any data $detailData = $factory->getDetailData(); if (!$detailData || !is_a($detailData, BasePostDetailData::class)) return; // Delete $deleter->delete($postSettings, $detailData, $saverData); }); } /** * Get category taxonomies defined by the post details * * @param null|SettingsImpl $postSettings * @return array See {@link BasePostDetailService::getCategoryTaxonomies()} * @since 1.8.0 */ public function getCategoryTaxonomies($postSettings) { $allTaxonomies = []; $this->walkRegisteredFactories(function($factory) use (&$postSettings, &$allTaxonomies) { /** @var BasePostDetailFactory $factory */ // Check availability if ($postSettings && !$factory->isAvailableForPost($postSettings)) return; // Get the service $service = $factory->getService(); if (!$service || !is_a($service, BasePostDetailService::class)) return; // Get the category taxonomies $taxonomies = $service->getCategoryTaxonomies(); if (!$taxonomies) return; // Collect them $allTaxonomies = array_merge($allTaxonomies, $taxonomies); }); return $allTaxonomies; } /** * @param PostBot $postBot * @param TranslatableTranslator $translator * @since 1.8.0 */ public function translate($postBot, $translator) { // Get a valid instance from the given value $postSettings = $this->getPostSettingsImplInstanceFromPostBot($postBot); $this->walkRegisteredFactories(function($factory) use (&$postSettings, &$translator) { /** @var BasePostDetailFactory $factory */ // Check availability if ($postSettings && !$factory->isAvailableForPost($postSettings)) return; // Get the data $data = $factory->getDetailData(); if (!$data || !is_a($data, Translatable::class)) return; // Try to translate try { /** @var Translatable $data */ $translator->setTranslatable($data); $translator->translate(); } catch (\Exception $e) { // Inform the user about the error Informer::addError( sprintf(_wpcc('Translation error for %1$s. Message: %2$s'), get_class($data), $e->getMessage()) )->setException($e)->addAsLog(); } }, $postBot); } /** * Invalidate all post detail factory instances * * @since 1.8.0 */ public function invalidateFactoryInstances() { BasePostDetailFactory::invalidateInstances(); } /* * PRIVATE METHODS */ /** * @param callable $callbackGetMetaKeys Provide the meta keys to be merged using the detail settings. Returns a * string array. For example: function(BasePostDetailSettings $settings) { * return $settings->getSingleMetaKeys() } * @param array $metaKeys Already-existing meta keys to which the meta keys retrieved from the * settings will be added. * @return array $metaKeys with the meta keys retrieved from the settings added * @since 1.8.0 */ private function addMetaKeys($callbackGetMetaKeys, $metaKeys = []) { $this->walkRegisteredFactories(function($factory) use (&$callbackGetMetaKeys, &$metaKeys) { /** @var BasePostDetailFactory $factory */ $settings = $factory->getSettings(null); if (!$settings || !is_a($settings, BasePostDetailSettings::class)) return; $detailMetaKeys = $callbackGetMetaKeys($settings); if (!$detailMetaKeys) return; $metaKeys = array_merge($metaKeys, $detailMetaKeys); }); return $metaKeys; } /** * Walks registered and available factories and calls the given callback. * * @param callable $callback A callback that will be called for each registered detail factory if it is available. * It takes only one parameter $factory, which is a BasePostDetailFactory, and returns * nothing. E.g. function($factory) {} * @param null|PostBot $postBot See {@link BasePostDetailFactory::getRegisteredFactoryInstances()} * @since 1.8.0 */ private function walkRegisteredFactories($callback, $postBot = null) { if (!$callback) return; foreach(BasePostDetailFactory::getRegisteredFactoryInstances($postBot) as $factory) { if (!$factory->isAvailable()) continue; $callback($factory); } } /** * Get a post settings instance using a post bot * * @param PostBot $postBot * @since 1.8.0 * @return SettingsImpl */ private function getPostSettingsImplInstanceFromPostBot($postBot) { if ($postBot) return $postBot->getSettingsImpl(); return $this->getPostSettingsImplInstance(null); } /** * @param SettingsImpl|array|null $postSettings * @param bool $prepare True if the settings should be prepared. Otherwise, false. * @return SettingsImpl * @since 1.8.0 */ private function getPostSettingsImplInstance($postSettings, $prepare = true) { // If this is an instance, use it directly. if (is_a($postSettings, SettingsImpl::class)) return $postSettings; // Otherwise, make sure it is an array. if (!$postSettings || !is_array($postSettings)) { $postSettings = []; } // Create an instance return new SettingsImpl($postSettings, Factory::postService()->getSingleMetaKeys(), $prepare); } }