From bf7ebd6d52c21291e55dd3cbf83e07ba6ced254a Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 2 Oct 2016 22:23:59 +0100 Subject: [PATCH] Initial commit --- .gitignore | 1 + composer.json | 19 +++++++++++++++++++ config/templates.php | 17 +++++++++++++++++ config/wordpress.php | 12 ++++++++++++ src/Models/Meta.php | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Models/Post.php | 37 +++++++++++++++++++++++++++++++++++++ src/Models/User.php | 26 ++++++++++++++++++++++++++ src/Models/UserMeta.php | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Providers/LarapressServiceProvider.php | 27 +++++++++++++++++++++++++++ src/Providers/RoutingServiceProvider.php | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Providers/WordpressServiceProvider.php | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Routing/ArchiveRoute.php | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Routing/PageRoute.php | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/Routing/SingularRoute.php | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Routing/TemplateRoute.php | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/Support/Wordpress.php | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 778 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 config/templates.php create mode 100644 config/wordpress.php create mode 100644 src/Models/Meta.php create mode 100644 src/Models/Post.php create mode 100644 src/Models/User.php create mode 100644 src/Models/UserMeta.php create mode 100644 src/Providers/LarapressServiceProvider.php create mode 100644 src/Providers/RoutingServiceProvider.php create mode 100644 src/Providers/WordpressServiceProvider.php create mode 100644 src/Routing/ArchiveRoute.php create mode 100644 src/Routing/PageRoute.php create mode 100644 src/Routing/SingularRoute.php create mode 100644 src/Routing/TemplateRoute.php create mode 100644 src/Support/Wordpress.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4c498df --- /dev/null +++ b/composer.json @@ -0,0 +1,19 @@ +{ + "name": "w4/larapress", + "description": "Integrate Wordpress into Laravel seamlessly", + "license": "GPL-3.0+", + "authors": [ + { + "name": "Jordan Doyle", + "email": "jordan@doyle.wf" + } + ], + "require": { + "illuminate/support": "5.3.*" + }, + "autoload": { + "psr-4": { + "JordanDoyle\\Larapress\\": "src/" + } + } +} diff --git a/config/templates.php b/config/templates.php new file mode 100644 index 0000000..4b56186 --- /dev/null +++ b/config/templates.php @@ -0,0 +1,17 @@ + friendly name format. + */ + + 'home' => 'Homepage' + +]; + diff --git a/config/wordpress.php b/config/wordpress.php new file mode 100644 index 0000000..6d01ff8 --- /dev/null +++ b/config/wordpress.php @@ -0,0 +1,12 @@ + env('AUTH_KEY'), + 'secure_auth_key' => env('SECURE_AUTH_KEY'), + 'logged_in_key' => env('LOGGED_IN_KEY'), + 'nonce_key' => env('NONCE_KEY'), + 'auth_salt' => env('AUTH_SALT'), + 'secure_auth_salt' => env('SECURE_AUTH_SALT'), + 'logged_in_salt' => env('LOGGED_IN_SALT'), + 'nonce_salt' => env('NONCE_SALT') +]; diff --git a/src/Models/Meta.php b/src/Models/Meta.php new file mode 100644 index 0000000..056bb60 --- /dev/null +++ b/src/Models/Meta.php @@ -0,0 +1,73 @@ + + */ +class Meta extends Model +{ + public $table = DB_PREFIX . 'postmeta'; + + /** + * Cache for all meta values. + * + * @var array + */ + public static $cache = []; + + /** + * Get metadata for a page (or the current page) + * + * Meta::get('my_meta_key'); + * or + * Meta::get(7, 'my_meta_key'); + * + * @param int|string|null $page page to get meta for (or name of the meta item to get + * if you want to get the current page's meta) + * @param string|null $name + * @return mixed + */ + public static function get($page = null, $name = null) + { + if (!ctype_digit((string) $page) && $name === null) { + $name = $page; + $page = null; + } + + if ($page === null) { + $page = Wordpress::id(); + } + + if (!isset(self::$cache[$page])) { + // get all the meta values for a post, it's more than likely we're going to + // need this again query, so we'll just grab all the results and cache them. + self::$cache[$page] = Meta::where('post_id', $page)->get(); + } + + if ($name === null) { + return self::$cache[$page]->mapWithKeys(function ($item) { + return [$item->meta_key => $item->meta_value]; + })->all(); + } + + $value = self::$cache[$page]->where('meta_key', $name)->first(); + + return empty($value) ? null : $value->meta_value; + } + + /** + * Get the post that this meta value belongs to. + * + * @return BelongsTo + */ + public function post() + { + return $this->belongsTo(Post::class); + } +} diff --git a/src/Models/Post.php b/src/Models/Post.php new file mode 100644 index 0000000..7726a0a --- /dev/null +++ b/src/Models/Post.php @@ -0,0 +1,37 @@ + + */ +class Post extends Model +{ + public $table = DB_PREFIX . 'posts'; + public $primaryKey = 'ID'; + + /** + * Get all the meta values that belong to this post. + * + * @return HasMany + */ + public function meta() + { + return $this->hasMany(Meta::class); + } + + /** + * Get the author that this post belongs to. + * + * @return BelongsTo + */ + public function author() + { + return $this->belongsTo(User::class, 'post_author'); + } +} diff --git a/src/Models/User.php b/src/Models/User.php new file mode 100644 index 0000000..1c6941e --- /dev/null +++ b/src/Models/User.php @@ -0,0 +1,26 @@ + + */ +class User extends Model +{ + public $table = DB_PREFIX . 'users'; + public $primaryKey = 'ID'; + + /** + * Get all the posts that belong to this user. + * + * @return HasMany + */ + public function posts() + { + return $this->hasMany(User::class, 'post_author'); + } +} diff --git a/src/Models/UserMeta.php b/src/Models/UserMeta.php new file mode 100644 index 0000000..bd6f6ec --- /dev/null +++ b/src/Models/UserMeta.php @@ -0,0 +1,67 @@ + + */ +class UserMeta extends Model +{ + public $table = DB_PREFIX . 'usermeta'; + + /** + * Cache for all meta values. + * + * @var array + */ + public static $cache = []; + + /** + * Get metadata for a user + * + * @param int|string|null $user user to get meta for (or name of the meta item to get + * if you want to get the current user's meta) + * @param string|null $name + * @return mixed + */ + public static function get($user = null, $name = null) + { + if (!ctype_digit((string) $user) && $name === null) { + $name = $user; + $page = null; + } + + if ($user === null) { + $user = Wordpress::currentUser()->ID; + } + + if (!isset(self::$cache[$user])) { + // get all the meta values for a post, it's more than likely we're going to + // need this again query, so we'll just grab all the results and cache them. + self::$cache[$user] = UserMeta::where('user_id', $user)->get(); + } + + if ($name === null) { + return self::$cache[$user]->mapWithKeys(function ($item) { + return [$item->meta_key => $item->meta_value]; + })->all(); + } + + return self::$cache[$user]->where('meta_key', $name)->first()->meta_value; + } + + /** + * Get the user that this meta value belongs to. + * + * @return BelongsTo + */ + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/src/Providers/LarapressServiceProvider.php b/src/Providers/LarapressServiceProvider.php new file mode 100644 index 0000000..7813a41 --- /dev/null +++ b/src/Providers/LarapressServiceProvider.php @@ -0,0 +1,27 @@ + + */ +class LarapressServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + * + * @return void + */ + public function register() + { + $this->app->register(WordpressServiceProvider::class); + $this->app->register(RoutingServiceProvider::class); + } +} diff --git a/src/Providers/RoutingServiceProvider.php b/src/Providers/RoutingServiceProvider.php new file mode 100644 index 0000000..eb0e0e5 --- /dev/null +++ b/src/Providers/RoutingServiceProvider.php @@ -0,0 +1,110 @@ + + */ +class RoutingServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + * + * @return void + */ + public function register() + { + // Router methods + Router::macro('template', function ($slug, $action) { + $action = $this->formatAction($action); + + $route = (new TemplateRoute($action['method'], $slug, $action)) + ->setRouter(app('router')) + ->setContainer(app(Container::class)); + + return Route::getRoutes()->add($route); + }); + + Router::macro('page', function ($slug, $action) { + $action = $this->formatAction($action); + + $route = (new PageRoute($action['method'], $slug, $action)) + ->setRouter(app('router')) + ->setContainer(app(Container::class)); + + return Route::getRoutes()->add($route); + }); + + Router::macro('archive', function ($postTypes = [], $action = []) { + if (empty($action)) { + $action = $postTypes; + $postTypes = []; + } + + if (!is_array($postTypes)) { + $postTypes = [$postTypes]; + } + + $action = $this->formatAction($action); + + $route = (new ArchiveRoute($action['method'], $postTypes, $action)) + ->setRouter(app('router')) + ->setContainer(app(Container::class)); + + return Route::getRoutes()->add($route); + }); + + Router::macro('singular', function ($types, $action) { + if (!is_array($types)) { + $types = [$types]; + } + + $action = $this->formatAction($action); + + $route = (new SingularRoute($action['method'], $types, $action)) + ->setRouter(app('router')) + ->setContainer(app(Container::class)); + + return Route::getRoutes()->add($route); + }); + + // Router helpers + Router::macro('formatAction', function ($action) { + if (!($action instanceof $action) && (is_string($action) || (isset($action['uses']) + && is_string($action['uses'])))) { + if (is_string($action)) { + $action = ['uses' => $action]; + } + + if (!empty($this->groupStack)) { + $group = end($this->groupStack); + + $action['uses'] = isset($group['namespace']) && strpos($action['uses'], '\\') !== 0 ? + $group['namespace'] . '\\' . $action['uses'] : $action['uses']; + } + + $action['controller'] = $action['uses']; + } + + if (!is_array($action)) { + $action = ['uses' => $action]; + } + + if (!isset($action['method'])) { + $action['method'] = ['GET']; + } + + return $action; + }); + } +} diff --git a/src/Providers/WordpressServiceProvider.php b/src/Providers/WordpressServiceProvider.php new file mode 100644 index 0000000..8c8ca3a --- /dev/null +++ b/src/Providers/WordpressServiceProvider.php @@ -0,0 +1,101 @@ + + */ +class WordpressServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + * + * @return void + */ + public function register() + { + // get the path wordpress is installed in + define('WP_PATH', + json_decode(file_get_contents(base_path('composer.json')), true)['extra']['wordpress-install-dir'] . '/'); + + $this->setConfig(); + $this->triggerHooks(); + + // Set up the WordPress query. + wp(); + } + + /** + * Set up the configuration values that wp-config.php + * does. Use all the values out of .env instead. + * + * @return void + */ + protected function setConfig() + { + $table_prefix = 'wp_'; + + $db = DB::getConfig(null); + + define('DB_NAME', $db['database']); + define('DB_USER', $db['username']); + define('DB_PASSWORD', $db['password']); + define('DB_HOST', $db['host']); + define('DB_CHARSET', $db['charset']); + define('DB_COLLATE', $db['collation']); + define('DB_PREFIX', $table_prefix); + + define('AUTH_KEY', config('app.auth_key')); + define('SECURE_AUTH_KEY', config('app.secure_auth_key')); + define('LOGGED_IN_KEY', config('app.logged_in_key')); + define('NONCE_KEY', config('app.nonce_key')); + define('AUTH_SALT', config('app.auth_salt')); + define('SECURE_AUTH_SALT', config('app.secure_auth_salt')); + define('LOGGED_IN_SALT', config('app.logged_in_salt')); + define('NONCE_SALT', config('app.nonce_salt')); + + define('WP_DEBUG', config('app.debug')); + define('SAVEQUERIES', WP_DEBUG); + define('WP_DEBUG_DISPLAY', WP_DEBUG); + define('SCRIPT_DEBUG', WP_DEBUG); + + define('DISALLOW_FILE_EDIT', true); + + if (!defined('ABSPATH')) { + define('ABSPATH', base_path(WP_PATH)); + } + + define('WP_SITEURL', url(str_replace('public/', '', WP_PATH))); + define('WP_HOME', url('/')); + + define('WP_CONTENT_DIR', base_path('public/content')); + define('WP_CONTENT_URL', url('content')); + + if (App::runningInConsole()) { + $_SERVER['SERVER_PROTOCOL'] = 'https'; + } + + require ABSPATH . 'wp-settings.php'; + } + + /** + * Wordpress core hooks needed for the main functionality of + * Larapress. + * + * @return void + */ + protected function triggerHooks() + { + add_filter('theme_page_templates', function ($page_templates) { + return array_merge($page_templates, config('templates')); + }); + } +} diff --git a/src/Routing/ArchiveRoute.php b/src/Routing/ArchiveRoute.php new file mode 100644 index 0000000..dbbaadb --- /dev/null +++ b/src/Routing/ArchiveRoute.php @@ -0,0 +1,60 @@ + + */ +class ArchiveRoute extends Route +{ + /** + * Post types for this archive route to hook onto + * + * @var array + */ + private $postTypes; + + /** + * Create a new Route instance. + * + * @param array|string $methods + * @param array $postTypes + * @param \Closure|array $action + * @return void + */ + public function __construct($methods, $postTypes, $action) + { + 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'); + } + + /** + * Determine if the route matches given request. + * + * @param \Illuminate\Http\Request $request + * @param bool $includingMethod + * @return bool + */ + public function matches(Request $request, $includingMethod = true) + { + return Wordpress::archive($this->postTypes); + } +} diff --git a/src/Routing/PageRoute.php b/src/Routing/PageRoute.php new file mode 100644 index 0000000..681dade --- /dev/null +++ b/src/Routing/PageRoute.php @@ -0,0 +1,44 @@ + + */ +class PageRoute extends Route +{ + /** + * Format a nice string for php artisan route:list + * + * @return string + */ + public function uri() + { + return 'page/' . parent::uri(); + } + + /** + * Determine if the route matches given request. + * + * @param \Illuminate\Http\Request $request + * @param bool $includingMethod + * @return bool + */ + public function matches(Request $request, $includingMethod = true) + { + $id = Wordpress::id(); + + if (!$id) { + // we're not on a Wordpress page + return false; + } + + return $this->uri === $id; + } +} diff --git a/src/Routing/SingularRoute.php b/src/Routing/SingularRoute.php new file mode 100644 index 0000000..a3a2f19 --- /dev/null +++ b/src/Routing/SingularRoute.php @@ -0,0 +1,65 @@ + + */ +class SingularRoute extends Route +{ + /** + * Entry types this route should hook onto. + * + * @var array + */ + private $types; + + /** + * Create a new Route instance. + * + * @param array|string $methods + * @param array $types + * @param \Closure|array $action + * @return void + */ + public function __construct($methods, $types, $action) + { + parent::__construct($methods, $types, $action); + + $this->types = $this->uri; + $this->uri = ''; + } + + /** + * 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 + * @param bool $includingMethod + * @return bool + */ + public function matches(Request $request, $includingMethod = true) + { + if (!Wordpress::id()) { + // this isn't a wordpress-controlled page + return false; + } + + return Wordpress::singular($this->types); + } +} diff --git a/src/Routing/TemplateRoute.php b/src/Routing/TemplateRoute.php new file mode 100644 index 0000000..a27de85 --- /dev/null +++ b/src/Routing/TemplateRoute.php @@ -0,0 +1,44 @@ + + */ +class TemplateRoute extends Route +{ + /** + * Format a nice string for php artisan route:list + * + * @return string + */ + public function uri() + { + return 'template/' . parent::uri(); + } + + /** + * Determine if the route matches given request. + * + * @param \Illuminate\Http\Request $request + * @param bool $includingMethod + * @return bool + */ + public function matches(Request $request, $includingMethod = true) + { + $slug = Wordpress::templateSlug(); + + if (!$slug) { + // the page we are on either isn't in the CMS or doesn't have a template. + return false; + } + + return $this->uri === $slug; + } +} diff --git a/src/Support/Wordpress.php b/src/Support/Wordpress.php new file mode 100644 index 0000000..69e45db --- /dev/null +++ b/src/Support/Wordpress.php @@ -0,0 +1,75 @@ + + */ +class Wordpress +{ + /** + * Get the current Wordpress query. + * + * @return \WP_Query + */ + public static function query() + { + global $wp_query; + return $wp_query; + } + + /** + * Get the current page id. + * + * @return int + */ + public static function id() + { + return get_the_ID(); + } + + /** + * Get the slug of the template of a page. + * + * @param string $page + * @return false|string + */ + public static function templateSlug($page = null) + { + return get_page_template_slug($page); + } + + /** + * Check if the current page is a singular item (eg. a news post) + * + * @param array|string $types + * @return bool + */ + public static function singular($types = '') + { + return is_singular($types); + } + + /** + * Check if the current page is an archive page + * + * @param string|array|null $types check if the archive page is for this type + * @return bool + */ + public static function archive($types = null) + { + return $types === null || empty($types) ? is_archive() : is_post_type_archive($types); + } + + /** + * Get the current logged in user. + * + * @return \WP_User + */ + public static function currentUser() + { + return wp_get_current_user(); + } +} -- libgit2 1.7.2