From f706619ea28c763247cbf47f83f92250b1d33c36 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 16 Oct 2016 15:02:22 +0100 Subject: [PATCH] Query class, fix routing and usability tweaks --- src/Facades/Query.php | 23 +++++++++++++++++++++++ src/Models/Meta.php | 3 ++- src/Models/Post.php | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/Models/User.php | 18 +++++++++++++++--- src/Models/UserMeta.php | 7 ++++--- src/Providers/WordpressServiceProvider.php | 5 +++++ src/Proxy/Query.php | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Routing/ArchiveRoute.php | 12 +----------- src/Routing/AuthorRoute.php | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Routing/PageRoute.php | 12 ++++++++---- src/Routing/Routing.php | 39 +++++++++++++++++++++++++++++++++++---- src/Routing/RoutingServiceProvider.php | 1 + src/Routing/SingularRoute.php | 12 +----------- src/Routing/TemplateRoute.php | 23 +++++++++++++++-------- src/Support/Wordpress.php | 51 +++++++++++++++++++++++++++------------------------ 15 files changed, 378 insertions(+), 74 deletions(-) create mode 100644 src/Facades/Query.php create mode 100644 src/Proxy/Query.php create mode 100644 src/Routing/AuthorRoute.php diff --git a/src/Facades/Query.php b/src/Facades/Query.php new file mode 100644 index 0000000..47d6b31 --- /dev/null +++ b/src/Facades/Query.php @@ -0,0 +1,23 @@ + + */ +class Query extends Facade +{ + /** + * Get the registered name of the component. + * + * @return string + */ + protected static function getFacadeAccessor() + { + return 'query'; + } +} diff --git a/src/Models/Meta.php b/src/Models/Meta.php index 8c84c9f..d23728e 100644 --- a/src/Models/Meta.php +++ b/src/Models/Meta.php @@ -14,7 +14,8 @@ use Koselig\Support\Wordpress; */ class Meta extends Model { - public $table = DB_PREFIX . 'postmeta'; + protected $table = DB_PREFIX . 'postmeta'; + public $timestamps = false; /** * Cache for all meta values. diff --git a/src/Models/Post.php b/src/Models/Post.php index 755aa78..6512c32 100644 --- a/src/Models/Post.php +++ b/src/Models/Post.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Koselig\Exceptions\UnsatisfiedDependencyException; use Koselig\Support\Action; +use WP_Post; /** * Table containing all the items within the CMS. @@ -16,13 +17,11 @@ use Koselig\Support\Action; */ class Post extends Model { - public $table = DB_PREFIX . 'posts'; - public $primaryKey = 'ID'; - + protected $table = DB_PREFIX . 'posts'; + protected $primaryKey = 'ID'; + protected $dates = ['post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt']; public $timestamps = false; - public $dates = ['post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt']; - /** * Get all the posts within a certain post type. * @@ -138,6 +137,75 @@ class Post extends Model } /** + * Get the categories of this post. + * + * @see get_the_category + * @return array + */ + public function category() + { + return get_the_category($this->ID); + } + + /** + * Get the permalink for this post. + * + * @see get_permalink + * @return false|string + */ + public function link() + { + return get_permalink($this->toWordpressPost()); + } + + /** + * Get the tags of this post. + * + * @see get_the_tags + * @return array|false|\WP_Error + */ + public function tags() + { + return get_the_tags($this->ID); + } + + /** + * Get the thumbnail of this post + * + * @see get_the_post_thumbnail + * @param string $size + * @param string $attr + * @return string + */ + public function thumbnail($size = 'post-thumbnail', $attr = '') + { + return get_the_post_thumbnail($this->toWordpressPost(), $size, $attr); + } + + /** + * Get the excerpt of this post. + * + * @return string + */ + public function excerpt() + { + dd($this); + return Action::filter('get_the_excerpt', $this->post_excerpt); + } + + /** + * Get the all the terms of this post. + * + * @see get_the_terms + * @param $taxonomy + * @return array|false|\WP_Error + */ + public function terms($taxonomy) + { + return get_the_terms($this->toWordpressPost(), $taxonomy); + } + + /** * Get the author that this post belongs to. * * @return BelongsTo @@ -146,4 +214,26 @@ class Post extends Model { return $this->belongsTo(User::class, 'post_author'); } + + /** + * Get the classes that should be applied to this post. + * + * @see get_post_class + * @return string + */ + public function classes() + { + return implode(' ', get_post_class('', $this->toWordpressPost())); + } + + /** + * Get the {@link WP_Post} instance for this Post. + * + * @deprecated + * @return WP_Post + */ + public function toWordpressPost() + { + return new WP_Post((object) $this->toArray()); + } } diff --git a/src/Models/User.php b/src/Models/User.php index 98ed007..9974e88 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -15,8 +15,10 @@ class User extends Model implements AuthenticatableContract { use Authenticatable; - public $table = DB_PREFIX . 'users'; - public $primaryKey = 'ID'; + protected $table = DB_PREFIX . 'users'; + protected $primaryKey = 'ID'; + protected $dates = ['user_registered']; + public $timestamps = false; /** * Get all the posts that belong to this user. @@ -25,7 +27,7 @@ class User extends Model implements AuthenticatableContract */ public function posts() { - return $this->hasMany(self::class, 'post_author'); + return $this->hasMany(Post::class, 'post_author'); } /** @@ -37,4 +39,14 @@ class User extends Model implements AuthenticatableContract { return $this->user_pass; } + + /** + * Get a link to this user's author page. + * + * @return string + */ + public function link() + { + return get_author_posts_url($this->ID, $this->display_name); + } } diff --git a/src/Models/UserMeta.php b/src/Models/UserMeta.php index db1c581..5450068 100644 --- a/src/Models/UserMeta.php +++ b/src/Models/UserMeta.php @@ -12,14 +12,15 @@ use Koselig\Support\Wordpress; */ class UserMeta extends Model { - public $table = DB_PREFIX . 'usermeta'; + protected $table = DB_PREFIX . 'usermeta'; + public $timestamps = false; /** * Cache for all meta values. * * @var array */ - public static $cache = []; + private static $cache = []; /** * Get metadata for a user. @@ -37,7 +38,7 @@ class UserMeta extends Model } if ($user === null) { - $user = Wordpress::currentUser()->ID; + $user = auth()->id(); } if (!isset(self::$cache[$user])) { diff --git a/src/Providers/WordpressServiceProvider.php b/src/Providers/WordpressServiceProvider.php index 6d726eb..b788c5b 100644 --- a/src/Providers/WordpressServiceProvider.php +++ b/src/Providers/WordpressServiceProvider.php @@ -4,6 +4,7 @@ namespace Koselig\Providers; use Illuminate\Contracts\Routing\UrlGenerator; use Illuminate\Support\Facades\DB; use Illuminate\Support\ServiceProvider; +use Koselig\Proxy\Query; use Koselig\Support\Action; use Koselig\Support\Wordpress; @@ -37,6 +38,10 @@ class WordpressServiceProvider extends ServiceProvider // Set up the WordPress query. wp(); + + $this->app->singleton('query', function () { + return Query::instance($GLOBALS['wp_the_query']); + }); } /** diff --git a/src/Proxy/Query.php b/src/Proxy/Query.php new file mode 100644 index 0000000..fe9c4d6 --- /dev/null +++ b/src/Proxy/Query.php @@ -0,0 +1,65 @@ + + */ +class Query +{ + /** + * Current query. + * + * @var WP_Query + */ + private $query; + + public static function instance(WP_Query $query) + { + $instance = new static; + $instance->query = $query; + return $instance; + } + + /** + * Get a property from {@link WP_Query} + * + * @param $name + * @return mixed + */ + public function __get($name) + { + return $this->query->{Str::snake($name)}; + } + + /** + * Pass a call to this function to {@link WP_Query} + * + * @param $name + * @param $arguments + * @return mixed + */ + public function __call($name, $arguments) + { + $name = Str::snake($name); + $name = str_replace('has', 'have', $name); + + if (!method_exists($this->query, $name)) { + // try and find the method that was attempted to be called. Makes for a lot nicer code when reading over + // it. + if (method_exists($this->query, 'the_' . $name)) { + $name = 'the_' . $name; + } elseif (method_exists($this->query, 'is_' . $name)) { + $name = 'is_' . $name; + } elseif (method_exists($this->query, 'get_' . $name)) { + $name = 'get_' . $name; + } + } + + return $this->query->{$name}(...$arguments); + } +} diff --git a/src/Routing/ArchiveRoute.php b/src/Routing/ArchiveRoute.php index dfb0d36..bd3f93f 100644 --- a/src/Routing/ArchiveRoute.php +++ b/src/Routing/ArchiveRoute.php @@ -33,17 +33,7 @@ class ArchiveRoute extends Route parent::__construct($methods, $postTypes, $action); $this->postTypes = $this->uri; - $this->uri = ''; - } - - /** - * Format a nice string for php artisan route:list. - * - * @return string - */ - public function uri() - { - return 'archive/' . (implode('/', $this->postTypes) ?: 'all'); + $this->uri = 'archive/' . (implode('/', $this->postTypes) ?: 'all'); } /** diff --git a/src/Routing/AuthorRoute.php b/src/Routing/AuthorRoute.php new file mode 100644 index 0000000..ef5b26d --- /dev/null +++ b/src/Routing/AuthorRoute.php @@ -0,0 +1,81 @@ + + */ +class AuthorRoute extends Route +{ + /** + * Users for this author route to hook onto. + * + * @var array + */ + private $users; + + /** + * Create a new Route instance. + * + * @param array|string $methods + * @param array $users + * @param \Closure|array $action + * @return void + */ + public function __construct($methods, $users, $action) + { + parent::__construct($methods, $users, $action); + + $this->users = $this->uri; + $this->uri = 'author/' . (implode('/', $this->users) ?: 'all'); + } + + /** + * Run the route action and return the response. + * + * @return mixed + */ + protected function runCallable() + { + // bind the current post to the parameters of the function + $function = new ReflectionFunction($this->action['uses']); + $params = $function->getParameters(); + + foreach ($params as $param) { + if ($param->getClass() + && ($param->getClass()->isSubclassOf(User::class) || $param->getClass()->getName() === User::class)) { + $builder = $param->getClass()->getMethod('query')->invoke(null); + $post = $builder->find(Query::queriedObject()->ID); + + $this->setParameter($param->getName(), $post); + } + } + + return parent::runCallable(); + } + + /** + * Determine if the route matches given request. + * + * @param \Illuminate\Http\Request $request + * @param bool $includingMethod + * @return bool + */ + public function matches(Request $request, $includingMethod = true) + { + if (!empty($this->getAction()['domain']) && !Wordpress::multisite($this->getAction()['domain'])) { + return false; + } + + return Wordpress::author($this->users); + } +} diff --git a/src/Routing/PageRoute.php b/src/Routing/PageRoute.php index c5a1d88..a0aa428 100644 --- a/src/Routing/PageRoute.php +++ b/src/Routing/PageRoute.php @@ -16,13 +16,17 @@ use ReflectionFunction; class PageRoute extends Route { /** - * Format a nice string for php artisan route:list. + * Create a new Route instance. * - * @return string + * @param array|string $methods + * @param array $users + * @param \Closure|array $action + * @return void */ - public function uri() + public function __construct($methods, $users, $action) { - return 'page/' . parent::uri(); + parent::__construct($methods, $users, $action); + $this->uri = 'page/' . $this->uri(); } /** diff --git a/src/Routing/Routing.php b/src/Routing/Routing.php index 1ff2d70..2e40806 100644 --- a/src/Routing/Routing.php +++ b/src/Routing/Routing.php @@ -10,7 +10,7 @@ class Routing * Register a new template route with the router. * * @param string $slug slug to match - * @param \Closure|array|string|null $action + * @param callable|array|string|null $action * @return \Illuminate\Routing\Route */ public function template($slug, $action) @@ -30,7 +30,7 @@ class Routing * Register a new page route with the router. * * @param string $slug slug to match - * @param \Closure|array|string|null $action + * @param callable|array|string|null $action * @return \Illuminate\Routing\Route */ public function page($slug, $action) @@ -50,8 +50,8 @@ class Routing * Register a new archive route with the router. Optionally supply * the post types you'd like to supply with this route. * - * @param \Closure|string|array $postTypes - * @param \Closure|array|string|null $action + * @param callable|string|array $postTypes + * @param callable|array|string|null $action * @return \Illuminate\Routing\Route */ public function archive($postTypes = [], $action = []) @@ -102,6 +102,37 @@ class Routing } /** + * Register a author route with the router. This allows the user to + * create pages for an author or authors. Optionally supply the authors + * you'd like to supply using this route. + * + * @param callable|array|int $users authors to handle by this route + * @param callable|array|string|null $action + * @return mixed + */ + public function author($users, $action = []) + { + if (empty($action)) { + $action = $users; + $users = []; + } + + if (!is_array($users)) { + $users = [$users]; + } + + $action = $this->formatAction($action); + + $route = (new AuthorRoute($action['method'], $users, $action)) + ->setRouter(app('router')) + ->setContainer(app(Container::class)); + + $route = $this->applyStack($route); + + return Route::getRoutes()->add($route); + } + + /** * Format
$action
in a nice way to pass to the {@link \Illuminate\Routing\RouteCollection}. * * @param $action diff --git a/src/Routing/RoutingServiceProvider.php b/src/Routing/RoutingServiceProvider.php index b3d79e7..356c7e5 100644 --- a/src/Routing/RoutingServiceProvider.php +++ b/src/Routing/RoutingServiceProvider.php @@ -28,5 +28,6 @@ class RoutingServiceProvider extends ServiceProvider Router::macro('page', [$routing, 'page']); Router::macro('archive', [$routing, 'archive']); Router::macro('singular', [$routing, 'singular']); + Router::macro('author', [$routing, 'author']); } } diff --git a/src/Routing/SingularRoute.php b/src/Routing/SingularRoute.php index 09904ec..8ba59b4 100644 --- a/src/Routing/SingularRoute.php +++ b/src/Routing/SingularRoute.php @@ -35,7 +35,7 @@ class SingularRoute extends Route parent::__construct($methods, $types, $action); $this->types = $this->uri; - $this->uri = ''; + $this->uri = 'singular/' . implode('/', $this->types); } /** @@ -63,16 +63,6 @@ class SingularRoute extends Route } /** - * Format a nice string for php artisan route:list. - * - * @return string - */ - public function uri() - { - return 'singular/' . implode('/', $this->types); - } - - /** * Determine if the route matches given request. * * @param \Illuminate\Http\Request $request diff --git a/src/Routing/TemplateRoute.php b/src/Routing/TemplateRoute.php index 9ec26b3..55ccc3d 100644 --- a/src/Routing/TemplateRoute.php +++ b/src/Routing/TemplateRoute.php @@ -1,8 +1,8 @@ uri = 'template/' . parent::uri(); } /** @@ -52,19 +57,21 @@ class TemplateRoute extends Route /** * Determine if the route matches given request. * - * @param \Illuminate\Http\Request $request + * @param Request $request * @param bool $includingMethod * @return bool */ public function matches(Request $request, $includingMethod = true) { - $slug = Wordpress::templateSlug(); + $post = $request->post(); - if (!$slug) { + if (!$post) { // the page we are on either isn't in the CMS or doesn't have a template. return false; } + $slug = $post->getMeta('_wp_page_template'); + if (!empty($this->getAction()['domain']) && !Wordpress::multisite($this->getAction()['domain'])) { return false; } diff --git a/src/Support/Wordpress.php b/src/Support/Wordpress.php index dec572a..6f614e6 100644 --- a/src/Support/Wordpress.php +++ b/src/Support/Wordpress.php @@ -1,6 +1,9 @@ $user) { + if ($user instanceof User) { + $users[$key] = $user->ID; + } + } + + return Query::author($users); } /** @@ -110,6 +112,7 @@ class Wordpress * * Use of WP_User is deprecated, however this method will not be removed. * + * @deprecated use Auth::user() instead. * @return \WP_User */ public static function currentUser() -- libgit2 1.7.2