Пример #1
0
 public function send()
 {
     $this->sendHeaders();
     $this->sendContent();
     if (function_exists('fastcgi_finish_request')) {
         Log::flush();
         //fastcgi_finish_request();
     } elseif ('cli' !== PHP_SAPI) {
         static::closeOutputBuffers(0, true);
     }
     return $this;
 }
Пример #2
0
 /**
  * Constructor
  *
  * Throws an exception if config/app.json file is missing.
  *
  * @param $rootPath string The root path to the theme
  *
  * @throws \Exception
  */
 public function __construct($rootPath)
 {
     $this->siteHost = parse_url(site_url(), PHP_URL_HOST);
     $this->httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
     // Load the config
     if (file_exists($rootPath . '/config/app.php')) {
         $this->config = (include $rootPath . '/config/app.php');
     } else {
         if (file_exists($rootPath . '/config/app.json')) {
             $this->config = JSONParser::parse(file_get_contents($rootPath . '/config/app.json'));
         } else {
             throw new \Exception('Missing app.json or app.php configuration for theme.');
         }
     }
     // Create the request object
     $this->request = Request::createFromGlobals();
     $this->environment = getenv('WP_ENV') ?: 'development';
     $this->debug = defined(WP_DEBUG) || $this->environment == 'development';
     // Initialize logging
     $loggingConfig = null;
     if (isset($this->config['logging'])) {
         if (isset($this->config['logging'][$this->environment])) {
             $loggingConfig = $this->config['logging'][$this->environment];
         } else {
             if (isset($this->config['logging']['development'])) {
                 $loggingConfig = $this->config['logging']['development'];
             } else {
                 if (isset($this->config['logging']['other'])) {
                     $loggingConfig = $this->config['logging']['other'];
                 }
             }
         }
     }
     Log::initialize($loggingConfig);
     // Set our text domain, not really used though.
     $this->textdomain = $this->config['text-domain'];
     // Setup our paths
     $this->rootPath = $rootPath;
     $this->classPath = $rootPath . '/classes/';
     if (!file_exists($this->classPath)) {
         $this->classPath = $rootPath . '/Classes/';
         if (!file_exists($this->classPath)) {
             throw new \xception("Missing 'classes' directory in Stem application directory: {$rootPath}");
         }
     }
     // Create the router for extra routes
     $this->router = new Router($this);
     $this->namespace = $this->config['namespace'];
     // Enable/disable XML RPC
     if ($this->setting('options/disable-xml-rpc', false)) {
         add_filter('xmlrpc_enabled', '__return_false', 10000);
     }
     // Enable/disable WordPress JSON API
     if ($this->setting('options/disable-wp-json-api', false)) {
         add_filter('json_enabled', '__return_false', 10000);
         add_filter('json_jsonp_enabled', '__return_false', 10000);
         add_filter('rest_enabled', '__return_false', 10000);
         add_filter('rest_jsonp_enabled', '__return_false', 10000);
         remove_action('xmlrpc_rsd_apis', 'rest_output_rsd');
         remove_action('wp_head', 'rest_output_link_wp_head', 10);
         remove_action('template_redirect', 'rest_output_link_header', 11);
     }
     // Enable/disable WordPress emoji crap
     if ($this->setting('options/disable-wp-json-api', false)) {
         add_action('init', function () {
             remove_action('admin_print_styles', 'print_emoji_styles');
             remove_action('wp_head', 'print_emoji_detection_script', 7);
             remove_action('admin_print_scripts', 'print_emoji_detection_script');
             remove_action('wp_print_styles', 'print_emoji_styles');
             remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
             remove_filter('the_content_feed', 'wp_staticize_emoji');
             remove_filter('comment_text_rss', 'wp_staticize_emoji');
             add_filter('disable-emoji', function ($plugins) {
                 if (is_array($plugins)) {
                     return array_diff($plugins, ['wpemoji']);
                 } else {
                     return [];
                 }
             }, 10000, 1);
         });
     }
     // Enable/disable RSS Feeds
     if ($this->setting('options/disable-rss', false)) {
         add_action('wp_loaded', function () {
             remove_action('wp_head', 'feed_links', 2);
             remove_action('wp_head', 'feed_links_extra', 3);
         });
     }
     // Create the controller/template dispatcher
     $this->dispatcher = new Dispatcher($this);
     // Autoload function for theme classes
     spl_autoload_register(function ($class) {
         if ('\\' == $class[0]) {
             $class = substr($class, 1);
         }
         $class = strtr($class, '\\', DIRECTORY_SEPARATOR);
         $classParts = explode(DIRECTORY_SEPARATOR, $class);
         if (count($classParts) > 1) {
             array_shift($classParts);
             $shortClass = implode(DIRECTORY_SEPARATOR, $classParts);
             if (file_exists($this->classPath . $shortClass . '.php')) {
                 require_once $this->classPath . $shortClass . '.php';
                 return true;
             }
         }
         if (file_exists($this->classPath . $class . '.php')) {
             require_once $this->classPath . $class . '.php';
             return true;
         }
         return false;
     });
     // Theme setup action hook
     add_action('after_setup_theme', function () {
         $this->setup();
     });
     // This does the actual dispatching to Stem controllers
     // and templates.
     add_filter('template_include', function ($template) {
         $this->dispatch();
     });
     // Build the controller map that maps the templates that
     // wordpress is trying to "include" to Controller classes
     // in the stem app/theme.  Additionally, we surface these
     // as "page templates" in the wordpress admin UI.
     if (isset($this->config['page-controllers'])) {
         $this->templates = $this->config['page-controllers'];
         foreach ($this->config['page-controllers'] as $key => $controller) {
             $this->controllerMap[strtolower(preg_replace('|[^aA-zZ0-9_]+|', "-", $key))] = $controller;
         }
         add_filter('theme_page_templates', function ($page_templates, $theme, $post) {
             foreach ($this->config['page-controllers'] as $key => $controller) {
                 $page_templates[preg_replace("/\\s+/", "-", $key) . '.php'] = $key;
             }
             return $page_templates;
         }, 10, 3);
     }
     // Load/save ACF Pro JSON fields to our config directory
     add_filter('acf/settings/save_json', function ($path) use($rootPath) {
         $newpath = $rootPath . '/config/fields';
         if (file_exists($newpath)) {
             return $newpath;
         }
         Log::error("Saving ACF fields, missing {$newpath} directory.");
         return $path;
     });
     add_filter('acf/settings/load_json', function ($paths) use($rootPath) {
         $newpath = $rootPath . '/config/fields';
         if (!file_exists($newpath)) {
             Log::error("Loading ACF fields, missing {$newpath} directory.");
             return $paths;
         }
         unset($paths[0]);
         $paths[] = $newpath;
         return $paths;
     });
     // Load our custom post types
     add_action('init', [$this, 'installCustomPostTypes'], 10000);
     // Require our plugins
     $this->setupRequiredPlugins();
     $this->cacheControl = new CacheControl($this);
     $this->ui = new UI($this);
     $this->admin = new Admin($this);
 }
