From daa873e519c621d1408774edd63e28e7281635cc Mon Sep 17 00:00:00 2001 From: Rasmus Winter Date: Thu, 10 Jun 2021 11:27:39 +0100 Subject: [PATCH] Whitespace standardisation --- oowp.php | 74 +- src/OowpQuery.php | 237 ++-- src/PostTypeManager.php | 263 ++-- src/PostTypes/FakePost.php | 12 +- src/PostTypes/RoutemasterPost.php | 34 +- src/PostTypes/WordpressPost.php | 1928 +++++++++++++++-------------- src/QueryVars.php | 55 +- src/Util/AdminUtils.php | 339 ++--- src/Util/ReflectionUtils.php | 58 +- src/Util/StringUtils.php | 52 +- src/Views/OowpView.php | 2 +- src/Views/PostMenuItem.php | 28 +- src/Views/RssFeed.php | 22 +- src/WordpressTheme.php | 328 ++--- 14 files changed, 1773 insertions(+), 1659 deletions(-) diff --git a/oowp.php b/oowp.php index b9ddb79..daa8ca0 100644 --- a/oowp.php +++ b/oowp.php @@ -12,58 +12,62 @@ AdminUtils::customiseAdmin(); if (!function_exists('unregister_post_type')) { - function unregister_post_type($post_type) - { - global $wp_post_types; - if (isset($wp_post_types[$post_type])) { - unset($wp_post_types[$post_type]); + function unregister_post_type($post_type) + { + global $wp_post_types; + if (isset($wp_post_types[$post_type])) { + unset($wp_post_types[$post_type]); - add_action('admin_menu', function () use ($post_type) { - remove_menu_page('edit.php' . ($post_type == 'post' ? "" : "?post_type=$post_type")); - }, $post_type); - return true; - } - return false; - } + add_action('admin_menu', function () use ($post_type) { + remove_menu_page('edit.php' . ($post_type == 'post' ? "" : "?post_type=$post_type")); + }, $post_type); + return true; + } + return false; + } } /** * Reverse the effects of register_taxonomy() * - * @package WordPress - * @subpackage Taxonomy - * @since 3.0 - * @uses $wp_taxonomies Modifies taxonomy object - * * @param string $taxonomy Name of taxonomy object * @param array|string $object_type Name of the object type * @return bool True if successful, false if not + * @uses $wp_taxonomies Modifies taxonomy object + * + * @package WordPress + * @subpackage Taxonomy + * @since 3.0 */ -if(!function_exists('unregister_taxonomy')){ - function unregister_taxonomy($taxonomy, $object_type = ''){ - global $wp_taxonomies; +if (!function_exists('unregister_taxonomy')) { + function unregister_taxonomy($taxonomy, $object_type = '') + { + global $wp_taxonomies; - if (!isset($wp_taxonomies[$taxonomy])) - return false; + if (!isset($wp_taxonomies[$taxonomy])) { + return false; + } - if (!empty($object_type)) { - $i = array_search($object_type, $wp_taxonomies[$taxonomy]->object_type); + if (!empty($object_type)) { + $i = array_search($object_type, $wp_taxonomies[$taxonomy]->object_type); - if (false !== $i) - unset($wp_taxonomies[$taxonomy]->object_type[$i]); + if (false !== $i) { + unset($wp_taxonomies[$taxonomy]->object_type[$i]); + } - if (empty($wp_taxonomies[$taxonomy]->object_type)) - unset($wp_taxonomies[$taxonomy]); - } else { - unset($wp_taxonomies[$taxonomy]); - } + if (empty($wp_taxonomies[$taxonomy]->object_type)) { + unset($wp_taxonomies[$taxonomy]); + } + } else { + unset($wp_taxonomies[$taxonomy]); + } - return true; - } + return true; + } } -add_shortcode(ListPostsShortcode::NAME, function($params, $content) { +add_shortcode(ListPostsShortcode::NAME, function ($params, $content) { ListPostsShortcode::apply($params, $content); -}); \ No newline at end of file +}); diff --git a/src/OowpQuery.php b/src/OowpQuery.php index 8d42a9d..0bdf85a 100644 --- a/src/OowpQuery.php +++ b/src/OowpQuery.php @@ -7,116 +7,129 @@ class OowpQuery extends \WP_Query implements \IteratorAggregate, \ArrayAccess, \Countable { - /** - * @var WordpressPost[] - */ - var $posts; - - /** - * @param string|array $query - */ - function __construct($query = '') { - global $wp_post_types; - - $defaults = array( - 'posts_per_page' => -1, - 'post_status' => 'publish' - ); - $query = wp_parse_args($query, $defaults); - - // if there is no post type, or the post type is singular and isn't valid, replace it with 'any' - if (!isset($query['post_type']) || (!is_array($query['post_type']) && !array_key_exists($query['post_type'], $wp_post_types))) { - $query['post_type'] = 'any'; - } - - parent::__construct($query); - - if ($this->query_vars['error']) { - die('Query error ' . $this->query_vars['error']); - } - } - - /* Interfaces */ - - public function getIterator() { - return new \ArrayIterator($this->posts); - } - - public function offsetExists($offset) { - return isset($this->posts[$offset]); - } - - public function offsetGet($offset) { - return $this->posts[$offset]; - } - - public function offsetSet($offset, $value) { - $this->posts[$offset] = $value; - } - - public function offsetUnset($offset) { - unset($this->posts[$offset]); - } - - public function count() { - return count($this->posts); - } - - /** - * Stores $this as the global $wp_query, executes the passed-in WP function, then reverts $wp_query - * @return mixed - */ - protected function callGlobalQuery() { - global $wp_query; - $args = func_get_args(); - $function = array_shift($args); - $oldQuery = $wp_query; - $wp_query = $this; - $returnVal = call_user_func_array($function, $args); - $wp_query = $oldQuery; - return $returnVal; - } - - /** - * Prints the prev/next links for this query - * @param string $sep - * @param string $preLabel - * @param string $nextLabel - */ - public function postsNavLink($sep = '', $preLabel = '', $nextLabel = '') { - $this->callGlobalQuery('posts_nav_link', $sep, $preLabel, $nextLabel); - } - - public function queryVars() { - return new QueryVars($this->query_vars); - } - - public function sortByIds($ids) { - $indexes = array_flip($ids); - usort($this->posts, function($a, $b) use ($indexes) { - $aIndex = $indexes[$a->ID]; - $bIndex = $indexes[$b->ID]; - return $aIndex < $bIndex ? -1 : 1; - }); - } - - /** - * Convert WP_Post objects to WordpressPost - * @return WordpressPost[] - */ - public function &get_posts() { - parent::get_posts(); - - foreach ($this->posts as $i => $post) { - $this->posts[$i] = WordpressPost::createWordpressPost($post); - } - - if (count($this->posts)) { - $this->post = $this->posts[0]; - $this->queried_object = $this->post; - $this->queried_object_id = $this->post->ID; - } - - return $this->posts; - } + /** + * @var WordpressPost[] + */ + var $posts; + + /** + * @param string|array $query + */ + function __construct($query = '') + { + global $wp_post_types; + + $defaults = array( + 'posts_per_page' => -1, + 'post_status' => 'publish' + ); + $query = wp_parse_args($query, $defaults); + + // if there is no post type, or the post type is singular and isn't valid, replace it with 'any' + if (!isset($query['post_type']) || (!is_array($query['post_type']) && !array_key_exists($query['post_type'], + $wp_post_types))) { + $query['post_type'] = 'any'; + } + + parent::__construct($query); + + if ($this->query_vars['error']) { + die('Query error ' . $this->query_vars['error']); + } + } + + /* Interfaces */ + + public function getIterator() + { + return new \ArrayIterator($this->posts); + } + + public function offsetExists($offset) + { + return isset($this->posts[$offset]); + } + + public function offsetGet($offset) + { + return $this->posts[$offset]; + } + + public function offsetSet($offset, $value) + { + $this->posts[$offset] = $value; + } + + public function offsetUnset($offset) + { + unset($this->posts[$offset]); + } + + public function count() + { + return count($this->posts); + } + + /** + * Stores $this as the global $wp_query, executes the passed-in WP function, then reverts $wp_query + * @return mixed + */ + protected function callGlobalQuery() + { + global $wp_query; + $args = func_get_args(); + $function = array_shift($args); + $oldQuery = $wp_query; + $wp_query = $this; + $returnVal = call_user_func_array($function, $args); + $wp_query = $oldQuery; + return $returnVal; + } + + /** + * Prints the prev/next links for this query + * @param string $sep + * @param string $preLabel + * @param string $nextLabel + */ + public function postsNavLink($sep = '', $preLabel = '', $nextLabel = '') + { + $this->callGlobalQuery('posts_nav_link', $sep, $preLabel, $nextLabel); + } + + public function queryVars() + { + return new QueryVars($this->query_vars); + } + + public function sortByIds($ids) + { + $indexes = array_flip($ids); + usort($this->posts, function ($a, $b) use ($indexes) { + $aIndex = $indexes[$a->ID]; + $bIndex = $indexes[$b->ID]; + return $aIndex < $bIndex ? -1 : 1; + }); + } + + /** + * Convert WP_Post objects to WordpressPost + * @return WordpressPost[] + */ + public function &get_posts() + { + parent::get_posts(); + + foreach ($this->posts as $i => $post) { + $this->posts[$i] = WordpressPost::createWordpressPost($post); + } + + if (count($this->posts)) { + $this->post = $this->posts[0]; + $this->queried_object = $this->post; + $this->queried_object_id = $this->post->ID; + } + + return $this->posts; + } } diff --git a/src/PostTypeManager.php b/src/PostTypeManager.php index f7341f9..9a27ef3 100644 --- a/src/PostTypeManager.php +++ b/src/PostTypeManager.php @@ -2,16 +2,13 @@ namespace Outlandish\Wordpress\Oowp; -use Outlandish\Wordpress\Oowp\PostTypes\OowpPage; -use Outlandish\Wordpress\Oowp\PostTypes\OowpPost; use Outlandish\Wordpress\Oowp\PostTypes\WordpressPost; -use Outlandish\Wordpress\Oowp\Util\AdminUtils; class PostTypeManager { - protected $registered = false; - protected $postTypes = []; - protected $connections = []; + protected $registered = false; + protected $postTypes = []; + protected $connections = []; private function __construct() { @@ -27,97 +24,97 @@ public static function get() return self::$instance; } - /** - * Registers a single post type from the given class - * - * @param string|WordpressPost $className - * @throws \RuntimeException if $className is not a subclass of WordpressPost - */ + /** + * Registers a single post type from the given class + * + * @param string|WordpressPost $className + * @throws \RuntimeException if $className is not a subclass of WordpressPost + */ protected function registerPostType($className) { - if (!is_subclass_of($className, 'Outlandish\Wordpress\Oowp\PostTypes\WordpressPost')) { - throw new \RuntimeException($className . ' is not a subclass of WordpressPost'); - } + if (!is_subclass_of($className, 'Outlandish\Wordpress\Oowp\PostTypes\WordpressPost')) { + throw new \RuntimeException($className . ' is not a subclass of WordpressPost'); + } - $postType = $className::postType(); + $postType = $className::postType(); if (in_array($postType, $this->postTypes)) { // already registered return; } - if ($className::canBeRegistered()) { - $registrationArgs = $className::getRegistrationArgs(); - register_post_type($postType, $registrationArgs); - } + if ($className::canBeRegistered()) { + $registrationArgs = $className::getRegistrationArgs(); + register_post_type($postType, $registrationArgs); + } - $this->postTypes[$className] = $postType; + $this->postTypes[$className] = $postType; - do_action('oowp/post_type_registered', $postType, $className); + do_action('oowp/post_type_registered', $postType, $className); } - /** - * Registers the given classes as OOWP post types - * - * Usage (php < 5.5): - * $manager->registerPostTypes(['namespace\of\posttypes\MyPostType', 'namespace\of\posttypes\AnotherPostType']) - * Usage (php >= 5.5): - * $manager->registerPostTypes([MyPostType::class, AnotherPostType::class]) - * - * @param string[] $classNames - * @throws \Exception - */ + /** + * Registers the given classes as OOWP post types + * + * Usage (php < 5.5): + * $manager->registerPostTypes(['namespace\of\posttypes\MyPostType', 'namespace\of\posttypes\AnotherPostType']) + * Usage (php >= 5.5): + * $manager->registerPostTypes([MyPostType::class, AnotherPostType::class]) + * + * @param string[] $classNames + * @throws \Exception + */ public function registerPostTypes($classNames) { - if ($this->registered) { - throw new \Exception('Can only register post types once'); - } + if ($this->registered) { + throw new \Exception('Can only register post types once'); + } - /** @var WordpressPost[]|string[] $classNames */ + /** @var WordpressPost[]|string[] $classNames */ - // add the built-in post/page classes after all of the others - $classNames[] = 'Outlandish\Wordpress\Oowp\PostTypes\OowpPage'; - $classNames[] = 'Outlandish\Wordpress\Oowp\PostTypes\OowpPost'; - $classNames = array_unique($classNames); + // add the built-in post/page classes after all of the others + $classNames[] = 'Outlandish\Wordpress\Oowp\PostTypes\OowpPage'; + $classNames[] = 'Outlandish\Wordpress\Oowp\PostTypes\OowpPost'; + $classNames = array_unique($classNames); - // register all classes - foreach ($classNames as $className) { + // register all classes + foreach ($classNames as $className) { $this->registerPostType($className); } // then call onRegistrationComplete, so that connections can be set up foreach ($classNames as $className) { - $className::onRegistrationComplete(); - } + $className::onRegistrationComplete(); + } - // add hook for posts to deal with data after it is saved - add_filter('save_post', function($postId, $postData) { - if ($postData) { - $postType = $postData->post_type; - if (in_array($postType, $this->postTypes)) { + // add hook for posts to deal with data after it is saved + add_filter('save_post', function ($postId, $postData) { + if ($postData) { + $postType = $postData->post_type; + if (in_array($postType, $this->postTypes)) { $post = WordpressPost::fetchOne([ 'p' => $postId, 'post_type' => $postType, 'post_status' => $postData->post_status ]); - if ($post) { - $post->onSave($postData); - } - } - } - }, '99', 2); // use high priority value to ensure this happens after acf finishes saving its metadata + if ($post) { + $post->onSave($postData); + } + } + } + }, '99', 2); // use high priority value to ensure this happens after acf finishes saving its metadata - $this->registered = true; - do_action('oowp/all_post_types_registered', $this->postTypes); + $this->registered = true; + do_action('oowp/all_post_types_registered', $this->postTypes); } - /** - * Gets the name of the class that corresponds to the given post type - * - * @param string $postType - * @return WordpressPost|string - */ + /** + * Gets the name of the class that corresponds to the given post type + * + * @param string $postType + * @return WordpressPost|string + */ public function getClassName($postType) { - $classNames = array_flip($this->postTypes); - return array_key_exists($postType, $classNames) ? $classNames[$postType] : null; + $classNames = array_flip($this->postTypes); + return array_key_exists($postType, $classNames) ? $classNames[$postType] : null; } /** @@ -135,24 +132,24 @@ public function postClassIsRegistered($className) return array_key_exists($className, $this->postTypes); } - /** - * Returns true if the post type was registered via registerPostTypes() - * @param string $postType - * @return bool - */ + /** + * Returns true if the post type was registered via registerPostTypes() + * @param string $postType + * @return bool + */ public function postTypeIsRegistered($postType) - { - return in_array($postType, $this->postTypes); - } + { + return in_array($postType, $this->postTypes); + } - /** - * Gets all of the post types registered via registerPostTypes() - * @return string[] - */ + /** + * Gets all of the post types registered via registerPostTypes() + * @return string[] + */ public function getPostTypes() - { - return array_values($this->postTypes); - } + { + return array_values($this->postTypes); + } /** * Registers a new connection between two post types @@ -162,71 +159,71 @@ public function getPostTypes() * @param string $connectionName * @return bool|object|null */ - public function registerConnection($postType, $targetPostType, $parameters, $connectionName = null) - { - if (!function_exists('p2p_register_connection_type')) { - return null; - } + public function registerConnection($postType, $targetPostType, $parameters, $connectionName = null) + { + if (!function_exists('p2p_register_connection_type')) { + return null; + } - if (!$connectionName) { + if (!$connectionName) { $connectionName = $this->generateConnectionName($postType, $targetPostType); } if (array_key_exists($connectionName, $this->connections)) { - return $this->connections[$connectionName]->connection; + return $this->connections[$connectionName]->connection; } - $defaults = array( - 'name' => $connectionName, - 'from' => $postType, - 'to' => $targetPostType, - 'cardinality' => 'many-to-many', - 'reciprocal' => true - ); + $defaults = array( + 'name' => $connectionName, + 'from' => $postType, + 'to' => $targetPostType, + 'cardinality' => 'many-to-many', + 'reciprocal' => true + ); - $parameters = wp_parse_args($parameters, $defaults); - $connection = p2p_register_connection_type($parameters); + $parameters = wp_parse_args($parameters, $defaults); + $connection = p2p_register_connection_type($parameters); - $this->connections[$connectionName] = (object) [ - 'parameters' => $parameters, - 'connection' => $connection + $this->connections[$connectionName] = (object)[ + 'parameters' => $parameters, + 'connection' => $connection ]; - return $connection; - } + return $connection; + } - /** - * Generates a connection name from the given types - * @param string $postType - * @param string $targetType - * @return string - */ - public function generateConnectionName($postType, $targetType) - { - // order them alphabetically, so that it doesn't matter which order they were supplied - $types = array($postType, $targetType); - sort($types); - return implode('_', $types); - } + /** + * Generates a connection name from the given types + * @param string $postType + * @param string $targetType + * @return string + */ + public function generateConnectionName($postType, $targetType) + { + // order them alphabetically, so that it doesn't matter which order they were supplied + $types = array($postType, $targetType); + sort($types); + return implode('_', $types); + } - /** - * Gets all of the post types that the given post type is connected to - * @param string $postType - * @return string[] - */ - public function getConnectedPostTypes($postType) - { - $types = []; - foreach ($this->connections as $connection) { - if ($connection->parameters['from'] === $postType) { - $types[] = $connection->parameters['to']; + /** + * Gets all of the post types that the given post type is connected to + * @param string $postType + * @return string[] + */ + public function getConnectedPostTypes($postType) + { + $types = []; + foreach ($this->connections as $connection) { + if ($connection->parameters['from'] === $postType) { + $types[] = $connection->parameters['to']; } - if ($connection->parameters['to'] === $postType) { - $types[] = $connection->parameters['from']; + if ($connection->parameters['to'] === $postType) { + $types[] = $connection->parameters['from']; } } return array_unique($types); - } + } /** * Gets all of the connection names that go between (one of) $postTypeA and (one of) $postTypeB @@ -234,7 +231,7 @@ public function getConnectedPostTypes($postType) * @param string|string[] $postTypeB * @return string[] */ - public function getConnectionNames($postTypeA, $postTypeB) + public function getConnectionNames($postTypeA, $postTypeB) { $connectionNames = []; if ($postTypeA && $postTypeB) { @@ -245,10 +242,12 @@ public function getConnectionNames($postTypeA, $postTypeB) $postTypeA = [$postTypeA]; } foreach ($this->connections as $name => $connection) { - if (in_array($connection->parameters['from'], $postTypeA) && in_array($connection->parameters['to'], $postTypeB)) { + if (in_array($connection->parameters['from'], $postTypeA) && in_array($connection->parameters['to'], + $postTypeB)) { $connectionNames[] = $name; } - if (in_array($connection->parameters['from'], $postTypeB) && in_array($connection->parameters['to'], $postTypeA)) { + if (in_array($connection->parameters['from'], $postTypeB) && in_array($connection->parameters['to'], + $postTypeA)) { $connectionNames[] = $name; } } diff --git a/src/PostTypes/FakePost.php b/src/PostTypes/FakePost.php index f09b219..bffd908 100644 --- a/src/PostTypes/FakePost.php +++ b/src/PostTypes/FakePost.php @@ -5,8 +5,10 @@ /** * As WordpressPost is abstract, this class can be used for entities that have no real existence, e.g. 404 pages */ -class FakePost extends WordpressPost { - public function __construct($args = array()) { +class FakePost extends WordpressPost +{ + public function __construct($args = array()) + { //set defaults $postArray = wp_parse_args($args, array( 'ID' => 0, @@ -27,7 +29,8 @@ public function __construct($args = array()) { parent::__construct($postArray); } - public function permalink($leaveName = false) { + public function permalink($leaveName = false) + { if (!empty($this->permalink)) { return $this->permalink; } @@ -37,7 +40,8 @@ public function permalink($leaveName = false) { /** * @return string the Robots meta tag, should be NOINDEX, NOFOLLOW for some post types */ - public function robots(){ + public function robots() + { return "NOINDEX, NOFOLLOW"; } } diff --git a/src/PostTypes/RoutemasterPost.php b/src/PostTypes/RoutemasterPost.php index 192fcd7..a81f8ef 100644 --- a/src/PostTypes/RoutemasterPost.php +++ b/src/PostTypes/RoutemasterPost.php @@ -2,21 +2,23 @@ namespace Outlandish\Wordpress\Oowp\PostTypes; -abstract class RoutemasterPost extends WordpressPost { +abstract class RoutemasterPost extends WordpressPost +{ - /** - * Generates the permalink by concatenating this post's name to its parent's (recursively) - * @param bool $leaveName - * @return string - */ - public function permalink($leaveName = false) { - $parent = $this->parent(); - $parentUrl = $parent ? $parent->permalink() : get_bloginfo('url') . '/'; - if ($this->isHomepage()) { - return $parentUrl; - } else { - $postName = $leaveName ? '%postname%' : $this->post_name; - return $parentUrl . $postName . '/'; - } - } + /** + * Generates the permalink by concatenating this post's name to its parent's (recursively) + * @param bool $leaveName + * @return string + */ + public function permalink($leaveName = false) + { + $parent = $this->parent(); + $parentUrl = $parent ? $parent->permalink() : get_bloginfo('url') . '/'; + if ($this->isHomepage()) { + return $parentUrl; + } else { + $postName = $leaveName ? '%postname%' : $this->post_name; + return $parentUrl . $postName . '/'; + } + } } diff --git a/src/PostTypes/WordpressPost.php b/src/PostTypes/WordpressPost.php index 22b36f9..34841ee 100644 --- a/src/PostTypes/WordpressPost.php +++ b/src/PostTypes/WordpressPost.php @@ -44,53 +44,53 @@ abstract class WordpressPost { - protected $_cache = array(); - protected static $_staticCache = array(); + protected $_cache = array(); + protected static $_staticCache = array(); - /** - * @var \WP_Post - */ - protected $post; + /** + * @var \WP_Post + */ + protected $post; #region Getters, Setters, Construct, Init - /** - * @param int|array|object $data - */ - public function __construct($data) - { - //Make sure it's an object - $this->post = self::getPostObject($data); - } - - /** - * Converts the data into an internal wordpress (WP_Post) post object - * @static - * - * @param mixed $data - * @return \WP_Post|WordpressPost - */ - public static function getPostObject($data) - { - if (is_array($data)) { - return new \WP_Post((object)$data); - } - if (is_object($data) && $data instanceof \WP_Post) { - return $data; - } - if (is_object($data)) { - return new \WP_Post($data); - } - if (is_numeric($data) && is_integer($data + 0)) { - return get_post($data); - } - - //TODO: should this throw an exception instead? - //this is the only way this can return a WordpressPost object - global $post; - return $post; - } + /** + * @param int|array|object $data + */ + public function __construct($data) + { + //Make sure it's an object + $this->post = self::getPostObject($data); + } + + /** + * Converts the data into an internal wordpress (WP_Post) post object + * @static + * + * @param mixed $data + * @return \WP_Post|WordpressPost + */ + public static function getPostObject($data) + { + if (is_array($data)) { + return new \WP_Post((object)$data); + } + if (is_object($data) && $data instanceof \WP_Post) { + return $data; + } + if (is_object($data)) { + return new \WP_Post($data); + } + if (is_numeric($data) && is_integer($data + 0)) { + return get_post($data); + } + + //TODO: should this throw an exception instead? + //this is the only way this can return a WordpressPost object + global $post; + return $post; + } /** * Called during PostTypeManager::registerPostType @@ -98,25 +98,25 @@ public static function getPostObject($data) * but there may be exceptional circumstances where they might be re-registered, so this function can be overridden * @return bool */ - public static function canBeRegistered() + public static function canBeRegistered() { return !post_type_exists(static::postType()); } - /** - * Called after all OOWP posts have been registered - * @static - */ - public static function onRegistrationComplete() - { - } + /** + * Called after all OOWP posts have been registered + * @static + */ + public static function onRegistrationComplete() + { + } - /** - * Return the underlying WP_Post - */ - public function get_post() + /** + * Return the underlying WP_Post + */ + public function get_post() { - return $this->post; + return $this->post; } /** @@ -128,147 +128,157 @@ public function setAsGlobal() $post = $this->get_post(); } - /** - * Override this to hook into the save event. This is called with low priority so - * all fields should be already saved - */ - public function onSave($postData) { - // do nothing - } - - /** - * Proxy magic properties to WP_Post - * - * @param string $name - * @return mixed - */ - public function __get($name) { - return $this->post->$name; - } - - /** - * Proxy magic properties to WP_Post - * - * @param string $name - * @param mixed $value - * @return mixed - */ - public function __set($name, $value) { - return $this->post->$name = $value; - } - - /** - * Proxy magic properties to WP_Post - * - * @param string $name - * @return mixed - */ - public function __isset($name) { - return isset($this->post->$name); - } - - /** - * Gets the cached value for the function that called this - * - * @return mixed - */ - protected function getCacheValue() { - $functionName = ReflectionUtils::getCaller(); - return (array_key_exists($functionName, $this->_cache) ? $this->_cache[$functionName] : null); - } - - /** - * Sets and returns the cached value for the function that called this - * - * @param mixed $value - * @return mixed - */ - protected function setCacheValue($value) { - $this->_cache[ReflectionUtils::getCaller()] = $value; - return $value; - } + /** + * Override this to hook into the save event. This is called with low priority so + * all fields should be already saved + */ + public function onSave($postData) + { + // do nothing + } + + /** + * Proxy magic properties to WP_Post + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->post->$name; + } + + /** + * Proxy magic properties to WP_Post + * + * @param string $name + * @param mixed $value + * @return mixed + */ + public function __set($name, $value) + { + return $this->post->$name = $value; + } + + /** + * Proxy magic properties to WP_Post + * + * @param string $name + * @return mixed + */ + public function __isset($name) + { + return isset($this->post->$name); + } + + /** + * Gets the cached value for the function that called this + * + * @return mixed + */ + protected function getCacheValue() + { + $functionName = ReflectionUtils::getCaller(); + return (array_key_exists($functionName, $this->_cache) ? $this->_cache[$functionName] : null); + } + + /** + * Sets and returns the cached value for the function that called this + * + * @param mixed $value + * @return mixed + */ + protected function setCacheValue($value) + { + $this->_cache[ReflectionUtils::getCaller()] = $value; + return $value; + } #endregion #region Default getters - protected static $postTypes = array(); - - /** - * @static - * - * @return string The post name for this class, derived from the classname - */ - public static function postType() - { - $class = get_called_class(); - $key = $class; - if (!array_key_exists($key, static::$postTypes)) { - $postType = null; - // strip out the namespace, then take a substring from the first capital letter, and un-camel case it - $class = substr($class, strrpos($class, '\\')+1); - if (preg_match('/([A-Z].*)/m', $class, $regs)) { - $match = $regs[1]; - $postType = lcfirst(StringUtils::fromCamelCase($match)); - } - static::$postTypes[$key] = $postType; - } - - $postType = static::$postTypes[$key]; - if (!$postType) { - die('Invalid post type (' . $class . ')'); - } - return $postType; - } - - /** - * @static - * - * @return string The human-friendly name of this class, derived from the post name - */ - public static function friendlyName() { - return ucwords(str_replace('_', ' ', static::postType())); - } - - /** - * @static - * - * @return string The human-friendly name of this class, derived from the post name - */ - public static function friendlyNamePlural() { - return static::friendlyName() . 's'; - } - - /** - * @param array $posts Array of posts/post ids - */ - public function connectAll($posts) { - foreach ($posts as $post) { - $this->connect($post); - } - } + protected static $postTypes = array(); + + /** + * @static + * + * @return string The post name for this class, derived from the classname + */ + public static function postType() + { + $class = get_called_class(); + $key = $class; + if (!array_key_exists($key, static::$postTypes)) { + $postType = null; + // strip out the namespace, then take a substring from the first capital letter, and un-camel case it + $class = substr($class, strrpos($class, '\\') + 1); + if (preg_match('/([A-Z].*)/m', $class, $regs)) { + $match = $regs[1]; + $postType = lcfirst(StringUtils::fromCamelCase($match)); + } + static::$postTypes[$key] = $postType; + } + + $postType = static::$postTypes[$key]; + if (!$postType) { + die('Invalid post type (' . $class . ')'); + } + return $postType; + } + + /** + * @static + * + * @return string The human-friendly name of this class, derived from the post name + */ + public static function friendlyName() + { + return ucwords(str_replace('_', ' ', static::postType())); + } + + /** + * @static + * + * @return string The human-friendly name of this class, derived from the post name + */ + public static function friendlyNamePlural() + { + return static::friendlyName() . 's'; + } + + /** + * @param array $posts Array of posts/post ids + */ + public function connectAll($posts) + { + foreach ($posts as $post) { + $this->connect($post); + } + } /** * @param int|object|WordpressPost $post * @param array $meta * @param string $connectionName */ - public function connect($post, $meta = array(), $connectionName = null) { - $post = WordpressPost::createWordpressPost($post); - if ($post) { - if (!$connectionName) { + public function connect($post, $meta = array(), $connectionName = null) + { + $post = WordpressPost::createWordpressPost($post); + if ($post) { + if (!$connectionName) { $connectionName = PostTypeManager::get()->generateConnectionName(self::postType(), $post->post_type); } - /** @var \P2P_Directed_Connection_Type $connectionType */ - $connectionType = p2p_type($connectionName); - if ($connectionType) { - $p2pId = $connectionType->connect($this->ID, $post->ID); - foreach ($meta as $key=>$value) { - p2p_update_meta($p2pId, $key, $value); - } - } - } - } + /** @var \P2P_Directed_Connection_Type $connectionType */ + $connectionType = p2p_type($connectionName); + if ($connectionType) { + $p2pId = $connectionType->connect($this->ID, $post->ID); + foreach ($meta as $key => $value) { + p2p_update_meta($p2pId, $key, $value); + } + } + } + } /** * @param string|string[] $targetPostType e.g. post, event - the type of connected post(s) you want @@ -278,378 +288,389 @@ public function connect($post, $meta = array(), $connectionName = null) { * @param string|string[] $connectionName If specified, only this connection name is used to find the connected posts (defaults to any/all connections to $targetPostType) * @return null|OowpQuery|WordpressPost */ - public function connected($targetPostType, $single = false, $queryArgs = array(), $hierarchical = false, $connectionName = null) - { - $toReturn = null; - if (function_exists('p2p_register_connection_type')) { - if(!is_array($targetPostType)) { - $targetPostType = array($targetPostType); - } - $manager = PostTypeManager::get(); - $postType = self::postType(); - - if (!$connectionName) { + public function connected( + $targetPostType, + $single = false, + $queryArgs = array(), + $hierarchical = false, + $connectionName = null + ) { + $toReturn = null; + if (function_exists('p2p_register_connection_type')) { + if (!is_array($targetPostType)) { + $targetPostType = array($targetPostType); + } + $manager = PostTypeManager::get(); + $postType = self::postType(); + + if (!$connectionName) { $connectionName = $manager->getConnectionNames($postType, $targetPostType); - } else if (!is_array($connectionName)) { - $connectionName = [$connectionName]; + } elseif (!is_array($connectionName)) { + $connectionName = [$connectionName]; + } + + $defaults = array( + 'connected_type' => $connectionName, + 'post_type' => $targetPostType, + ); + + // ignore $hierarchical = true if this post type is not hierarchical + if ($hierarchical && !self::isHierarchical($postType)) { + $hierarchical = false; + } + + if ($hierarchical) { + $defaults['connected_items'] = array_merge($this->getDescendantIds(), array($this->ID)); + } else { + $defaults['connected_items'] = $this->ID; + } + + // use the menu order if $hierarchical is true, or any of the target post types are hierarchical + $useMenuOrder = $hierarchical; + if (!$useMenuOrder) { + foreach ($targetPostType as $otherPostType) { + if (self::isHierarchical($otherPostType)) { + $useMenuOrder = true; + break; + } + } + } + if ($useMenuOrder) { + $defaults['orderby'] = 'menu_order'; + $defaults['order'] = 'asc'; + } + + $queryArgs = array_merge($defaults, $queryArgs); + $result = new OowpQuery($queryArgs); + + if ($hierarchical) { //filter out any duplicate posts + $post_ids = array(); + foreach ($result->posts as $i => $post) { + if (in_array($post->ID, $post_ids)) { + unset($result->posts[$i]); + } + + $post_ids[] = $post->ID; + } + } + + $toReturn = $single ? null : $result; + if (!$single) { + $toReturn = $result; + } elseif ($result && $result->posts) { + $toReturn = $result->posts[0]; + } + } + + return $toReturn; + } + + static function walkTree($p, &$current_descendants = array()) + { + $current_descendants = array_merge($p->children, $current_descendants); + foreach ($p->children as $child) { + self::walkTree($child, $current_descendants); + } + + return $current_descendants; + + } + + function getDescendants() + { + $posts = self::fetchAll(); + $keyed = array(); + foreach ($posts as $post) { + $keyed[$post->ID] = $post; + $keyed[$post->ID]->children = array(); + } + unset($posts); + foreach ($keyed as $post) { /* This is all a bit complicated but it works */ + if ($post->post_parent) { + $keyed[$post->post_parent]->children[] = $post; + } + } + + $p = $keyed[$this->ID]; + $descendants = static::walkTree($p); + return $descendants; + } + + function getDescendantIds() + { + $ids = array(); + foreach ($this->getDescendants() as $d) { + $ids[] = $d->ID; + } + return $ids; + } + + public function allMetadata() + { + return get_metadata('post', $this->ID); + } + + /** + * Gets the metadata (custom fields) for the post + * @param string $name + * @param bool $single + * @return array|string + */ + public function metadata($name, $single = true) + { + $meta = null; + if (function_exists('get_field')) { + $meta = get_field($name, $this->ID); + // if not found by acf, then may not be an acf-configured field, so fall back on normal wp method + if ($meta === false) { + $fieldObj = get_field_object($name, $this->ID); + if (!$fieldObj || !$fieldObj['key']) { + $meta = get_post_meta($this->ID, $name, $single); + } + } + } else { + $meta = get_post_meta($this->ID, $name, $single); + } + if (!$single && !$meta) { + $meta = array(); // ensure return type is an array + } + return $meta; + } + + /** + * Sets the metadata with the given key for the post + * + * @param string $key + * @param mixed $value + */ + public function setMetadata($key, $value) + { + if (function_exists('update_field')) { + update_field($key, $value, $this->ID); + } else { + update_post_meta($this->ID, $key, $value); + } + } + + /** + * Deletes the metadata with the given key for the post + * + * @param string $key + */ + public function deleteMetadata($key) + { + if (function_exists('delete_field')) { + delete_field($key, $this->ID); + } else { + delete_post_meta($this->ID, $key); + } + } + + /*************************************************************************************************************************************** + * * + * TEMPLATE HELPERS * + * * + ***************************************************************************************************************************************/ + + public function title() + { + return apply_filters('the_title', $this->post_title, $this->ID); + } + + public function content() + { + return apply_filters('the_content', $this->post_content); + } + + public function date($format = 'd M Y') + { + return date($format, $this->timestamp()); + } + + public function modifiedDate($format = 'd M Y') + { + return date($format, strtotime($this->post_modified)); + } + + /** + * @return WordpressPost|null Get parent of post (or post type) + */ + public function parent() + { + $parentId = $this->post_parent; + if (!$parentId) { + $parentId = static::postTypeParentId(); + } + $parentSlug = static::postTypeParentSlug(); + if (empty($parentId) && empty($parentSlug)) { + return null; + } + + $parent = $this->getCacheValue(); + if (!$parent) { + $parent = $parentId ? WordpressPost::fetchById($parentId) : WordpressPost::fetchBySlug($parentSlug); + $this->setCacheValue($parent); + } + return $parent; + } + + /** + * If the parent of a hierarchical post type is a page, for example, this needs to be set to that ID. + * Is mutually exclusive with postTypeParentSlug (this takes priority) + * + * @return int The ID of the parent post for this post type. + */ + public static function postTypeParentId() + { + return 0; + } + + /** + * If the parent of a hierarchical post type is a page, for example, this needs to be set to that slug + * Is mutually exclusive with postTypeParentId (that takes priority) + * + * @return string The slug of the parent post for this post type. + */ + public static function postTypeParentSlug() + { + return ''; + } + + /** + * Traverses up the getParent() hierarchy until finding one with no parent, which is returned + */ + public function getRoot() + { + $parent = $this->parent(); + if ($parent) { + return $parent->getRoot(); + } + return $this; + } + + public function timestamp() + { + return strtotime($this->post_date); + } + + function excerpt($chars = 400, $stuff = null) + { + (!empty($stuff) ?: $stuff = $this->content()); + $content = str_replace("", '', $stuff); + //try to split on more link + $parts = preg_split('||i', $content); + $content = $parts[0]; + $content = strip_tags($content); + $excerpt = ''; + $sentences = array_filter(explode(" ", $content)); + if ($sentences) { + foreach ($sentences as $sentence) { + if ((strlen($excerpt) + strlen($sentence)) < $chars && $sentence) { + $excerpt .= $sentence . " "; + } else { + break; + } + } + } + + if (!$excerpt) { + $words = array_filter(explode(" ", $content)); + if ($words) { + foreach ($words as $word) { + if ((strlen($excerpt) + strlen($word)) < $chars && $word) { + $excerpt .= $word . " "; + } else { + break; + } + } } + } + + $excerpt = trim(str_replace(' ', ' ', $excerpt)); + if (preg_match('%\w|,|:%i', substr($excerpt, -1))) { + $excerpt = $excerpt . "..."; + } - $defaults = array( - 'connected_type' => $connectionName, - 'post_type' => $targetPostType, - ); + return ($excerpt); + } + + public function permalink($leaveName = false) + { + if ($this->isHomepage()) { + return rtrim(get_bloginfo('url'), '/') . '/'; + } + return get_permalink($this->ID, $leaveName); + } - // ignore $hierarchical = true if this post type is not hierarchical - if ($hierarchical && !self::isHierarchical($postType)) { - $hierarchical = false; + /** + * Fetches all posts (of any post_type) whose post_parent is this post, as well as + * the root posts of any post_types whose declared postTypeParentId is this post. + * Add 'post_type' to query args to only return certain post types for children + * Add 'post__not_in' to query args to exclude certain pages based on id. + * + * @param array $queryArgs + * @return WordpressPost[]|OowpQuery + */ + public function children($queryArgs = array()) + { + $posts = array(); + $postTypes = (array_key_exists('post_type', $queryArgs) ? $queryArgs['post_type'] : 'any'); + unset($queryArgs['post_type']); + if (!is_array($postTypes)) { + $postTypes = array($postTypes); + } + $manager = PostTypeManager::get(); + foreach ($this->childPostClassNames() as $className) { + foreach ($postTypes as $postType) { + if ($postType == 'any' || ($postType != 'none' && $manager->getClassName($postType) == $className)) { + $posts = array_merge($posts, $className::fetchRoots($queryArgs)->posts); + } } + } + $defaults = array('post_parent' => $this->ID); + $queryArgs = wp_parse_args($queryArgs, $defaults); + $children = static::fetchAll($queryArgs); + $children->posts = array_merge($children->posts, $posts); + $children->post_count = count($children->posts); + return $children; + } - if ($hierarchical) { - $defaults['connected_items'] = array_merge($this->getDescendantIds(), array($this->ID)); - } else { - $defaults['connected_items'] = $this->ID; - } - - // use the menu order if $hierarchical is true, or any of the target post types are hierarchical - $useMenuOrder = $hierarchical; - if (!$useMenuOrder) { - foreach ($targetPostType as $otherPostType) { - if (self::isHierarchical($otherPostType)) { - $useMenuOrder = true; - break; - } - } - } - if ($useMenuOrder) { - $defaults['orderby'] = 'menu_order'; - $defaults['order'] = 'asc'; - } - - $queryArgs = array_merge($defaults, $queryArgs); - $result = new OowpQuery($queryArgs); - - if ($hierarchical) { //filter out any duplicate posts - $post_ids = array(); - foreach($result->posts as $i => $post){ - if(in_array($post->ID, $post_ids)) { - unset($result->posts[$i]); - } - - $post_ids[] = $post->ID; - } - } - - $toReturn = $single ? null : $result; - if (!$single) { - $toReturn = $result; - } else if ($result && $result->posts) { - $toReturn = $result->posts[0]; - } - } - - return $toReturn; - } - - static function walkTree($p, &$current_descendants = array()) - { - $current_descendants = array_merge($p->children, $current_descendants); - foreach ($p->children as $child) { - self::walkTree($child, $current_descendants); - } - - return $current_descendants; - - } - - function getDescendants() - { - $posts = self::fetchAll(); - $keyed = array(); - foreach ($posts as $post) { - $keyed[$post->ID] = $post; - $keyed[$post->ID]->children = array(); - } - unset($posts); - foreach ($keyed as $post) { /* This is all a bit complicated but it works */ - if ($post->post_parent) { - $keyed[$post->post_parent]->children[] = $post; - } - } - - $p = $keyed[$this->ID]; - $descendants = static::walkTree($p); - return $descendants; - } - - function getDescendantIds() - { - $ids = array(); - foreach ($this->getDescendants() as $d) { - $ids[] = $d->ID; - } - return $ids; - } - - public function allMetadata() { - return get_metadata('post', $this->ID); - } - - /** - * Gets the metadata (custom fields) for the post - * @param string $name - * @param bool $single - * @return array|string - */ - public function metadata($name, $single = true) { - $meta = null; - if (function_exists('get_field')) { - $meta = get_field($name, $this->ID); - // if not found by acf, then may not be an acf-configured field, so fall back on normal wp method - if ($meta === false) { - $fieldObj = get_field_object($name, $this->ID); - if (!$fieldObj || !$fieldObj['key']) { - $meta = get_post_meta($this->ID, $name, $single); - } - } - } else { - $meta = get_post_meta($this->ID, $name, $single); - } - if (!$single && !$meta) { - $meta = array(); // ensure return type is an array - } - return $meta; - } - - /** - * Sets the metadata with the given key for the post - * - * @param string $key - * @param mixed $value - */ - public function setMetadata($key, $value) - { - if (function_exists('update_field')) { - update_field($key, $value, $this->ID); - } else { - update_post_meta($this->ID, $key, $value); - } - } - - /** - * Deletes the metadata with the given key for the post - * - * @param string $key - */ - public function deleteMetadata($key) - { - if (function_exists('delete_field')) { - delete_field($key, $this->ID); - } else { - delete_post_meta($this->ID, $key); - } - } - - /*************************************************************************************************************************************** - * * - * TEMPLATE HELPERS * - * * - ***************************************************************************************************************************************/ - - public function title() - { - return apply_filters('the_title', $this->post_title, $this->ID); - } - - public function content() - { - return apply_filters('the_content', $this->post_content); - } - - public function date($format = 'd M Y') - { - return date($format, $this->timestamp()); - } - - public function modifiedDate($format = 'd M Y') { - return date($format, strtotime($this->post_modified)); - } - - /** - * @return WordpressPost|null Get parent of post (or post type) - */ - public function parent() - { - $parentId = $this->post_parent; - if (!$parentId) { - $parentId = static::postTypeParentId(); - } - $parentSlug = static::postTypeParentSlug(); - if (empty($parentId) && empty($parentSlug)) { - return null; - } - - $parent = $this->getCacheValue(); - if (!$parent) { - $parent = $parentId ? WordpressPost::fetchById($parentId) : WordpressPost::fetchBySlug($parentSlug); - $this->setCacheValue($parent); - } - return $parent; - } - - /** - * If the parent of a hierarchical post type is a page, for example, this needs to be set to that ID. - * Is mutually exclusive with postTypeParentSlug (this takes priority) - * - * @return int The ID of the parent post for this post type. - */ - public static function postTypeParentId() - { - return 0; - } - - /** - * If the parent of a hierarchical post type is a page, for example, this needs to be set to that slug - * Is mutually exclusive with postTypeParentId (that takes priority) - * - * @return string The slug of the parent post for this post type. - */ - public static function postTypeParentSlug() - { - return ''; - } - - /** - * Traverses up the getParent() hierarchy until finding one with no parent, which is returned - */ - public function getRoot() { - $parent = $this->parent(); - if ($parent) { - return $parent->getRoot(); - } - return $this; - } - - public function timestamp() - { - return strtotime($this->post_date); - } - - function excerpt($chars = 400, $stuff = null) { - (!empty($stuff) ?: $stuff = $this->content()); - $content = str_replace("", '', $stuff); - //try to split on more link - $parts = preg_split('||i', $content); - $content = $parts[0]; - $content = strip_tags($content); - $excerpt = ''; - $sentences = array_filter(explode(" ", $content)); - if($sentences){ - foreach($sentences as $sentence){ - if((strlen($excerpt) + strlen($sentence)) < $chars && $sentence){ - $excerpt .= $sentence." "; - }else{ - break; - } - } - } - - if(!$excerpt){ - $words = array_filter(explode(" ", $content)); - if($words){ - foreach($words as $word){ - if((strlen($excerpt) + strlen($word)) < $chars && $word){ - $excerpt .= $word." "; - }else{ - break; - } - } - } - } - - $excerpt = trim(str_replace(' ', ' ',$excerpt)); - if(preg_match('%\w|,|:%i', substr($excerpt, -1))) { - $excerpt = $excerpt . "..."; - } - - return ($excerpt); - } - - public function permalink($leaveName = false) { - if ($this->isHomepage()) { - return rtrim(get_bloginfo('url'), '/') . '/'; - } - return get_permalink($this->ID, $leaveName); - } - - /** - * Fetches all posts (of any post_type) whose post_parent is this post, as well as - * the root posts of any post_types whose declared postTypeParentId is this post. - * Add 'post_type' to query args to only return certain post types for children - * Add 'post__not_in' to query args to exclude certain pages based on id. - * - * @param array $queryArgs - * @return WordpressPost[]|OowpQuery - */ - public function children($queryArgs = array()) - { - $posts = array(); - $postTypes = (array_key_exists ('post_type', $queryArgs) ? $queryArgs['post_type'] : 'any'); - unset($queryArgs['post_type']); - if (!is_array($postTypes)) { - $postTypes = array($postTypes); - } - $manager = PostTypeManager::get(); - foreach($this->childPostClassNames() as $className){ - foreach($postTypes as $postType){ - if($postType == 'any' || ($postType != 'none' && $manager->getClassName($postType) == $className)) { - $posts = array_merge($posts, $className::fetchRoots($queryArgs)->posts); - } - } - } - $defaults = array('post_parent' => $this->ID); - $queryArgs = wp_parse_args($queryArgs, $defaults); - $children = static::fetchAll($queryArgs); - $children->posts = array_merge($children->posts, $posts); - $children->post_count = count($children->posts); - return $children; - } - - /** - * @return array Class names of WordpressPost types having this post as their parent - */ - public function childPostClassNames() - { - $manager = PostTypeManager::get(); - $names = array(); - foreach ($manager->getPostTypes() as $postType) { - $class = $manager->getClassName($postType); - if ($class::postTypeParentId() == $this->ID || $class::postTypeParentSlug() == $this->post_name) { - $names[] = $class; - } - } - return $names; - } - - /** - * @return array Post types of WordpressPost types that are connected to this post type - */ - public static function connectedPostTypes() - { - return PostTypeManager::get()->getConnectedPostTypes(self::postType()); - } - - /** - * @return array Class names of WordpressPost types that are connected to this post type - */ - public static function connectedClassNames() - { - $manager = PostTypeManager::get(); - $names = array(); - foreach(self::connectedPostTypes() as $postType){ - $names[] = $manager->getClassName($postType); - } - return $names; - } + /** + * @return array Class names of WordpressPost types having this post as their parent + */ + public function childPostClassNames() + { + $manager = PostTypeManager::get(); + $names = array(); + foreach ($manager->getPostTypes() as $postType) { + $class = $manager->getClassName($postType); + if ($class::postTypeParentId() == $this->ID || $class::postTypeParentSlug() == $this->post_name) { + $names[] = $class; + } + } + return $names; + } + + /** + * @return array Post types of WordpressPost types that are connected to this post type + */ + public static function connectedPostTypes() + { + return PostTypeManager::get()->getConnectedPostTypes(self::postType()); + } + + /** + * @return array Class names of WordpressPost types that are connected to this post type + */ + public static function connectedClassNames() + { + $manager = PostTypeManager::get(); + $names = array(); + foreach (self::connectedPostTypes() as $postType) { + $names[] = $manager->getClassName($postType); + } + return $names; + } /** * Executes a wordpress function, setting $this as the global $post first, then resets the global post data. @@ -663,7 +684,7 @@ protected function callGlobalPost() $prevPost = $post; // Get requested WordPress function and arguments - $args = func_get_args(); + $args = func_get_args(); $callback = array_shift($args); // Set up global variables to support WP function execution @@ -680,181 +701,190 @@ protected function callGlobalPost() return $returnVal; } - public function wp_author() - { - return $this->callGlobalPost('get_the_author'); - } - - /** - * @return string the Robots meta tag, should be NOINDEX, NOFOLLOW for some post types - */ - public function robots(){ - return ""; - } - - /** - * Gets the url for editing this post. Returns blank if $requireLoggedIn is true and the logged-in user doesn't have the right permissions - * - * @param bool $requireLoggedIn - * @return string - */ - public function editUrl($requireLoggedIn = false) { - $url = get_edit_post_link($this->ID, ''); - if (!$url && !$requireLoggedIn) { - $post_type_object = get_post_type_object(static::postType()); - $url = admin_url( sprintf($post_type_object->_edit_link . '&action=edit', $this->ID)); - } - return $url; - } - - /** - * Use this with attachment posts to convert the front page of a PDF to a PNG, and create a corresponding attachment. - * Typical usage (requires project to define xxAttachment class): - * add_action('add_attachment', function($id) { - * //use constructor rather than factory to get around auto-draft post_status issue - * $attachment = new xxAttachment($id); - * $attachment->generatePdfImage(); - * }); - * IMPORTANT!!! in php-fpm.conf, the env[PATH] = /usr/local/bin:/usr/bin:/bin needs to be uncommented for this to work - * - * @param string $extension - * @param string $namePrefix - * @param bool $logDebug - */ - public function generatePdfImage($extension = 'png', $namePrefix = 'pdf-image-', $logDebug = false) { - $debug = @fopen(get_stylesheet_directory() . '/debug.txt', 'a'); - $log = function($message, $force = false) use ($debug, $logDebug) { - if ($debug && ($logDebug || $force)) { - @fwrite($debug, '[' . date('Y-m-d H:i:s') . "]: $message\n"); - } - }; - $log('checking for suitability (' . $this->ID . ", $extension, $namePrefix)"); - // IMAGEMAGICK_CONVERT should be defined in wp-config.php - if (defined('IMAGEMAGICK_CONVERT') && IMAGEMAGICK_CONVERT && $this->post_mime_type == 'application/pdf') { - $log('attempting conversion'); - - $sourceFile = get_attached_file($this->ID); - $targetFile = str_replace('.pdf', '.' . $extension, $sourceFile); - - // Converted image will have a fixed size (-extent), centred (-gravity), with the aspect ratio respected (-thumbnail), and - // excess space filled with transparent colour (-background) - $size = '260x310'; - $args = array( - '-density 96', - '-quality 85', - '-thumbnail ' . $size, + public function wp_author() + { + return $this->callGlobalPost('get_the_author'); + } + + /** + * @return string the Robots meta tag, should be NOINDEX, NOFOLLOW for some post types + */ + public function robots() + { + return ""; + } + + /** + * Gets the url for editing this post. Returns blank if $requireLoggedIn is true and the logged-in user doesn't have the right permissions + * + * @param bool $requireLoggedIn + * @return string + */ + public function editUrl($requireLoggedIn = false) + { + $url = get_edit_post_link($this->ID, ''); + if (!$url && !$requireLoggedIn) { + $post_type_object = get_post_type_object(static::postType()); + $url = admin_url(sprintf($post_type_object->_edit_link . '&action=edit', $this->ID)); + } + return $url; + } + + /** + * Use this with attachment posts to convert the front page of a PDF to a PNG, and create a corresponding attachment. + * Typical usage (requires project to define xxAttachment class): + * add_action('add_attachment', function($id) { + * //use constructor rather than factory to get around auto-draft post_status issue + * $attachment = new xxAttachment($id); + * $attachment->generatePdfImage(); + * }); + * IMPORTANT!!! in php-fpm.conf, the env[PATH] = /usr/local/bin:/usr/bin:/bin needs to be uncommented for this to work + * + * @param string $extension + * @param string $namePrefix + * @param bool $logDebug + */ + public function generatePdfImage($extension = 'png', $namePrefix = 'pdf-image-', $logDebug = false) + { + $debug = @fopen(get_stylesheet_directory() . '/debug.txt', 'a'); + $log = function ($message, $force = false) use ($debug, $logDebug) { + if ($debug && ($logDebug || $force)) { + @fwrite($debug, '[' . date('Y-m-d H:i:s') . "]: $message\n"); + } + }; + $log('checking for suitability (' . $this->ID . ", $extension, $namePrefix)"); + // IMAGEMAGICK_CONVERT should be defined in wp-config.php + if (defined('IMAGEMAGICK_CONVERT') && IMAGEMAGICK_CONVERT && $this->post_mime_type == 'application/pdf') { + $log('attempting conversion'); + + $sourceFile = get_attached_file($this->ID); + $targetFile = str_replace('.pdf', '.' . $extension, $sourceFile); + + // Converted image will have a fixed size (-extent), centred (-gravity), with the aspect ratio respected (-thumbnail), and + // excess space filled with transparent colour (-background) + $size = '260x310'; + $args = array( + '-density 96', + '-quality 85', + '-thumbnail ' . $size, // '-extent ' . $size, - '-gravity center', - '-background transparent', - escapeshellarg($sourceFile . '[0]'), - escapeshellarg($targetFile) - ); - $cmd = IMAGEMAGICK_CONVERT . ' ' . implode(' ', $args) . ' 2>&1'; - $out = exec($cmd, $output, $returnVar); - - $log($cmd); - // if the convert fails, log the output - if ($returnVar != 0) { - $log('conversion failed', true); - $log('out: ' . $out, true); - $log('output: ' . print_r($output, true), true); - $log('returnVar: ' . $returnVar, true); - } else { - //create wordpress attachment for thumbnail image - $attachmentSlug = $namePrefix . $this->ID; - $log('creating attachment: ' . $attachmentSlug); - $targetAttachment = self::fetchBySlug($attachmentSlug); - if ($targetAttachment) { - $log('deleting existing attachment: ' . $targetAttachment->ID); - wp_delete_attachment($targetAttachment->ID); - } - $id = wp_insert_attachment(array( - 'post_title' => '[Thumb] ' . $this->title(), - 'post_name' => $attachmentSlug, - 'post_content' => '', - 'post_mime_type' => 'image/' . $extension - ), $targetFile); - $log('created new attachment: ' . print_r($id, true)); - } - } else { - if (!defined('IMAGEMAGICK_CONVERT')) { - $log('ignoring: IMAGEMAGICK_CONVERT not defined'); - } else { - $log('ignoring: post type is ' . $this->post_mime_type); - } - } - @fclose($debug); - } + '-gravity center', + '-background transparent', + escapeshellarg($sourceFile . '[0]'), + escapeshellarg($targetFile) + ); + $cmd = IMAGEMAGICK_CONVERT . ' ' . implode(' ', $args) . ' 2>&1'; + $out = exec($cmd, $output, $returnVar); + + $log($cmd); + // if the convert fails, log the output + if ($returnVar != 0) { + $log('conversion failed', true); + $log('out: ' . $out, true); + $log('output: ' . print_r($output, true), true); + $log('returnVar: ' . $returnVar, true); + } else { + //create wordpress attachment for thumbnail image + $attachmentSlug = $namePrefix . $this->ID; + $log('creating attachment: ' . $attachmentSlug); + $targetAttachment = self::fetchBySlug($attachmentSlug); + if ($targetAttachment) { + $log('deleting existing attachment: ' . $targetAttachment->ID); + wp_delete_attachment($targetAttachment->ID); + } + $id = wp_insert_attachment(array( + 'post_title' => '[Thumb] ' . $this->title(), + 'post_name' => $attachmentSlug, + 'post_content' => '', + 'post_mime_type' => 'image/' . $extension + ), $targetFile); + $log('created new attachment: ' . print_r($id, true)); + } + } else { + if (!defined('IMAGEMAGICK_CONVERT')) { + $log('ignoring: IMAGEMAGICK_CONVERT not defined'); + } else { + $log('ignoring: post type is ' . $this->post_mime_type); + } + } + @fclose($debug); + } #endregion #region HTML Template helpers - public function htmlLink($attrs = array()) - { - $attrString = self::getAttributeString($attrs); - return '' . $this->title() . ""; - } - - /** - * Turns an array of key=>value attibutes into html string - * @static - * - * @param array $attrs key=>value attributes - * @return string HTML for including in an element - */ - public static function getAttributeString($attrs){ - $attributeString = ''; - foreach($attrs as $key => $value){ - $attributeString .= " $key='$value' "; - } - return $attributeString; - } - - /** - * @return WordpressTheme - */ - public static function theme() { - return WordpressTheme::getInstance(); - } - - function htmlAuthorLink() - { - return $this->callGlobalPost('get_the_author_link'); - } - - /** - * @return bool true if this is an ancestor of the page currently being viewed - */ - public function isCurrentPage() { - $x = WordpressPost::getQueriedObject(); - return (isset($x) && $x->ID == $this->ID); - } - - /** - * @return bool true if this is an ancestor of the page currently being viewed - */ - public function isCurrentPageParent() { - $x = WordpressPost::getQueriedObject(); - return (isset($x) && ($x->post_parent == $this->ID || $x->postTypeParentId() == $this->ID || $x->postTypeParentSlug() == $this->post_name)); - } - - /** - * @return bool true if this is an ancestor of the page currently being viewed - */ - public function isCurrentPageAncestor() { - $x = WordpressPost::getQueriedObject(); - while (isset($x) && $x) { - if ($x->ID == $this->ID) { - return true; - } - $x = $x->parent(); - } - return false; - } - - - protected function featuredImageAttachmentId() { + public function htmlLink($attrs = array()) + { + $attrString = self::getAttributeString($attrs); + return '' . $this->title() . ""; + } + + /** + * Turns an array of key=>value attibutes into html string + * @static + * + * @param array $attrs key=>value attributes + * @return string HTML for including in an element + */ + public static function getAttributeString($attrs) + { + $attributeString = ''; + foreach ($attrs as $key => $value) { + $attributeString .= " $key='$value' "; + } + return $attributeString; + } + + /** + * @return WordpressTheme + */ + public static function theme() + { + return WordpressTheme::getInstance(); + } + + function htmlAuthorLink() + { + return $this->callGlobalPost('get_the_author_link'); + } + + /** + * @return bool true if this is an ancestor of the page currently being viewed + */ + public function isCurrentPage() + { + $x = WordpressPost::getQueriedObject(); + return (isset($x) && $x->ID == $this->ID); + } + + /** + * @return bool true if this is an ancestor of the page currently being viewed + */ + public function isCurrentPageParent() + { + $x = WordpressPost::getQueriedObject(); + return (isset($x) && ($x->post_parent == $this->ID || $x->postTypeParentId() == $this->ID || $x->postTypeParentSlug() == $this->post_name)); + } + + /** + * @return bool true if this is an ancestor of the page currently being viewed + */ + public function isCurrentPageAncestor() + { + $x = WordpressPost::getQueriedObject(); + while (isset($x) && $x) { + if ($x->ID == $this->ID) { + return true; + } + $x = $x->parent(); + } + return false; + } + + + protected function featuredImageAttachmentId() + { $image = $this->metadata('featured_image', true) ?: $this->metadata('image', true); if ($image) { @@ -866,52 +896,62 @@ protected function featuredImageAttachmentId() { return false; } - public function featuredImageUrl($image_size = 'thumbnail'){ - $image = wp_get_attachment_image_src($this->featuredImageAttachmentId(), $image_size); - return $image ? $image[0] : null; - } - - public function featuredImage($size = 'thumbnail', $attrs = array()){ - return wp_get_attachment_image($this->featuredImageAttachmentId(), $size, 0, $attrs); - } - - /** - * Gets the list of elements that comprise a breadcrumb trail - */ - function breadcrumbs(){ - $ancestors = array($this->title()); - $current = $this; - while($parent = $current->parent()){ - $ancestors[] = $parent->htmlLink(); - $current = $parent; - } - $home = self::fetchHomepage(); - if ($home && $this->ID != $home->ID) { - $ancestors[] = $home->htmlLink(); - } - return array_reverse($ancestors); - } - - /** - * @return OowpQuery - */ - public function attachments(){ - $queryArgs = array( 'post_type' => 'attachment', 'numberposts' => -1, 'post_status' => 'inherit', 'post_parent' => $this->ID ); - return new OowpQuery($queryArgs); - } + public function featuredImageUrl($image_size = 'thumbnail') + { + $image = wp_get_attachment_image_src($this->featuredImageAttachmentId(), $image_size); + return $image ? $image[0] : null; + } + + public function featuredImage($size = 'thumbnail', $attrs = array()) + { + return wp_get_attachment_image($this->featuredImageAttachmentId(), $size, 0, $attrs); + } + + /** + * Gets the list of elements that comprise a breadcrumb trail + */ + function breadcrumbs() + { + $ancestors = array($this->title()); + $current = $this; + while ($parent = $current->parent()) { + $ancestors[] = $parent->htmlLink(); + $current = $parent; + } + $home = self::fetchHomepage(); + if ($home && $this->ID != $home->ID) { + $ancestors[] = $home->htmlLink(); + } + return array_reverse($ancestors); + } + + /** + * @return OowpQuery + */ + public function attachments() + { + $queryArgs = array( + 'post_type' => 'attachment', + 'numberposts' => -1, + 'post_status' => 'inherit', + 'post_parent' => $this->ID + ); + return new OowpQuery($queryArgs); + } #endregion #region Static functions - /** - * @static - * Called by register(), for registering this post type - * - * @return array Array of arguments used by register_post - */ - static function getRegistrationArgs() { - return array( + /** + * @static + * Called by register(), for registering this post type + * + * @return array Array of arguments used by register_post + */ + static function getRegistrationArgs() + { + return array( 'labels' => AdminUtils::generateLabels(static::friendlyName(), static::friendlyNamePlural()), 'public' => true, 'has_archive' => true, @@ -927,42 +967,45 @@ static function getRegistrationArgs() { 'revisions', ) ); - } - - /** - * Use this in combination with getCustomAdminColumnValue to add custom columns to the wp admin interface for the post. - * @static - * - * @param ArrayHelper $helper Contains the default columns - */ - static function addCustomAdminColumns(ArrayHelper $helper) { /* do nothing */ } - - /** - * Use this in combination with addCustomAdminColumns to get the column value for a post - * - * @param string $column The name of the column, as given in addCustomAdminColumns - * @return string - */ - function getCustomAdminColumnValue($column) - { - return ''; - } - - /** - * Gets the queried object (i.e. the post/page currently being viewed) - * @static - * - * @return null|WordpressPost - */ - static function getQueriedObject() { - global $ooQueriedObject; - if (!isset($ooQueriedObject)) { - global $wp_the_query; - $id = $wp_the_query->get_queried_object_id(); - $ooQueriedObject = $id ? WordpressPost::fetchById($id) : null; - } - return $ooQueriedObject; - } + } + + /** + * Use this in combination with getCustomAdminColumnValue to add custom columns to the wp admin interface for the post. + * @static + * + * @param ArrayHelper $helper Contains the default columns + */ + static function addCustomAdminColumns(ArrayHelper $helper) + { /* do nothing */ + } + + /** + * Use this in combination with addCustomAdminColumns to get the column value for a post + * + * @param string $column The name of the column, as given in addCustomAdminColumns + * @return string + */ + function getCustomAdminColumnValue($column) + { + return ''; + } + + /** + * Gets the queried object (i.e. the post/page currently being viewed) + * @static + * + * @return null|WordpressPost + */ + static function getQueriedObject() + { + global $ooQueriedObject; + if (!isset($ooQueriedObject)) { + global $wp_the_query; + $id = $wp_the_query->get_queried_object_id(); + $ooQueriedObject = $id ? WordpressPost::fetchById($id) : null; + } + return $ooQueriedObject; + } /** * @static Creates a p2p connection to another post type @@ -972,157 +1015,164 @@ static function getQueriedObject() { * @param string $connectionName * @return mixed */ - static function registerConnection($targetPostType, $parameters = array(), $connectionName = null) - { - return PostTypeManager::get()->registerConnection(self::postType(), $targetPostType, $parameters, $connectionName); - } - - /** - * Factory method for creating a post of the appropriate WordpressPost subclass, for the given data - * @static - * - * @param object|int $data - * @return WordpressPost|null - */ - public static function createWordpressPost($data = null) { - if ($data) { - if ($data instanceof WordpressPost) { - return $data; - } - $postData = self::getPostObject($data); - if ($postData) { - $className = PostTypeManager::get()->getClassName($postData->post_type); + static function registerConnection($targetPostType, $parameters = array(), $connectionName = null) + { + return PostTypeManager::get()->registerConnection(self::postType(), $targetPostType, $parameters, + $connectionName); + } + + /** + * Factory method for creating a post of the appropriate WordpressPost subclass, for the given data + * @static + * + * @param object|int $data + * @return WordpressPost|null + */ + public static function createWordpressPost($data = null) + { + if ($data) { + if ($data instanceof WordpressPost) { + return $data; + } + $postData = self::getPostObject($data); + if ($postData) { + $className = PostTypeManager::get()->getClassName($postData->post_type); if (!$className) { $className = 'Outlandish\Wordpress\Oowp\PostTypes\MiscPost'; } - if ($postData instanceof $className) { - return $postData; - } else { - return new $className($postData); - } - } - } - return null; - } - - /** - * Factory method for creating a post of the appropriate WordpressPost subclass, for the given post ID - * @static - * - * @param int|int[] $ids - * @return WordpressPost|OowpQuery|null - */ - public static function fetchById($ids) { - if (is_array($ids) && $ids){ - return new OowpQuery(array('post__in' => $ids)); - }elseif($ids){ - return static::fetchOne(array('p' => $ids)); - }else{ - throw new \Exception("no IDs supplied to WordpressPost::fetchById()"); - } - } - - public static function fetchBySlug($slug){ - return static::fetchOne(array('name' => $slug)); - } - - /** - * @static - * - * @param array $queryArgs Accepts a wp_query $queryArgs array which overwrites the defaults - * @return OowpQuery - */ - public static function fetchAll($queryArgs = array()) - { - $defaults = array( - 'post_type' => static::getSelfPostTypeConstraint() - ); - if (static::isHierarchical()) { - $defaults['orderby'] = 'menu_order'; - $defaults['order'] = 'asc'; - } - - $queryArgs = wp_parse_args($queryArgs, $defaults); - $query = new OowpQuery($queryArgs); - - return $query; - } - - /** - * @deprecated - */ - static function fetchAllQuery($queryArgs = array()) - { - return static::fetchAll($queryArgs); - } - - /** - * @static - * - * @return null|WordpressPost - */ - static function fetchHomepage() { - $key = 'homepage'; - if (!array_key_exists($key, WordpressPost::$_staticCache)) { - $id = get_option('page_on_front'); - WordpressPost::$_staticCache[$key] = $id ? self::fetchById($id) : null; - } - return WordpressPost::$_staticCache[$key]; - } - - /** - * @return bool True if this is the site homepage - */ - public function isHomepage() { - return $this->ID == get_option('page_on_front'); - } - - /** - * Return the first post matching the arguments - * @static - * - * @param array $queryArgs - * @return null|WordpressPost - */ - static function fetchOne($queryArgs) - { - $queryArgs['posts_per_page'] = 1; // Force-override this rather than only setting a default. + if ($postData instanceof $className) { + return $postData; + } else { + return new $className($postData); + } + } + } + return null; + } + + /** + * Factory method for creating a post of the appropriate WordpressPost subclass, for the given post ID + * @static + * + * @param int|int[] $ids + * @return WordpressPost|OowpQuery|null + */ + public static function fetchById($ids) + { + if (is_array($ids) && $ids) { + return new OowpQuery(array('post__in' => $ids)); + } elseif ($ids) { + return static::fetchOne(array('p' => $ids)); + } else { + throw new \Exception("no IDs supplied to WordpressPost::fetchById()"); + } + } + + public static function fetchBySlug($slug) + { + return static::fetchOne(array('name' => $slug)); + } + + /** + * @static + * + * @param array $queryArgs Accepts a wp_query $queryArgs array which overwrites the defaults + * @return OowpQuery + */ + public static function fetchAll($queryArgs = array()) + { $defaults = array( 'post_type' => static::getSelfPostTypeConstraint() ); + if (static::isHierarchical()) { + $defaults['orderby'] = 'menu_order'; + $defaults['order'] = 'asc'; + } + $queryArgs = wp_parse_args($queryArgs, $defaults); + $query = new OowpQuery($queryArgs); + + return $query; + } + + /** + * @deprecated + */ + static function fetchAllQuery($queryArgs = array()) + { + return static::fetchAll($queryArgs); + } + + /** + * @static + * + * @return null|WordpressPost + */ + static function fetchHomepage() + { + $key = 'homepage'; + if (!array_key_exists($key, WordpressPost::$_staticCache)) { + $id = get_option('page_on_front'); + WordpressPost::$_staticCache[$key] = $id ? self::fetchById($id) : null; + } + return WordpressPost::$_staticCache[$key]; + } + + /** + * @return bool True if this is the site homepage + */ + public function isHomepage() + { + return $this->ID == get_option('page_on_front'); + } + + /** + * Return the first post matching the arguments + * @static + * + * @param array $queryArgs + * @return null|WordpressPost + */ + static function fetchOne($queryArgs) + { + $queryArgs['posts_per_page'] = 1; // Force-override this rather than only setting a default. + $defaults = array( + 'post_type' => static::getSelfPostTypeConstraint() + ); + $queryArgs = wp_parse_args($queryArgs, $defaults); + + $query = new OowpQuery($queryArgs); + return $query->posts ? $query->post : null; + } - $query = new OowpQuery($queryArgs); - return $query->posts ? $query->post : null; - } - - /** - * @static Returns the roots of this post type (i.e those whose post_parent is self::postTypeParentId) - * - * @param array $queryArgs - * @return OowpQuery - */ - static function fetchRoots($queryArgs = array()) - { - // TODO Perhaps the post_parent should be set properly in the database. - //$queryArgs['post_parent'] = static::postTypeParentId(); - $queryArgs['post_parent'] = self::postTypeParentId(); - return static::fetchAll($queryArgs); - } - - - /** - * @static - * - * @param string $postType - * @return bool Whether or not the post type is declared as hierarchical - */ - static function isHierarchical($postType = null) { - if (!$postType) { - $postType = static::postType(); - } - return is_post_type_hierarchical($postType); - } + /** + * @static Returns the roots of this post type (i.e those whose post_parent is self::postTypeParentId) + * + * @param array $queryArgs + * @return OowpQuery + */ + static function fetchRoots($queryArgs = array()) + { + // TODO Perhaps the post_parent should be set properly in the database. + //$queryArgs['post_parent'] = static::postTypeParentId(); + $queryArgs['post_parent'] = self::postTypeParentId(); + return static::fetchAll($queryArgs); + } + + + /** + * @static + * + * @param string $postType + * @return bool Whether or not the post type is declared as hierarchical + */ + static function isHierarchical($postType = null) + { + if (!$postType) { + $postType = static::postType(); + } + return is_post_type_hierarchical($postType); + } private static function getSelfPostTypeConstraint() { diff --git a/src/QueryVars.php b/src/QueryVars.php index 01e7d1f..0eff276 100644 --- a/src/QueryVars.php +++ b/src/QueryVars.php @@ -2,32 +2,37 @@ namespace Outlandish\Wordpress\Oowp; -class QueryVars { - private $args; +class QueryVars +{ + private $args; - function __construct($data) { - if ($data instanceof \WP_Query) { - $this->args = $data->query_vars; - } else { - $this->args = $data; - } - } + function __construct($data) + { + if ($data instanceof \WP_Query) { + $this->args = $data->query_vars; + } else { + $this->args = $data; + } + } - public function hasArg($arg) { - return isset($this->args[$arg]); - } + public function hasArg($arg) + { + return isset($this->args[$arg]); + } - public function arg($arg) { - return $this->args[$arg]; - } + public function arg($arg) + { + return $this->args[$arg]; + } - public function isForPostType($postType) { - $postTypes = $this->args['post_type']; - if (is_array($postTypes)) { - // TODO: Is this correct? - return in_array($postType, $postTypes); - } else { - return $postTypes == 'any' || $postTypes == $postType; - } - } -} \ No newline at end of file + public function isForPostType($postType) + { + $postTypes = $this->args['post_type']; + if (is_array($postTypes)) { + // TODO: Is this correct? + return in_array($postType, $postTypes); + } else { + return $postTypes == 'any' || $postTypes == $postType; + } + } +} diff --git a/src/Util/AdminUtils.php b/src/Util/AdminUtils.php index d3d7b8f..3ffae85 100644 --- a/src/Util/AdminUtils.php +++ b/src/Util/AdminUtils.php @@ -7,174 +7,179 @@ class AdminUtils { - /** @var WordpressPost[] */ - static $customColumnsCache = []; - - /** - * Customises admin UI - */ - static function customiseAdmin() - { - $disabledPostTypes = apply_filters('oowp_disabled_post_types', ['post']); - - // make disabled post types private (can't remove them entirely) - add_action('register_post_type_args', function ($args, $postType) use ($disabledPostTypes) { - if (in_array($postType, $disabledPostTypes)) { - $args['public'] = false; - } - return $args; - }, 10, 2); - - // prevent users accessing the post-new.php and edit.php pages for disabled post types - add_action('load-post-new.php', function() use ($disabledPostTypes) { - $postType = get_current_screen()->post_type; - if (in_array($postType, $disabledPostTypes)) { - wp_die('Invalid post type'); - } - }); - add_action('load-edit.php', function() use ($disabledPostTypes) { - $postType = get_current_screen()->post_type; - if (in_array($postType, $disabledPostTypes)) { - wp_die('Invalid post type'); - } - }); - - add_action('oowp/all_post_types_registered', function ($postTypes) { - $publicDir = plugin_dir_url(realpath(__DIR__ . '/../../public') . '/fake.txt'); - if (is_admin()) { - add_action('admin_head', function() use ($postTypes) { - self::addAdminStyles($postTypes); - }); - add_action('admin_menu', function() { - remove_menu_page('link-manager.php'); - }); - wp_enqueue_script('oowp_admin_js', $publicDir . '/oowp-admin.js', array('jquery'), false, true); - wp_enqueue_style('oowp_admin_css', $publicDir . '/oowp-admin.css'); - } else { - wp_enqueue_style('oowp_css', $publicDir . '/oowp.css'); - } - - foreach ($postTypes as $className => $postType) { - /** @var string $postType */ - /** @var WordpressPost $className Actually a class name string, but we're using static methods on those classes */ - - // add any custom columns - add_filter("manage_edit-{$postType}_columns", function($defaults) use ($className) { - if (isset($_GET['post_status']) && $_GET['post_status'] == 'trash') { - return $defaults; - } else { - $helper = new ArrayHelper($defaults); - $className::addCustomAdminColumns($helper); - return $helper->array; - } - }); - - // populate the custom columns for each post - add_action("manage_{$postType}_posts_custom_column", function($column, $post_id) { - // cache each post, to avoid re-fetching - if (!isset(self::$customColumnsCache[$post_id])) { - $status = empty($_GET['post_status']) ? '' : $_GET['post_status']; - $query = new OowpQuery(array('p'=>$post_id, 'posts_per_page'=>1, 'post_status'=>$status)); - self::$customColumnsCache[$post_id] = ($query->post_count ? $query->post : null); - } - if (self::$customColumnsCache[$post_id]) { - echo self::$customColumnsCache[$post_id]->getCustomAdminColumnValue($column); - } - }, 10, 2); - } - - // append the count(s) to the end of the 'at a glance' box on the dashboard - add_action('dashboard_glance_items', function($items) use ($postTypes) { - foreach ($postTypes as $className => $postType) { - /** @var WordpressPost $className */ - if ($postType != 'post' && $postType != 'page') { - $singular = $className::friendlyName(); - $plural = $className::friendlyNamePlural(); - - $numPosts = wp_count_posts($postType); - $postTypeObject = get_post_type_object($postType); - - if ($postTypeObject->show_ui) { - $count = $numPosts->publish; - $text = number_format_i18n($count) . ' ' . _n($singular, $plural, intval($count) ); - if ( current_user_can( 'edit_posts' )) { - $icon = $postTypeObject->menu_icon ? '' : ''; - $iconSuffix = $icon ? 'icon' : 'no-icon'; - $items[] = "
{$icon}$text
"; - } - } - } - } - return $items; - }); - }); - } - - /** - * Attempts to style each post type menu item and posts page with its own custom image icon, as found in the - * theme's 'images' directory. - * In order to be automatically styled, icon filenames should have the following forms: - * - icon-{post_type} (for posts pages, next to header) - * - icon-menu-{post_type} (for menu items) - * - icon-menu-active-{post_type} (for menu items when active/hovered) - * @param string[] $postTypes - */ - protected static function addAdminStyles($postTypes) - { - $imagesDir = get_template_directory() . DIRECTORY_SEPARATOR . 'images'; - $styles = array(); - if (is_dir($imagesDir)) { - $handle = opendir($imagesDir); - while (false !== ($file = readdir($handle))) { - $fullFile = $imagesDir . DIRECTORY_SEPARATOR . $file; - if (is_dir($fullFile) || !filesize($fullFile)) { - continue; - } - - $imageSize = @getimagesize($fullFile); - if (!$imageSize || !$imageSize[0] || !$imageSize[1]) { - continue; - } - - foreach ($postTypes as $postType) { - if (preg_match('/icon(-menu(-active)?)?-' . $postType . '\.\w+$/', $file, $matches)) { - if (!array_key_exists($postType, $styles)) { - $styles[$postType] = array(); - } - if (count($matches) == 3) { - $type = 'active-menu'; - } else if (count($matches) == 2) { - $type = 'menu'; - } else { - $type = 'page'; - } - $styles[$postType][$type] = $file; - } - } - } - } - if ($styles) { - $patterns = array( - 'menu' => '#adminmenu #menu-posts-{post_type} .wp-menu-image', - 'active-menu' => '#adminmenu #menu-posts-{post_type}:hover .wp-menu-image, #adminmenu #menu-posts-{post_type}.wp-has-current-submenu .wp-menu-image', - 'page' => '.icon32-posts-{post_type}' - ); - echo ''; - } - } - - static function generateLabels($singular, $plural = null) { + } + } + } + echo ''; + } + } + + static function generateLabels($singular, $plural = null) + { if (!$plural) { $plural = $singular . 's'; } @@ -188,7 +193,7 @@ static function generateLabels($singular, $plural = null) { 'all_items' => 'All ' . $plural, 'view_item' => 'View ' . $singular, 'search_items' => 'Search ' . $plural, - 'not_found' => 'No ' . $plural . ' found', + 'not_found' => 'No ' . $plural . ' found', 'not_found_in_trash' => 'No ' . $plural . ' found in Trash', 'parent_item_colon' => 'Parent ' . $singular . ':', 'menu_name' => $plural diff --git a/src/Util/ReflectionUtils.php b/src/Util/ReflectionUtils.php index 0f9a56a..be27552 100644 --- a/src/Util/ReflectionUtils.php +++ b/src/Util/ReflectionUtils.php @@ -4,31 +4,33 @@ class ReflectionUtils { - /** - * Returns the name of the function that called whatever called the caller :) - * e.g. if theFunction() called theOtherFunction(), theOtherFunction() could call getCaller(), which - * would return 'theFunction' - * @return string - */ - public static function getCaller() { - return self::getCaller_internal(__FUNCTION__, 2); - } - - public static function getCaller_internal($function, $diff) { - - $stack = debug_backtrace(); - $stackSize = count($stack); - - $caller = ''; - for ($i = 0; $i < $stackSize; $i++) { - if ($stack[$i]['function'] == $function && ($i + $diff) < $stackSize) { - $caller = $stack[$i + $diff]['function']; - break; - } - } - - return $caller; - } - - -} \ No newline at end of file + /** + * Returns the name of the function that called whatever called the caller :) + * e.g. if theFunction() called theOtherFunction(), theOtherFunction() could call getCaller(), which + * would return 'theFunction' + * @return string + */ + public static function getCaller() + { + return self::getCaller_internal(__FUNCTION__, 2); + } + + public static function getCaller_internal($function, $diff) + { + + $stack = debug_backtrace(); + $stackSize = count($stack); + + $caller = ''; + for ($i = 0; $i < $stackSize; $i++) { + if ($stack[$i]['function'] == $function && ($i + $diff) < $stackSize) { + $caller = $stack[$i + $diff]['function']; + break; + } + } + + return $caller; + } + + +} diff --git a/src/Util/StringUtils.php b/src/Util/StringUtils.php index 0fbe62a..53a2b8a 100644 --- a/src/Util/StringUtils.php +++ b/src/Util/StringUtils.php @@ -4,32 +4,36 @@ class StringUtils { - /** - * Translates a camel case string into a string with underscores (e.g. firstName -> first_name) - * @param string $str String in camel case format - * @return string $str Translated into underscore format - */ - static function fromCamelCase($str) - { - $str[0] = strtolower($str[0]); - return preg_replace_callback( - '/([A-Z])/', function($c){ return "_" . strtolower($c[1]); }, $str); + /** + * Translates a camel case string into a string with underscores (e.g. firstName -> first_name) + * @param string $str String in camel case format + * @return string $str Translated into underscore format + */ + static function fromCamelCase($str) + { + $str[0] = strtolower($str[0]); + return preg_replace_callback( + '/([A-Z])/', function ($c) { + return "_" . strtolower($c[1]); + }, $str); - } + } - /** - * Translates a string with underscores into camel case (e.g. first_name -> firstName) - * @param string $str String in underscore format - * @param bool $capitalise_first_char If true, capitalise the first char in $str - * @return string $str translated into camel caps - */ - static function toCamelCase($str, $capitalise_first_char = false) - { - if ($capitalise_first_char) { - $str[0] = strtoupper($str[0]); - } - return preg_replace_callback('/_([a-z])/', function ($c){return strtoupper($c[1]);}, $str); - } + /** + * Translates a string with underscores into camel case (e.g. first_name -> firstName) + * @param string $str String in underscore format + * @param bool $capitalise_first_char If true, capitalise the first char in $str + * @return string $str translated into camel caps + */ + static function toCamelCase($str, $capitalise_first_char = false) + { + if ($capitalise_first_char) { + $str[0] = strtoupper($str[0]); + } + return preg_replace_callback('/_([a-z])/', function ($c) { + return strtoupper($c[1]); + }, $str); + } } diff --git a/src/Views/OowpView.php b/src/Views/OowpView.php index 00d009e..7f7010a 100644 --- a/src/Views/OowpView.php +++ b/src/Views/OowpView.php @@ -12,7 +12,7 @@ abstract class OowpView public function __construct($args = []) { $this->theme = WordpressTheme::getInstance(); - foreach($args as $name => $value) { + foreach ($args as $name => $value) { $this->$name = $value; } } diff --git a/src/Views/PostMenuItem.php b/src/Views/PostMenuItem.php index 72a01f9..ed4d939 100644 --- a/src/Views/PostMenuItem.php +++ b/src/Views/PostMenuItem.php @@ -6,7 +6,7 @@ class PostMenuItem extends PostView { public function render($args = []) { - $post = $this->post; + $post = $this->post; $classes = ['page_item', 'page-item-' . $post->ID]; if ($post->isCurrentPage()) { $classes[] = 'current_page_item'; @@ -18,7 +18,7 @@ public function render($args = []) $classes[] = 'current_page_ancestor'; } $children = $post->children(); - $args = array_merge([ + $args = array_merge([ 'max_depth' => 0, 'current_depth' => 1 ], $args); @@ -26,19 +26,19 @@ public function render($args = [])
  • title(); ?> - post_count && ( !$args['max_depth'] || $args['current_depth'] < $args['max_depth'] )): ?> - + post_count && (!$args['max_depth'] || $args['current_depth'] < $args['max_depth'])): ?> +
  • description ?: "Latest news from {$this->name}"; - $title = $this->title ?: "{$this->name} latest updates"; -?> + $title = $this->title ?: "{$this->name} latest updates"; + ?> <?php echo $title; ?> - url; ?> + url; ?> - 1800 - 1800 + items as $item) { - $view->post = $item; - $view->render(); - } + $view = new RssItem(); + foreach ($this->items as $item) { + $view->post = $item; + $view->render(); + } } -} \ No newline at end of file +} diff --git a/src/WordpressTheme.php b/src/WordpressTheme.php index b7378a5..3880370 100644 --- a/src/WordpressTheme.php +++ b/src/WordpressTheme.php @@ -8,32 +8,37 @@ * Subclass this in your theme's classes directory, and put all theme-specific functionality in its init() function * instead of in functions.php, then call init() inside a wordpress 'init' action listener */ -class WordpressTheme { +class WordpressTheme +{ private static $instance; - protected $allHooks = array(); - private $acfFields = array(); + protected $allHooks = array(); + private $acfFields = array(); - protected function __construct(){ - } + protected function __construct() + { + } /** * @static * * @return self Singleton instance */ - public static function getInstance() { + public static function getInstance() + { if (!isset(self::$instance)) { self::$instance = new static(); } return self::$instance; } - public function init() { + public function init() + { } - public function siteInfo($info) { + public function siteInfo($info) + { return get_bloginfo($info); } @@ -43,7 +48,8 @@ public function siteInfo($info) { * No trailing slash as standard (http://www.example.com), if trailing slash is required, include as first argument, ($a = '/') * second argument returns protocol for the url (http, https, etc) - see http://codex.wordpress.org/Function_Reference/site_url for more info */ - public function siteURL($relativePath = '') { + public function siteURL($relativePath = '') + { return site_url(null, null) . '/' . ltrim($relativePath, '/'); } @@ -51,162 +57,182 @@ public function siteURL($relativePath = '') { * No trailing slash as standard (http://www.example.com), if trailing slash is required, include as first argument, ($a = '/') * second argument returns protocol for the url (http, https, etc) - see http://codex.wordpress.org/Function_Reference/site_url for more info */ - public function homeURL($relativePath = '') { + public function homeURL($relativePath = '') + { return home_url(null, null) . '/' . ltrim($relativePath, '/'); } - /** - * Gets the url for an asset in this theme. - * With no argument, this is just the root directory of this theme - * - * @param string $relativePath - * @return string - */ - public function assetUrl($relativePath = '') { - $relativePath = '/' . ltrim($relativePath, '/'); - return get_template_directory_uri() . $relativePath; - } - - public function imageUrl($fileName) { - return $this->assetUrl('/images/' . $fileName); - } - - public function jsUrl($fileName) { - return $this->assetUrl('/js/' . $fileName); - } - - public function cssUrl($fileName) { - return $this->assetUrl('/css/' . $fileName); - } - - /** - * @deprecated Use assetUrl() instead - * - * @return string - */ - public function siteThemeURL() { + /** + * Gets the url for an asset in this theme. + * With no argument, this is just the root directory of this theme + * + * @param string $relativePath + * @return string + */ + public function assetUrl($relativePath = '') + { + $relativePath = '/' . ltrim($relativePath, '/'); + return get_template_directory_uri() . $relativePath; + } + + public function imageUrl($fileName) + { + return $this->assetUrl('/images/' . $fileName); + } + + public function jsUrl($fileName) + { + return $this->assetUrl('/js/' . $fileName); + } + + public function cssUrl($fileName) + { + return $this->assetUrl('/css/' . $fileName); + } + + /** + * @return string + * @deprecated Use assetUrl() instead + * + */ + public function siteThemeURL() + { return $this->assetUrl(); } - public function directory($path = '') { + public function directory($path = '') + { return get_stylesheet_directory() . DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR); } - public function siteTitle() { + public function siteTitle() + { return $this->siteInfo('name'); } - public function htmlTitle() { - return wp_title('«', true, 'right') . ' ' . $this->siteTitle(); - } + public function htmlTitle() + { + return wp_title('«', true, 'right') . ' ' . $this->siteTitle(); + } + + /** + * @param bool $parent + * @deprecated Use addImageSize instead + * + */ + public function addImageSizes($parent = true) + { + if (function_exists('add_image_size')) { + add_image_size('category-thumb', 300, 9999); //300 pixels wide (and unlimited height) + add_image_size('homepage-thumb', 220, 180, true); //(cropped) + } + } + + /** + * Adds an image size to the theme, and adds the hook that ensures the thumbnails get resized when edited through the CMS + * + * @param string $name + * @param string $width + * @param string $height + * @param bool $crop + */ + public function addImageSize($name, $width, $height, $crop = false) + { + if (function_exists('add_image_size')) { + add_image_size($name, $width, $height, $crop); + add_action('image_save_pre', array($this, 'addImageOptions')); + } + } + + function addImageOptions($data) + { + global $_wp_additional_image_sizes; + foreach ($_wp_additional_image_sizes as $size => $properties) { + update_option($size . "_size_w", $properties['width']); + update_option($size . "_size_h", $properties['height']); + update_option($size . "_crop", $properties['crop']); + } + return $data; + } + + public static function slugify($label) + { + return str_replace(' ', '-', strtolower($label)); + } + + public static function labelify($slug) + { + return ucwords(str_replace('-', ' ', $slug)); + } + + /** + * @return \wpdb + */ + public function db() + { + global $wpdb; + return $wpdb; + } + + /** + * Gets an ACF options value + * + * @param string $optionName + * @return mixed + */ + public function acfOption($optionName) + { + return get_field($optionName, 'option'); + } + + /** + * Gets the acf definitions, keyed by their hierarchical name (using hyphens). + * If $name is provided, a single acf definition is returned (if found) + * + * @param string $acfPostName + * @param string $name + * @return array|null + */ + public function acf($acfPostName, $name = null) + { + if (!isset($this->acfFields[$acfPostName])) { + $wpdb = $this->db(); + // TODO Use wpdb->prepare() + $acfData = $wpdb->get_col("SELECT pm.meta_value FROM $wpdb->posts AS p INNER JOIN $wpdb->postmeta AS pm ON p.ID = pm.post_id WHERE p.post_name = 'acf_{$acfPostName}' AND pm.meta_key like 'field_%'"); + $acfFields = array(); + $this->populateAcf($acfFields, $acfData); + $this->acfFields[$acfPostName] = $acfFields; + } + if ($name) { + return array_key_exists($name, + $this->acfFields[$acfPostName]) ? $this->acfFields[$acfPostName][$name] : null; + } + + return $this->acfFields[$acfPostName]; + } - /** - * @deprecated Use addImageSize instead - * - * @param bool $parent - */ - public function addImageSizes($parent = true){ - if ( function_exists( 'add_image_size' ) ) { - add_image_size( 'category-thumb', 300, 9999 ); //300 pixels wide (and unlimited height) - add_image_size( 'homepage-thumb', 220, 180, true ); //(cropped) + /** + * Recursively populates the acf definitions list + * + * @param array $toPopulate + * @param array $data The ACF definition from the database + * @param string $prefix The prefix to use in the name. (only applicable to hierarchical fields, i.e. repeater fields) + */ + private function populateAcf(&$toPopulate, $data, $prefix = '') + { + foreach ($data as $acf) { + $acf = maybe_unserialize($acf); + $toPopulate[$prefix . $acf['name']] = $acf; + if (!empty($acf['sub_fields'])) { + $this->populateAcf($toPopulate, $acf['sub_fields'], $acf['name'] . '-'); + } } } - /** - * Adds an image size to the theme, and adds the hook that ensures the thumbnails get resized when edited through the CMS - * - * @param string $name - * @param string $width - * @param string $height - * @param bool $crop - */ - public function addImageSize($name, $width, $height, $crop = false){ - if ( function_exists( 'add_image_size' ) ) { - add_image_size( $name, $width, $height, $crop); - add_action('image_save_pre', array($this, 'addImageOptions')); - } - } - - function addImageOptions($data){ - global $_wp_additional_image_sizes; - foreach($_wp_additional_image_sizes as $size => $properties){ - update_option($size."_size_w", $properties['width']); - update_option($size."_size_h", $properties['height']); - update_option($size."_crop", $properties['crop']); - } - return $data; - } - - public static function slugify($label) { - return str_replace(' ', '-', strtolower($label)); - } - - public static function labelify($slug) { - return ucwords(str_replace('-', ' ', $slug)); - } - - /** - * @return \wpdb - */ - public function db() { - global $wpdb; - return $wpdb; - } - - /** - * Gets an ACF options value - * - * @param string $optionName - * @return mixed - */ - public function acfOption($optionName) { - return get_field($optionName, 'option'); - } - - /** - * Gets the acf definitions, keyed by their hierarchical name (using hyphens). - * If $name is provided, a single acf definition is returned (if found) - * - * @param string $acfPostName - * @param string $name - * @return array|null - */ - public function acf($acfPostName, $name = null) { - if (!isset($this->acfFields[$acfPostName])) { - $wpdb = $this->db(); - // TODO Use wpdb->prepare() - $acfData = $wpdb->get_col("SELECT pm.meta_value FROM $wpdb->posts AS p INNER JOIN $wpdb->postmeta AS pm ON p.ID = pm.post_id WHERE p.post_name = 'acf_{$acfPostName}' AND pm.meta_key like 'field_%'"); - $acfFields = array(); - $this->populateAcf($acfFields, $acfData); - $this->acfFields[$acfPostName] = $acfFields; - } - if ($name) { - return array_key_exists($name, $this->acfFields[$acfPostName]) ? $this->acfFields[$acfPostName][$name] : null; - } - - return $this->acfFields[$acfPostName]; - } - - /** - * Recursively populates the acf definitions list - * - * @param array $toPopulate - * @param array $data The ACF definition from the database - * @param string $prefix The prefix to use in the name. (only applicable to hierarchical fields, i.e. repeater fields) - */ - private function populateAcf(&$toPopulate, $data, $prefix = '') { - foreach ($data as $acf) { - $acf = maybe_unserialize($acf); - $toPopulate[$prefix . $acf['name']] = $acf; - if (!empty($acf['sub_fields'])) { - $this->populateAcf($toPopulate, $acf['sub_fields'], $acf['name'] . '-'); - } - } - } - - public static function currentUser() { - global $current_user; - get_currentuserinfo(); - return $current_user; - } + public static function currentUser() + { + global $current_user; + get_currentuserinfo(); + return $current_user; + } }