service, BasePostDetailService::class)) return;
// Apply short codes
$service->applyShortCodes($factory->getDetailData(), $map, $frForMedia);
}, $postBot);
}
/**
* Prepare all interactable fields of the data, which should be an instance of {@link Transformable}, of all post
* details.
*
* @param PostBot $postBot
* @param callable $cbPrepare See {@link TransformablePreparer::__construct()}
* @since 1.9.0
*/
public function prepareDetailData($postBot, callable $cbPrepare): void {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstanceFromPostBot($postBot);
// Prepare templates defined in Options Boxes of other post details implementations
$this->walkRegisteredFactories(function($factory) use (&$postSettings, &$cbPrepare) {
/** @var BasePostDetailFactory $factory */
// Check availability for post
if (!$factory->isAvailableForPost($postSettings)) return;
// Get the data
$data = $factory->getDetailData();
if (!is_a($data, Transformable::class)) return;
/** @var Transformable $data */
// Prepare the data
$preparer = new TransformablePreparer($data, array_keys($data->getInteractableFields()->toAssociativeArray()), $cbPrepare);
$preparer->prepare();
}, $postBot);
}
/**
* Save registered post details.
*
* @param PostBot $postBot
* @param PostSaverData $saverData
* @throws DuplicatePostException|StopSavingException
* @since 1.8.0
*/
public function save($postBot, $saverData): void {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstanceFromPostBot($postBot);
// Get duplicate check options
$duplicateCheckOptions = null;
$duplicateCheckSettingValues = $postBot->getSetting(SettingKey::DUPLICATE_CHECK_TYPES);
// The values are stored under 0 key. So, make sure 0 key exists.
if($duplicateCheckSettingValues && isset($duplicateCheckSettingValues[0])) {
$duplicateCheckOptions = $duplicateCheckSettingValues[0];
}
/** @var null|DuplicatePostException $duplicateException */
$duplicateException = null;
$this->walkRegisteredFactories(function($factory) use (&$duplicateException, &$postSettings, &$saverData, &$duplicateCheckOptions) {
/** @var BasePostDetailFactory $factory */
// If there is a duplicate post found, stop.
if ($duplicateException) return;
// Check availability for post
if (!$factory->isAvailableForPost($postSettings)) return;
// Get the saver
$saver = $factory->getDetailSaver($saverData);
if (!$saver || !is_a($saver, BasePostDetailSaver::class)) return;
try {
// Save
$saver->save($factory->getDuplicateChecker(), $duplicateCheckOptions);
} catch (DuplicatePostException $e) {
$duplicateException = $e;
}
}, $postBot);
// If there is a duplicate post exception, throw it here.
if ($duplicateException) throw $duplicateException;
}
/**
* Get settings views of the registered post details, combined.
*
* @param SettingsImpl|array|null $postSettings
* @param array $viewVars Variables that will be injected to the settings views of the details
* @return string Rendered settings views as a single string.
* @since 1.8.0
*/
public function getSettingsViews($postSettings, $viewVars = []) {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstance($postSettings);
// Add post detail settings if there are any
$postDetailSettingsViews = '';
$this->walkRegisteredFactories(function($factory) use (&$postDetailSettingsViews, &$viewVars, &$postSettings) {
/** @var BasePostDetailFactory $factory */
// Check availability for post
if (!$factory->isAvailableForPost($postSettings)) return;
// Get the detail settings. Get a fresh one because the settings instance was created before in
// addMetaKeys() method with a null post settings. Here, we provide a non-null post settings. Hence,
// a new instance of detail settings must be created so that it can use the post settings. If a new instance
// is not created, there would not be any value in providing a non-null post settings here. So, a fresh one.
$settings = $factory->getSettings($postSettings, true);
if (!$settings || !is_a($settings, BasePostDetailSettings::class)) return;
// Get the settings view
$detailView = $settings->getSettingsView();
if (!$detailView) return;
// Append to other views
$postDetailSettingsViews .= $detailView->with($viewVars)->render();
});
return $postDetailSettingsViews;
}
/**
* Adds site settings assets of each available detail factory
*
* @param SettingsImpl|array|null $postSettings
* @since 1.8.0
*/
public function addSiteSettingsAssets($postSettings): void {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstance($postSettings);
$this->walkRegisteredFactories(function($factory) use (&$postSettings) {
/** @var BasePostDetailFactory $factory */
// Check availability
if (!$factory->isAvailableForPost($postSettings)) return;
$service = $factory->getService();
if (!$service || !is_a($service, BasePostDetailService::class)) return;
$service->addSiteSettingsAssets();
});
}
/**
* Get test views of the registered post details, combined.
*
* @param PostBot $postBot
* @param PostData $postData
* @param array $viewVars
* @return string Rendered test views as a single 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(): void {
$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): void {
$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 (!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 AbstractTransformer $transformer
* @since 1.8.0
*/
public function transform($postBot, $transformer): void {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstanceFromPostBot($postBot);
$this->walkRegisteredFactories(function($factory) use (&$postSettings, &$transformer) {
/** @var BasePostDetailFactory $factory */
// Check availability
if (!$factory->isAvailableForPost($postSettings)) return;
// Get the data
$data = $factory->getDetailData();
if (!is_a($data, Transformable::class)) return;
// Try to transform
try {
/** @var Transformable $data */
$transformer->setTransformable($data, $factory->getIdentifier());
$transformer->transform();
} catch (Exception $e) {
// Inform the user about the error
Informer::addError(sprintf(
_wpcc('Transformation error for %1$s. Message: %2$s - Class: %3$s'),
get_class($data),
$e->getMessage(),
get_class($transformer)
))->setException($e)->addAsLog();
}
}, $postBot);
}
/**
* Get transformable fields of registered post details
*
* @param SettingsImpl|array|null $postSettings
* @return array A key-value pair where keys are post details' names, and the values are associative arrays. Value
* arrays are structured such that the keys are transformable field dot notation keys and the values are
* descriptions for them.
* @since 1.9.0
*/
public function getTransformableFields($postSettings) {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstance($postSettings);
$result = [];
$this->walkRegisteredFactories(function($factory) use (&$postSettings, &$result) {
/** @var BasePostDetailFactory $factory */
// Check availability for post
if (!$factory->isAvailableForPost($postSettings)) return;
// Create a data object instance for the factory
$data = $factory->getDetailData();
// Make sure it is transformable
if (!is_a($data, Transformable::class)) return;
/** @var Transformable $data */
$transformableFields = $data->getTransformableFields()->toAssociativeArray();
if (!$transformableFields) return;
// Get the name and the identifier for this factory
$name = $factory->getName();
$identifier = $factory->getIdentifier();
if (!$name || !$identifier) return;
// Add the options
$result[$name] = AbstractTransformationService::prepareTransformableFieldForSelect($transformableFields, $identifier);
});
return $result;
}
/**
* Get factories that have {@link Transformable} data
*
* @param SettingsImpl|array|null $postSettings
* @return BasePostDetailFactory[] Array of factories that have {@link Transformable} data
* @since 1.11.0
*/
public function getTransformableFactories($postSettings) {
// Get a valid instance from the given value
$postSettings = $this->getPostSettingsImplInstance($postSettings);
$result = [];
$this->walkRegisteredFactories(function($factory) use (&$postSettings, &$result) {
/** @var BasePostDetailFactory $factory */
// Check availability for post
if (!$factory->isAvailableForPost($postSettings)) return;
// Create a data object instance for the factory
$data = $factory->getDetailData();
// Make sure it is transformable
if (!is_a($data, Transformable::class)) return;
/** @var Transformable $data */
$result[] = $factory;
});
return $result;
}
/**
* Invalidate all post detail factory instances
*
* @since 1.8.0
*/
public function invalidateFactoryInstances(): void {
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|null $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): void {
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|null $postBot
* @since 1.8.0
* @return SettingsImpl
*/
private function getPostSettingsImplInstanceFromPostBot($postBot): SettingsImpl {
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): SettingsImpl {
// If this is an instance, use it directly.
if (is_object($postSettings) && 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);
}
}
Fatal error: Uncaught Error: Class 'WPCCrawler\PostDetail\PostDetailsService' not found in /home/healths/public_html/wp-content/plugins/wp-content-crawler/app/WPCCrawler.php:223
Stack trace:
#0 /home/healths/public_html/wp-includes/class-wp-hook.php(324): WPCCrawler\WPCCrawler->WPCCrawler\{closure}()
#1 /home/healths/public_html/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()
#2 /home/healths/public_html/wp-includes/plugin.php(517): WP_Hook->do_action()
#3 /home/healths/public_html/wp-settings.php(550): do_action()
#4 /home/healths/public_html/wp-config.php(99): require_once('/home/healths/p...')
#5 /home/healths/public_html/wp-load.php(50): require_once('/home/healths/p...')
#6 /home/healths/public_html/wp-blog-header.php(13): require_once('/home/healths/p...')
#7 /home/healths/public_html/index.php(17): require('/home/healths/p...')
#8 {main}
thrown in /home/healths/public_html/wp-content/plugins/wp-content-crawler/app/WPCCrawler.php on line 223