Пример #3
0
 /**
  * @param $templateName string|array
  * @param $pageType string
  * @return bool
  * @throws \Exception
  */
 private function dispatchTemplate($templateName, $pageType)
 {
     if (is_array($templateName)) {
         foreach ($templateName as $name) {
             if ($this->dispatchTemplate($name, $pageType)) {
                 return true;
             }
         }
     } else {
         Log::debug("Looking for template '{$templateName}' for page type '{$pageType}'.", ['templateName' => $templateName, 'pageType' => $pageType]);
         $templateName = strtolower($templateName);
         // normalize the name, eg front_page becomes front-page
         $name = preg_replace('|[^a-z0-9_]+|', '-', $templateName);
         // camel case the the controller class name, eg front_page becomes FrontPage
         $nameparts = explode('-', $name);
         array_walk($nameparts, function (&$value, $index) {
             $value = ucfirst($value);
         });
         $classname = implode('', $nameparts);
         if (is_numeric($classname)) {
             $classname = 'Error' . $classname;
         }
         // Interpolate the class name
         $class = $this->context->namespace . '\\Controllers\\' . $classname . 'Controller';
         Log::debug("Looking for class.", ['class' => $class]);
         // Determine the action and controller method
         $action = $this->context->request->query->has('_action') ? ucfirst($this->context->request->query->get('_action')) : 'Index';
         $method = strtolower($this->context->request->getMethod()) . $action;
         $controller = null;
         // If the controller exists, create it ...
         if (class_exists($class)) {
             $controller = new $class($this->context);
         } else {
             // Otherwise, we check to see if the template exists.
             if ($this->context->ui->viewExists('templates/' . $name)) {
                 if ($pageType == 'none') {
                     Log::debug("Found template.", ['templateName' => $templateName]);
                     $this->context->cacheControl->sendHTTPHeaders();
                     // Template exists but page type doesn't map to a built-in
                     // controller, so we just render the template as is.
                     echo $this->context->ui->render('templates/' . $name, [$this->context]);
                     return true;
                 }
                 $controller = $this->context->createController($pageType, $name);
             } else {
                 Log::debug("Trying to mapping controller for class.", ['name' => $name]);
                 $controller = $this->context->mapController($name);
             }
         }
         // if we found a controller, then invoke the method and return it's output
         if ($controller) {
             Log::debug("Found controller.", ['templateName' => $templateName]);
             if (method_exists($controller, $method)) {
                 $response = call_user_func([$controller, $method], $this->context->request);
             } else {
                 // Try GET if method was something other ...
                 $method = 'get' . $action;
                 if (method_exists($controller, $method)) {
                     $response = call_user_func([$controller, $method], $this->context->request);
                 } else {
                     throw new \Exception("Missing method '{$method}' on class '{$class}'.");
                 }
             }
             if (is_object($response) && $response instanceof Response) {
                 $this->context->cacheControl->addResponseHeaders($response);
                 $response->send();
             } else {
                 if (is_string($response)) {
                     $this->context->cacheControl->sendHTTPHeaders();
                     echo $response;
                 }
             }
             return true;
         } else {
             Log::debug("Controller not found.", ['templateName' => $templateName]);
         }
         return false;
     }
     return false;
 }
Пример #4
0
 /**
  * Load custom image sizes
  */
 private function loadImageSizes()
 {
     // configure image sizes
     if (file_exists($this->context->rootPath . '/config/sizes.php')) {
         $sizesConfig = (include $this->context->rootPath . '/config/sizes.php');
     } else {
         if (file_exists($this->context->rootPath . '/config/sizes.json')) {
             $sizesConfig = JSONParser::parse(file_get_contents($this->context->rootPath . '/config/sizes.json'));
         } else {
             return;
         }
     }
     if (isset($sizesConfig['srcset'])) {
         $this->srcsetConfig = $sizesConfig['srcset'];
     }
     if (isset($sizesConfig['sizes'])) {
         $customSizes = [];
         foreach ($sizesConfig['sizes'] as $key => $info) {
             if ($key == 'original') {
                 Log::warning("Your sizes config has specified a size for 'original'.  This is a keyword and cannot be used.  Skipping for now.");
                 continue;
             }
             if ($key == 'post-thumbnail') {
                 set_post_thumbnail_size($info['width'], $info['height'], $info['crop']);
             } else {
                 add_image_size($key, $info['width'], $info['height'], $info['crop']);
             }
             if (isset($info['display']) && $info['display']) {
                 $customSizes[] = $key;
             }
         }
         if (count($customSizes) > 0) {
             add_filter('image_size_names_choose', function ($sizes) use($customSizes) {
                 foreach ($customSizes as $size) {
                     $sizes[$size] = ucwords(str_replace('_', ' ', str_replace('-', ' ', $size)));
                 }
                 return $sizes;
             });
         }
     }
     if (isset($sizesConfig['disable-wp-sizes'])) {
         $disabled = $sizesConfig['disable-wp-sizes'];
         add_filter('intermediate_image_sizes_advanced', function ($sizes) use($disabled) {
             foreach ($disabled as $size) {
                 unset($sizes[$size]);
             }
             return $sizes;
         }, 10000);
     }
 }