├── .gitignore ├── LICENSE ├── README.md ├── cache └── .gitkeep ├── framework ├── Asset │ ├── Asset.php │ ├── Managers │ │ ├── ScriptManager.php │ │ └── StyleManager.php │ ├── Script.php │ ├── Services │ │ ├── ScriptService.php │ │ └── StyleService.php │ └── Style.php ├── Autoloader.php ├── Component.php ├── Container.php ├── Database │ ├── DB.php │ ├── Model.php │ └── Query.php ├── Helpers │ ├── Arr.php │ ├── Folder.php │ ├── Inflector.php │ ├── Scripts.php │ ├── Str.php │ ├── Url.php │ └── V.php ├── Manager.php ├── Plugin │ ├── Managers │ │ └── PluginManager.php │ ├── Plugin.php │ └── Services │ │ ├── ActivationService.php │ │ ├── DeactivationService.php │ │ └── OptionService.php ├── Resources │ └── js │ │ └── admin_scripts.js ├── Router │ ├── Controller.php │ ├── Managers │ │ ├── RestManager.php │ │ └── RouteManager.php │ ├── Request.php │ ├── Rest.php │ └── Route.php ├── Sci.php ├── Support │ ├── Collection.php │ ├── CollectionInterface.php │ ├── Helper.php │ ├── Managers │ │ └── ProviderManager.php │ └── Provider.php ├── Template │ ├── Managers │ │ └── TemplateManager.php │ ├── Services │ │ └── TemplateService.php │ └── Template.php ├── Traits │ ├── MethodBinding.php │ ├── Sci.php │ ├── Singleton.php │ └── StaticClass.php ├── View.php └── run.php ├── main.php ├── readme.txt ├── setup.php └── updater.php /.gitignore: -------------------------------------------------------------------------------- 1 | cache/* 2 | !cache/.gitkeep -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MVC WP 2 | 3 | A MVC Framework for WordPress. 4 | 5 | # Funtionalities 6 | -------------------------------------- 7 | 8 | * ORM with most common CRUD operations and Query builder 9 | * MVC Architecture (Controllers, Models, Views) 10 | * Service container supporting parametrized dependency injection 11 | * Namespaces and PSR-4 compliant autoloader 12 | * Configure custom URL routes hierarchically 13 | * Extend with other plugins working as addons 14 | * Collections, Services and dynamic method bindings 15 | * Activation and deactivation actions and checks 16 | * Asset manager for JS scripts and CSS files 17 | * Service providers 18 | 19 | NOTE: For instructions of how to use this framework check the documentation at http://www.sciwp.com 20 | 21 | -------------------------------------------------------------------------------- /cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciwp/sciwp-framework/73c476cd439967f08d8aaae369583361929a68bd/cache/.gitkeep -------------------------------------------------------------------------------- /framework/Asset/Asset.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2020 Kenodo LTD 15 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 16 | * @version 1.0.0 17 | * @link https://www.sciwp.com 18 | * @since Version 1.0.0 19 | */ 20 | class Asset 21 | { 22 | /** @var string $src The asset absolute path */ 23 | protected $src; 24 | 25 | /** @var string $version The asset version */ 26 | protected $version; 27 | 28 | /** @var string[] $dependencies The asset dependencies */ 29 | protected $dependencies; 30 | 31 | /** 32 | * Create a new asset 33 | * 34 | * @param string $src The asset location 35 | * @param string $version The asset version 36 | * @param string[] $dependencies The registered css file dependencies 37 | */ 38 | public function __construct($src, $version = false, $dependencies = []) 39 | { 40 | $this->src = $src; 41 | $this->version = $version; 42 | $this->dependencies = (array) $dependencies; 43 | } 44 | 45 | /** 46 | * Add a new asset 47 | * 48 | * @param string $src The asset location 49 | * @param string $version The asset version 50 | * @param array $dependencies The asset dependencies 51 | * @return Asset 52 | */ 53 | public static function create($src, $version = false, $dependencies = []) 54 | { 55 | return Sci::make(self::class, [$src, $version, $dependencies]); 56 | } 57 | 58 | /** 59 | * Returns the asset src 60 | * 61 | * @return string 62 | */ 63 | public function getSrc() 64 | { 65 | return $this->src; 66 | } 67 | 68 | /** 69 | * Returns the asset dependencies 70 | * 71 | * @return string[] 72 | */ 73 | public function getDependences() 74 | { 75 | return $this->dependencies; 76 | } 77 | 78 | /** 79 | * Returns the asset version 80 | * 81 | * @return string 82 | */ 83 | public function getVersion() 84 | { 85 | return $this->version; 86 | } 87 | 88 | /** 89 | * Sets the asset src 90 | * 91 | * @param string $src The asset url 92 | * @return Asset 93 | */ 94 | public function setSrc($src) 95 | { 96 | $this->src = $src; 97 | return $this; 98 | } 99 | 100 | /** 101 | * Sets the asset dependencies 102 | * 103 | * @param string[] $dependencies The asset dependencies 104 | * @return Asset 105 | */ 106 | public function setDependences($dependencies) 107 | { 108 | $this->dependencies = $dependencies; 109 | return $this; 110 | } 111 | 112 | /** 113 | * Sets the asset version 114 | * 115 | * @param string $version The asset version 116 | * @return Asset 117 | */ 118 | public function setVersion($version) 119 | { 120 | $this->version = $version; 121 | return $this; 122 | } 123 | } -------------------------------------------------------------------------------- /framework/Asset/Managers/ScriptManager.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class ScriptManager extends Manager 22 | { 23 | /** @var array $scripts Array with scripts. */ 24 | private $scripts = []; 25 | 26 | /** @var array $zones Array with handles organized by zone. */ 27 | private $zones = ['front' => [], 'admin' => []]; 28 | 29 | /** @var boolean $filtersAdded If the WP filters have been added or not. */ 30 | private $filtersAdded = false; 31 | 32 | /** 33 | * Class constructor 34 | */ 35 | protected function __construct() 36 | { 37 | parent::__construct(); 38 | } 39 | 40 | /** 41 | * Register a script into the Style Manager 42 | * 43 | * @param Script $asset The script instance 44 | * @param string $handle The script handle 45 | * @param string $zone The script zone 46 | * @return ScriptManager 47 | */ 48 | public function register($asset, $handle, $zone = false) 49 | { 50 | if (!($asset instanceof Script)) { 51 | throw new Exception('Only instances of the Script class can be registered into the Script Manager.'); 52 | } 53 | 54 | $this->scripts[$handle] = $asset; 55 | 56 | if ((!$zone || $zone == 'front') && !in_array($handle, $this->zones['front'] )) { 57 | $this->zones['front'][] = $handle; 58 | } 59 | 60 | if ((!$zone || $zone == 'admin') && !in_array($handle, $this->zones['admin'] )) { 61 | $this->zones['admin'][] = $handle; 62 | } 63 | 64 | if (!$this->filtersAdded) $this->addFilters(); 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * Enqueue scripts 71 | * 72 | * @param string $zone The script zone 73 | * @return ScriptManager 74 | */ 75 | public function enqueue($zone) 76 | { 77 | if (!isset($this->zones[$zone])) return $this; 78 | 79 | foreach($this->scripts as $handle => $script) { 80 | if (in_array($handle, $this->zones[$zone])) { 81 | wp_register_script($handle, $script->getSrc(), $script->getDependences(), $script->getVersion(), $script->getFooter()); 82 | } 83 | } 84 | 85 | foreach($this->zones[$zone] as $handle) { 86 | wp_enqueue_script($handle); 87 | } 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * Add filters to WordPress so the scripts are processed 94 | * 95 | * @return ScriptManager 96 | */ 97 | public function addFilters() 98 | { 99 | // Enqueue frontend scripts 100 | add_action( 'wp_enqueue_scripts', function() { 101 | $this->enqueue('front'); 102 | }); 103 | 104 | // Enqueue admin panel scripts 105 | add_action( 'admin_enqueue_scripts', function() { 106 | $this->enqueue('admin'); 107 | }); 108 | 109 | // To avoid repeating this action 110 | $this->filtersAdded = true; 111 | return $this; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /framework/Asset/Managers/StyleManager.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class StyleManager extends Manager 22 | { 23 | /** @var array $styles Array with styles. */ 24 | private $styles = []; 25 | 26 | /** @var array $zones Array with handles organized by zone. */ 27 | private $zones = ['front' => [], 'admin' => []]; 28 | 29 | /** @var boolean $filtersAdded If the WP filters have been added or not. */ 30 | private $filtersAdded = false; 31 | 32 | /** 33 | * Class constructor 34 | * 35 | * @return StyleManager 36 | */ 37 | protected function __construct() 38 | { 39 | parent::__construct(); 40 | } 41 | 42 | /** 43 | * Register a style into the Style Manager 44 | * 45 | * @param Style $asset The Style instance 46 | * @param string $handle The Style handle 47 | * @param string $zone The style zone 48 | * @return StyleManager 49 | */ 50 | function register($asset, $handle, $zone = false) 51 | { 52 | if (!($asset instanceof Style)) { 53 | throw new Exception('Only instances of the Style class can be registered into the Style Manager.'); 54 | } 55 | 56 | $this->styles[$handle] = $asset; 57 | 58 | if ((!$zone || $zone == 'front') && !in_array($handle, $this->zones['front'] )) { 59 | $this->zones['front'][] = $handle; 60 | } 61 | 62 | if ((!$zone || $zone == 'admin') && !in_array($handle, $this->zones['admin'] )) { 63 | $this->zones['admin'][] = $handle; 64 | } 65 | 66 | if (!$this->filtersAdded) $this->addFilters(); 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Enqueue styles 73 | * 74 | * @param string $zone The style zone 75 | * @return StyleManager 76 | */ 77 | public function enqueue($zone) 78 | { 79 | if (!isset($this->zones[$zone])) return $this; 80 | 81 | foreach($this->styles as $handle => $style) { 82 | if (in_array($handle, $this->zones[$zone])) { 83 | wp_register_style($handle, $style->getSrc(), $style->getDependences(), $style->getVersion(), $style->getMedia()); 84 | } 85 | } 86 | 87 | foreach($this->zones[$zone] as $handle) { 88 | wp_enqueue_style($handle); 89 | } 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * Add filters to WordPress so the styles are processed 96 | * 97 | * @return StyleManager 98 | */ 99 | public function addFilters() 100 | { 101 | // Enqueue frontend styles 102 | add_action( 'wp_enqueue_scripts', function() { 103 | $this->enqueue('front'); 104 | }); 105 | 106 | // Enqueue admin panel styles 107 | add_action( 'admin_enqueue_scripts', function() { 108 | $this->enqueue('admin'); 109 | }); 110 | 111 | // To avoid repeating this action 112 | $this->filtersAdded = true; 113 | return $this; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /framework/Asset/Script.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Script extends Asset 22 | { 23 | /** @var boolean $footer If the script should be added in footer/header */ 24 | protected $footer; 25 | 26 | /** @var ScriptManager $scriptManager The Script Manager */ 27 | protected $scriptManager; 28 | 29 | /** 30 | * Create a new Script 31 | * 32 | * @param string $handle The script handle 33 | * @param string $src The script location 34 | * @param string $version The script asset version 35 | * @param string[] $dependencies The registered script dependencies 36 | * @param string $footer Script location 37 | */ 38 | public function __construct($src, $version = false, $dependencies = [], $footer = true, ScriptManager $scriptManager) 39 | { 40 | parent::__construct($src, $version, $dependencies); 41 | $this->scriptManager = $scriptManager; 42 | $this->footer = $footer; 43 | } 44 | 45 | /** 46 | * Add a new script 47 | * 48 | * @param string $src The script location 49 | * @param string $version The script version 50 | * @param string[] $dependencies The registered script dependencies 51 | * @param string $zone The script zone 52 | * @param string $footer Script location 53 | * @return Script 54 | */ 55 | public static function create($src, $version = false, $dependencies = [], $footer = true) 56 | { 57 | $script = Sci::make(self::class, [$src, $version, $dependencies, $footer]); 58 | return $script; 59 | } 60 | 61 | /** 62 | * Add the script to the Script Manager 63 | * 64 | * @param string $handle The script handle 65 | * @param string $zone Frontend or admin panel 66 | * @return Script 67 | */ 68 | public function register($handle, $zone = false) 69 | { 70 | $this->scriptManager->register($this, $handle, $zone); 71 | return $this; 72 | } 73 | 74 | /** 75 | * Returns if the asset should be placed in footer or in header 76 | * 77 | * @return boolean 78 | */ 79 | public function getFooter() 80 | { 81 | return $this->footer; 82 | } 83 | 84 | /** 85 | * Sets if the asset should be placed in footer (true) or in header (false) 86 | * 87 | * @param boolean $footer The boolen value 88 | * @return Script 89 | */ 90 | public function setFooter($footer) 91 | { 92 | $this->footer = $footer; 93 | return $this; 94 | } 95 | } -------------------------------------------------------------------------------- /framework/Asset/Services/ScriptService.php: -------------------------------------------------------------------------------- 1 | 16 | * @copyright 2020 Kenodo LTD 17 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 18 | * @version 1.0.0 19 | * @link https://www.sciwp.com 20 | * @since Version 1.0.0 21 | */ 22 | class ScriptService 23 | { 24 | /** @var string $plugin The plugin this service belongs to. */ 25 | private $plugin; 26 | 27 | /** @var string $key The plugin key */ 28 | private $key; 29 | 30 | /** @var ScriptManager $scriptManager The instance of the script manager. */ 31 | private $scriptManager; 32 | 33 | /** 34 | * Constructor 35 | */ 36 | public function __construct($key, Plugin $plugin, ScriptManager $scriptManager) 37 | { 38 | $this->key = $key; 39 | $this->plugin = $plugin; 40 | $this->scriptManager = $scriptManager; 41 | } 42 | 43 | /** 44 | * Read the plugin configuration 45 | * 46 | * @return ScriptService 47 | */ 48 | public function configure() 49 | { 50 | $scripts = $this->plugin->config()->get('scripts'); 51 | 52 | if (!$scripts) return; 53 | 54 | foreach ( (array) $scripts as $handle => $script) { 55 | 56 | if (is_array($script)) { 57 | 58 | $src = plugin_dir_url($this->plugin->getDir()) . '/' . $script['src']; 59 | $version = $script['version'] ?? $version; 60 | $dependencies = isset($script['dependencies']) ?? []; 61 | $footer = $script['footer'] ?? $footer; 62 | $zone = $script['zone'] ?? false; 63 | $script = Sci::make(Script::class, [$src, $version, $dependencies, $footer]); 64 | $this->scriptManager->register($script, $handle, $zone); 65 | 66 | } else { 67 | $src = plugin_dir_url($this->plugin->getDir()) . '/' . $script; 68 | $script = Sci::make(Script::class, [$src]); 69 | $this->scriptManager->register($script, $handle); 70 | } 71 | } 72 | 73 | return $this; 74 | } 75 | } -------------------------------------------------------------------------------- /framework/Asset/Services/StyleService.php: -------------------------------------------------------------------------------- 1 | 16 | * @copyright 2020 Kenodo LTD 17 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 18 | * @version 1.0.0 19 | * @link https://www.sciwp.com 20 | * @since Version 1.0.0 21 | */ 22 | class StyleService 23 | { 24 | /** @var string $plugin The plugin this service belongs to. */ 25 | private $plugin; 26 | 27 | /** @var string $key The plugin key */ 28 | private $key; 29 | 30 | /** @var StyleManager $styleManager The instance of the style manager. */ 31 | private $styleManager; 32 | 33 | /** 34 | * Constructor 35 | */ 36 | public function __construct($key, Plugin $plugin, StyleManager $styleManager) 37 | { 38 | $this->key = $key; 39 | $this->plugin = $plugin; 40 | $this->styleManager = $styleManager; 41 | } 42 | 43 | /** 44 | * Read the plugin configuration 45 | * 46 | * @param Plugin|string $plugin The plugin/id 47 | * @return StyleService 48 | */ 49 | public function configure() 50 | { 51 | $styles = $this->plugin->config()->get('styles'); 52 | 53 | if (!$styles) return; 54 | 55 | foreach ( (array) $styles as $handle => $style) { 56 | 57 | if (is_array($style)) { 58 | 59 | $src = plugin_dir_url($this->plugin->getDir()) . '/' . $style['src']; 60 | $version = $style['version'] ?? $version; 61 | $dependencies = $style['dependencies'] ?? []; 62 | $media = $style['media'] ?? $media; 63 | $zone = $style['zone'] ?? false; 64 | $style = Sci::make(Style::class, [$src, $version, $dependencies, $media]); 65 | $this->styleManager->register($style, $handle, $zone); 66 | } else { 67 | $src = plugin_dir_url($this->plugin->getDir()) . '/' . $style; 68 | $style = Sci::make(Style::class, [$src]); 69 | $this->styleManager->register($style, $handle); 70 | } 71 | } 72 | 73 | return $this; 74 | } 75 | } -------------------------------------------------------------------------------- /framework/Asset/Style.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Style extends Asset 22 | { 23 | /** @var string $media Media value for ccss files */ 24 | protected $media; 25 | 26 | /** @var StyleManager $styleManager The Style Manager */ 27 | protected $styleManager; 28 | 29 | /** 30 | * Create a new style 31 | * 32 | * @param string $handle The style handle 33 | * @param string $src The css file location 34 | * @param string $version The css file asset version 35 | * @param string[] $dependencies The registered css file dependencies 36 | * @param string $media The asset version 37 | */ 38 | public function __construct($src, $version = false, $dependencies = [], $media = 'all', StyleManager $styleManager) 39 | { 40 | parent::__construct($src, $version, $dependencies); 41 | $this->styleManager = $styleManager; 42 | $this->media = $media; 43 | } 44 | 45 | /** 46 | * Add a new style 47 | * 48 | * @param string|array $src The css file location 49 | * @param string $version The css file asset version 50 | * @param string[] $dependencies The registered css file dependencies 51 | * @param string $media The asset version 52 | * @return Style 53 | */ 54 | public static function create($src, $version = false, $dependencies = [], $media = 'all') 55 | { 56 | $style = Sci::make(self::class, [$src, $version, $dependencies, $media]); 57 | return $style; 58 | } 59 | 60 | /** 61 | * Add the asset to the asset manager 62 | * 63 | * @param string $handle The style handle 64 | * @param string $zone Frontend or admin panel 65 | * @return Style 66 | */ 67 | public function register($handle, $zone = false) 68 | { 69 | $this->styleManager->register($this, $handle, $zone); 70 | return $this; 71 | } 72 | 73 | /** 74 | * Returns if the asset media value for css files 75 | * 76 | * @return string 77 | */ 78 | public function getMedia() 79 | { 80 | return $this->media; 81 | } 82 | 83 | /** 84 | * Sets the media value for css files 85 | * 86 | * @param string $media The asset media value 87 | * @return Style 88 | */ 89 | public function setMedia($media) 90 | { 91 | $this->media = $media; 92 | return $this; 93 | } 94 | } -------------------------------------------------------------------------------- /framework/Autoloader.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | class Autoloader 17 | { 18 | /** @var string $mode The sci files autoloading mode */ 19 | private static $mode; 20 | 21 | /** @var string $folder Stores de root folder */ 22 | private static $folder; 23 | 24 | /** @var string $namespace Stores de framework namespace */ 25 | private static $namespace; 26 | 27 | /** @var string $plugins Stores the list of plugins using Sci */ 28 | private static $plugins = array(); 29 | 30 | /** @var array $cache Stores de cached classes */ 31 | public static $cache = array(); 32 | 33 | /** @var string $file_cache Stores de cache folder path */ 34 | private static $dir_cache; 35 | 36 | /** @var string $file_cache Stores de cache file path */ 37 | private static $file_cache; 38 | 39 | /** 40 | * Class constructor 41 | * 42 | * @return void 43 | */ 44 | private function __construct(){} 45 | 46 | /** 47 | * Clone 48 | * 49 | * @return void 50 | */ 51 | private function __clone() {} 52 | 53 | /** 54 | * Wakeup 55 | * 56 | * @return void 57 | */ 58 | private function __wakeup() {} 59 | 60 | /** 61 | * Initialize the autoloader 62 | * 63 | * @param string $mode The sci files autoloading mode 64 | * @return object 65 | */ 66 | public static function start($mode = 'embedded') 67 | { 68 | self::$mode = $mode; 69 | self::$folder = substr(plugin_dir_path( __FILE__ ), 0, -1); 70 | self::$namespace = trim(__NAMESPACE__,'\\'); 71 | spl_autoload_register( array(self::$namespace . '\Autoloader', 'autoload')); 72 | self::$dir_cache = dirname(self::$folder) . '/cache/'; 73 | self::$file_cache = self::$dir_cache . 'autoload.cache.php'; 74 | self::$cache = self::loadCache(); 75 | return self::class; 76 | } 77 | 78 | /** 79 | * Loads the autoloader cache 80 | * 81 | * @return bool 82 | */ 83 | public static function loadCache() 84 | { 85 | $cache_array = is_file(self::$file_cache) ? (array)include self::$file_cache : []; 86 | self::$cache = array_merge(self::$cache , $cache_array); 87 | return self::$cache; 88 | } 89 | 90 | /** 91 | * Saves the autoloader cache 92 | * 93 | * @return bool 94 | */ 95 | public static function saveCache() 96 | { 97 | if (!file_exists(self::$dir_cache)) mkdir(self::$dir_cache); 98 | file_put_contents(self::$file_cache, ' $config['namespace'], 155 | 'main_namespace' => ucfirst(preg_replace("/[^A-Za-z0-9]/", '', basename($config['main_dir']))), 156 | 'dir' => $config['dir'], 157 | 'main_dir' => $config['main_dir'], 158 | 'module_dir' => $config['module_dir'], 159 | 'cache_enabled' => isset($config['cache_enabled']) ? $config['cache_enabled'] : false, 160 | 'reflexive' => isset($config['reflexive']) ? $config['reflexive'] : false, 161 | 'autoload' => isset($config['autoload']) ? $config['autoload'] : [], 162 | ]; 163 | } 164 | 165 | 166 | /** 167 | * Includes a file 168 | * 169 | * @param string $file The file to include 170 | * @param string $class A class to save in the cache 171 | * @return bool 172 | */ 173 | public static function includeFile($file, $class = false) 174 | { 175 | if (file_exists($file)) { 176 | require_once $file; 177 | if ($class) { 178 | self::$cache[$class] = $file; 179 | self::saveCache(); 180 | } 181 | return true; 182 | } 183 | return false; 184 | } 185 | 186 | /** 187 | * File name has extension 188 | * 189 | * @param string $string The file name 190 | * @param string $extension The file extension 191 | * @return bool 192 | */ 193 | public static function hasExtension($file, $extension) 194 | { 195 | $fileLenght = strlen($file); 196 | $extensionLength = strlen($extension); 197 | 198 | if ($extensionLength > $fileLenght) return false; 199 | return substr_compare($file, $extension, $fileLenght - $extensionLength, $extensionLength) === 0; 200 | } 201 | 202 | /** 203 | * Main autoload function 204 | * 205 | * @param string $class The class name 206 | * @return bool 207 | */ 208 | public static function autoload($class) 209 | { 210 | $class = trim($class); 211 | $class_arr = explode('\\', $class); 212 | 213 | // Not a valid Sci namespace, as it should contain at least the base namespace and the class 214 | if (count ($class_arr) < 2) return false; 215 | 216 | // Sci files 217 | //wp_die($class_arr[0] . '\\' . $class_arr[1]); 218 | 219 | if (self::$mode == 'core' && $class_arr[0] == self::$namespace) { 220 | // Autoload Get trait 221 | if (!isset($class_arr[1])) { 222 | require_once self::$folder . '/Traits/Sci.php'; 223 | return true; 224 | } 225 | // Autoload regular Sci files 226 | else { 227 | $relative_class = trim(substr($class, strlen($class_arr[0])), '\\'); // Remove base namespace from the class name 228 | array_shift ($class_arr); // Remove base namespace from the array 229 | 230 | $class_file = self::$folder; 231 | $count_class_arr = count($class_arr); 232 | 233 | foreach ($class_arr as $key => $element) { 234 | $class_file .= '/' . $element; 235 | } 236 | 237 | if (self::includeFile($class_file . '.php')) return true; 238 | else if (self::includeFile($class_file . '.class.php')) return true; 239 | return false; 240 | } 241 | } 242 | 243 | if (self::$mode == 'embedded' && $class_arr[0] . '\\' . $class_arr[1] == self::$namespace) { 244 | 245 | // Autoload Get trait 246 | if (!isset($class_arr[2])) { 247 | require_once self::$folder . '/Traits/Sci.php'; 248 | return true; 249 | } 250 | // Autoload regular Sci files 251 | else { 252 | $relative_class = trim(substr($class, strlen($class_arr[0])), '\\'); // Remove base namespace from the class name 253 | array_shift ($class_arr); // Remove base namespace from the array 254 | array_shift ($class_arr); // Remove Sci namespace from the array 255 | 256 | $class_file = self::$folder; 257 | $count_class_arr = count($class_arr); 258 | 259 | foreach ($class_arr as $key => $element) { 260 | $class_file .= '/' . $element; 261 | } 262 | 263 | if (self::includeFile($class_file . '.php')) return true; 264 | else if (self::includeFile($class_file . '.class.php')) return true; 265 | return false; 266 | } 267 | } else { 268 | // Check the cache array 269 | if (self::checkCache($class)) return true; 270 | 271 | $plugin = false; 272 | 273 | foreach(self::$plugins as $key => &$p) { 274 | 275 | if ($p['namespace'] == $class_arr[0]) { 276 | $plugin = $p; 277 | } 278 | 279 | $classToCache = $p['cache_enabled'] ? $class : false; 280 | 281 | // Configured custom namespaces 282 | foreach ($p['autoload'] as $keyAutoload => $folder) { 283 | 284 | $base = trim($keyAutoload,'\\'); 285 | 286 | if (substr($class, 0, strlen($base)) === $base ) { 287 | 288 | $class_file = $p['dir']. '/'. trim($folder,'\/'); 289 | $class_arr_r = explode('\\', substr($class, strlen($base), strlen($class))); 290 | 291 | foreach ($class_arr_r as $key => $element) { 292 | if ($element) $class_file .= '/' . $element; 293 | } 294 | 295 | if (self::includeFile($class_file . '.php', $classToCache)) return true; 296 | if (self::includeFile($class_file . '.class.php', $classToCache)) return true; 297 | } 298 | } 299 | } 300 | 301 | if (!$plugin) return false; 302 | $classToCache = $plugin['cache_enabled'] ? $class : false; 303 | 304 | // Remove the base plugin namespace 305 | $relative_class = trim(substr($class, strlen($class_arr[0])), '\\'); // Remove base namespace from the class name 306 | array_shift ($class_arr); // Remove base namespace from the array 307 | 308 | $class_file = $plugin['dir']; 309 | 310 | foreach ($class_arr as $key => $element) { 311 | if ($key == 0) { 312 | if (count($class_arr) > 1) { 313 | switch ($element) { 314 | case $plugin['main_namespace']: 315 | $class_file = $plugin['main_dir']; 316 | break; 317 | default: $class_file = $plugin['module_dir'] .'/'. $element; 318 | } 319 | } 320 | else { 321 | $class_file .= '/' . $element; 322 | } 323 | } 324 | else { 325 | $class_file .= '/' . $element; 326 | } 327 | } 328 | 329 | if (self::includeFile($class_file . '.php', $classToCache)) return true; 330 | if (self::includeFile($class_file . '.class.php', $classToCache)) return true; 331 | 332 | if ($plugin['reflexive']) { 333 | // Namespace structure is a file name with the class suffix 334 | $found = false; 335 | $class_name = ''; 336 | foreach ( array_reverse($class_arr) as $key => $namespace) { 337 | if ($key == count($class_arr) - 1) { 338 | $class_name .= $namespace.'.'; 339 | } 340 | else { 341 | $class_name .= $namespace . '.'; 342 | } 343 | } 344 | $file = self::searchReflexiveClassFile($plugin['dir'], $class_name.'class.php'); 345 | if ($file && self::includeFile($file, $classToCache)) return true; 346 | } 347 | return false; 348 | } 349 | } 350 | } -------------------------------------------------------------------------------- /framework/Component.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | class Component 17 | { 18 | /** 19 | * Creates an object of the class 20 | * 21 | * @param mixed[] $params The method parameters 22 | */ 23 | public static function create(...$params) 24 | { 25 | return new static(...$params); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /framework/Database/DB.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | abstract class DB 17 | { 18 | /** 19 | * Returns the table name 20 | * 21 | * @param string $table The table name 22 | * @return Query 23 | */ 24 | public static function table($tableName) 25 | { 26 | $query = new Query($tableName); 27 | return $query; 28 | } 29 | 30 | /** 31 | * Start a query 32 | * 33 | * @return Query 34 | */ 35 | public static function query() 36 | { 37 | return new Query(); 38 | } 39 | } -------------------------------------------------------------------------------- /framework/Database/Model.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | abstract class Model 19 | { 20 | /** @const string The primary key for the model */ 21 | const PRIMARY_KEY = 'id'; 22 | 23 | /** @const bool Indicates if the IDs are auto-incrementing */ 24 | const AUTO_INCREMENT = true; 25 | 26 | /** @var boolean Enable created, deleted and updated date fields */ 27 | const TIMESTAMPS = false; 28 | 29 | /** @const string The name of the "created at" column */ 30 | const CREATED_AT = 'created_at'; 31 | 32 | /** @const string The name of the "updated at" column */ 33 | const UPDATED_AT = 'updated_at'; 34 | 35 | /** @const string The name of the "deleted at" column */ 36 | const DELETED_AT = 'deleted_at'; 37 | 38 | /** @var boolean The table associated with the model */ 39 | const TABLE_NAME = false; 40 | 41 | /** @var boolean The table associated with the model */ 42 | const TABLE_PREFIX = true; 43 | 44 | /** @var array $attributes of model attributes */ 45 | protected $attributes = []; 46 | 47 | /** 48 | * Return configured table prefix 49 | * 50 | * @return string 51 | */ 52 | public static function tablePrefix() 53 | { 54 | if (static::TABLE_PREFIX) { 55 | global $wpdb; 56 | return $wpdb->prefix; 57 | } else { 58 | return ''; 59 | } 60 | } 61 | 62 | /** 63 | * Returns the table name 64 | * 65 | * @return string 66 | */ 67 | public static function table() 68 | { 69 | if (static::TABLE_NAME) { 70 | return static::tablePrefix().static::TABLE_NAME; 71 | } else { 72 | return static::tablePrefix().Str::toPlural(strtolower(substr(strrchr(get_called_class(), "\\"), 1))); 73 | } 74 | } 75 | 76 | /** 77 | * Get the column used as the primary key, defaults to 'id' 78 | * 79 | * @return string 80 | */ 81 | public static function primaryKey() 82 | { 83 | return static::PRIMARY_KEY; 84 | } 85 | 86 | /** 87 | * Create a new object from the given data 88 | * 89 | * @return self 90 | */ 91 | public static function create($attributes = []) 92 | { 93 | return new static($attributes); 94 | } 95 | 96 | /** 97 | * Constructor 98 | * 99 | * @param array $properties 100 | */ 101 | public function __construct(array $attributes = array()) 102 | { 103 | foreach ($attributes as $key => $value) { 104 | $this->attributes[$key] = maybe_unserialize($value); 105 | } 106 | } 107 | 108 | /** 109 | * Get a property via the mafic get method 110 | * 111 | * @param string $key 112 | * @return mixed 113 | */ 114 | public function __get($key) 115 | { 116 | if (isset($this->attributes[$key])) return $this->attributes[$key]; 117 | else return null; 118 | } 119 | 120 | /** 121 | * Set a property via the magic get method 122 | * 123 | * @param string $key 124 | * @param mixed $value 125 | * @return Model 126 | */ 127 | public function __set($key, $value) 128 | { 129 | $this->attributes[$key] = $value; 130 | return $this; 131 | } 132 | 133 | /** 134 | * Magically handle getters and setters for the class properties 135 | * 136 | * @param string $function 137 | * @param array $arguments 138 | * @return mixed 139 | */ 140 | public function __call($function, $arguments) 141 | { 142 | // Getters following the pattern 'get_{$property}' 143 | if (substr($function, 0, 3) == 'get') { 144 | $model_props = get_object_vars($this); 145 | $property = lcfirst(substr($function, 3)); 146 | 147 | if (array_key_exists($property, $model_props)) { 148 | return $this->{$property}; 149 | } 150 | } 151 | 152 | // Setters following the pattern 'set_{$property}' 153 | if (substr($function, 0, 3) == 'set') { 154 | $model_props = get_object_vars($this); 155 | $property = lcfirst(substr($function, 3)); 156 | 157 | if (array_key_exists($property, $model_props)) { 158 | $this->{$property} = $arguments[0]; 159 | } 160 | } 161 | } 162 | 163 | /** 164 | * flattenProps 165 | * 166 | * @param array $props 167 | * @return array 168 | */ 169 | public function flattenProps($props) 170 | { 171 | foreach ($props as $property => $value) { 172 | if (is_object($value) && get_class($value) == 'DateTime') { 173 | $props[$property] = $value->format('Y-m-d H:i:s'); 174 | } else if (is_array($value)) { 175 | $props[$property] = serialize($value); 176 | } else if ($value instanceof AbstractClass) { 177 | $props[$property] = $value->{$value->primaryKey()}[0]; 178 | } 179 | } 180 | return $props; 181 | } 182 | 183 | /** 184 | * Save the model into the database creating or updating a record 185 | * 186 | * @return Model 187 | */ 188 | public function save() 189 | { 190 | global $wpdb; 191 | 192 | $attributes = $this->attributes; 193 | $isNewRecord = !array_key_exists(static::primaryKey(), $attributes); 194 | 195 | // Convert complex objects to strings to insert into the database 196 | foreach ($attributes as $key => $value) { 197 | if (is_object($value) && get_class($value) == 'DateTime') { 198 | $attributes[$key] = $value->format('Y-m-d H:i:s'); 199 | } else if (is_array($value)) { 200 | $attributes[$key] = serialize($value); 201 | } else if ($value instanceof AbstractClass) { 202 | $attributes[$key] = $value->{$value->primaryKey()}[0]; 203 | } 204 | } 205 | 206 | if (static::TIMESTAMPS) { 207 | $attributes[static::UPDATED_AT] = date("Y-m-d h:i:s"); 208 | if ($isNewRecord) $attributes[static::CREATED_AT] = $attributes[static::UPDATED_AT]; 209 | } 210 | 211 | if ($isNewRecord) { 212 | if (!static::AUTO_INCREMENT) { 213 | $attributes[static::primaryKey()] = uniqid(); 214 | } 215 | $wpdb->insert($this->table(), $attributes); 216 | $this->{static::primaryKey()} = $wpdb->insert_id; 217 | } else { 218 | $wpdb->update(static::table(), $attributes, [static::primaryKey() => $attributes[static::primaryKey()]]); 219 | } 220 | 221 | if (static::TIMESTAMPS) { 222 | $this->attributes[static::UPDATED_AT] = $attributes[static::UPDATED_AT]; 223 | if ($isNewRecord) $this->attributes[static::CREATED_AT] = $attributes[static::CREATED_AT]; 224 | } 225 | 226 | return $this; 227 | } 228 | 229 | /** 230 | * Return all database records for this model 231 | * 232 | * @param int $skip 233 | * @param int $limit 234 | * @return array 235 | */ 236 | public static function findAll($skip = false, $limit = false) 237 | { 238 | $query = new Query(); 239 | $query->setModel(get_called_class()); 240 | if ($skip) $query->skip($skip); 241 | if ($limit) $query->limit($limit); 242 | 243 | $models = []; 244 | $results = $query->get(); 245 | if ($results) { 246 | foreach ($results as $index => $result) { 247 | $models[$index] = static::create((array) $result); 248 | } 249 | } 250 | return $models; 251 | } 252 | 253 | /** 254 | * Find an array if models by ID or array of IDs 255 | * 256 | * @param integer|array $id 257 | * @return array 258 | */ 259 | public static function find(...$queries) 260 | { 261 | $queries = func_get_args(); 262 | $hasArray = false; 263 | $skip = false; 264 | $limit = false; 265 | 266 | foreach($queries as $query) { 267 | if (is_array($query)) $hasArray = true; 268 | } 269 | 270 | if ($hasArray && is_int($queries[count($queries) - 1])) { 271 | $skip = array_pop($queries); 272 | if (is_int($queries[count($queries) - 1])) { 273 | $limit = $skip; 274 | $skip = array_pop($queries); 275 | } 276 | } 277 | 278 | $query = new Query(); 279 | $query->setModel(get_called_class()); 280 | 281 | call_user_func_array([$query, 'where'], $queries); 282 | 283 | if ($skip) $query->skip($skip); 284 | if ($limit) $query->limit($limit); 285 | 286 | $models = []; 287 | $results = $query->get(); 288 | if ($results) { 289 | foreach ($results as $index => $result) { 290 | $models[$index] = static::create((array) $result); 291 | } 292 | } 293 | return $models; 294 | } 295 | 296 | /** 297 | * Find a specific model by a given property value. 298 | * 299 | * @param string $property 300 | * @param string $value 301 | * @return false|Model 302 | */ 303 | public static function findOne(...$queries) 304 | { 305 | $queries = func_get_args(); 306 | $query = new Query(); 307 | $query->setModel(get_called_class()); 308 | 309 | call_user_func_array([$query, 'where'], $queries); 310 | 311 | $query->skip(0)->limit(1); 312 | 313 | $results = $query->get(); 314 | if (count($results)) { 315 | return static::create((array) $results[0]); 316 | } 317 | return false; 318 | } 319 | 320 | /** 321 | * Delete the model from the database 322 | * 323 | * @return boolean 324 | */ 325 | public function delete() 326 | { 327 | global $wpdb; 328 | return $wpdb->delete(static::table(), array(static::primaryKey() => $this->{static::primaryKey()})); 329 | } 330 | 331 | /** 332 | * Soft delete the model from the database 333 | * 334 | * @return self 335 | */ 336 | public function remove() 337 | { 338 | global $wpdb; 339 | if (static::TIMESTAMPS) { 340 | $wpdb->update(static::table(),[static::DELETED_AT => date("Y-m-d h:i:s")], array(static::primaryKey() => $this->attributes[static::primaryKey()])); 341 | } 342 | return $this; 343 | } 344 | 345 | /** 346 | * Start a query to find models matching specific criteria 347 | * 348 | * @return Query 349 | */ 350 | public static function query() 351 | { 352 | $query = new Query(); 353 | $query->setModel(get_called_class()); 354 | return $query; 355 | } 356 | } -------------------------------------------------------------------------------- /framework/Helpers/Arr.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class Arr extends Helper 20 | { 21 | /** 22 | * Sorts an array by a property inside its elements, which can be objects or arrays 23 | * 24 | * @param array $arr The array we want to process 25 | * @param string $index The array index or attribute name 26 | * @param bool $asc Order ascending if true, descending in false 27 | * @param bool $preserveKeys Keep array indexes 28 | * @return array 29 | */ 30 | public static function sortBySubValue($arr, $index, $asc = true, $preserveKeys = false) 31 | { 32 | if (is_object(reset($arr))) { 33 | $preserveKeys ? uasort($arr, function ($a, $b) use ($index, $asc) { 34 | return $a->{$index} == $b->{$index} ? 0 : ($a->{$index} - $b->{$index}) * ($asc ? 1 : -1); 35 | }) : usort($arr, function ($a, $b) use ($index, $asc) { 36 | return $a->{$index} == $b->{$index} ? 0 : ($a->{$index} - $b->{$index}) * ($asc ? 1 : -1); 37 | }); 38 | } else { 39 | $preserveKeys ? uasort($arr, function ($a, $b) use ($index, $asc) { 40 | return $a[$index] == $b[$index] ? 0 : ($a[$index] - $b[$index]) * ($asc ? 1 : -1); 41 | }) : usort($arr, function ($a, $b) use ($index, $asc) { 42 | return $a[$index] == $b[$index] ? 0 : ($a[$index] - $b[$index]) * ($asc ? 1 : -1); 43 | }); 44 | } 45 | return $arr; 46 | } 47 | 48 | /** 49 | * Merges 2 arrays and sub arrays, overwriting existing values 50 | * 51 | * @param array $arr The array we want to process 52 | * @param string $index The array index or attribute name 53 | * @param bool $asc Order ascending if true, descending in false 54 | * @param bool $preserveKeys Keep array indexes 55 | * @return array 56 | */ 57 | public static function mergeRecursive(array &$array1, array &$array2) 58 | { 59 | $merged = $array1; 60 | foreach ($array2 as $key => &$value) { 61 | if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { 62 | $merged[$key] = self::arrayMergeRecursiveDistinct($merged[$key], $value); 63 | } 64 | else { 65 | $merged[$key] = $value; 66 | } 67 | } 68 | return $merged; 69 | } 70 | 71 | /** 72 | * Determine whether the given value is array accessible. 73 | * 74 | * @param mixed $value 75 | * @return bool 76 | */ 77 | public static function accessible($value) 78 | { 79 | return is_array($value) || $value instanceof ArrayAccess; 80 | } 81 | 82 | /** 83 | * Collapse an array of arrays into a single array. 84 | * 85 | * @param array $array 86 | * @return array 87 | */ 88 | public static function collapse($array) 89 | { 90 | $results = []; 91 | foreach ($array as $values) { 92 | if ($values instanceof Collection) { 93 | $values = $values->all(); 94 | } elseif (! is_array($values)) { 95 | continue; 96 | } 97 | $results = array_merge($results, $values); 98 | } 99 | return $results; 100 | } 101 | 102 | /** 103 | * Determine if the given key exists in the provided array. 104 | * 105 | * @param \ArrayAccess|array $array 106 | * @param string|int $key 107 | * @return bool 108 | */ 109 | public static function exists($array, $key) 110 | { 111 | if ($array instanceof ArrayAccess) { 112 | return $array->offsetExists($key); 113 | } 114 | return array_key_exists($key, $array); 115 | } 116 | 117 | /** 118 | * Get all of the given array except for a specified array of keys. 119 | * 120 | * @param array $array 121 | * @param array|string $keys 122 | * @return array 123 | */ 124 | public static function except($array, $keys) 125 | { 126 | static::forget($array, $keys); 127 | return $array; 128 | } 129 | 130 | /** 131 | * Flatten a multi-dimensional array into a single level. 132 | * 133 | * @param array $array 134 | * @param int $depth 135 | * @return array 136 | */ 137 | public static function flatten($array, $depth = INF) 138 | { 139 | $result = []; 140 | foreach ($array as $item) { 141 | $item = $item instanceof Collection ? $item->all() : $item; 142 | if (! is_array($item)) { 143 | $result[] = $item; 144 | } elseif ($depth === 1) { 145 | $result = array_merge($result, array_values($item)); 146 | } else { 147 | $result = array_merge($result, static::flatten($item, $depth - 1)); 148 | } 149 | } 150 | return $result; 151 | } 152 | 153 | /** 154 | * Push an item onto the beginning of an array. 155 | * 156 | * @param array $array 157 | * @param mixed $value 158 | * @param mixed $key 159 | * @return array 160 | */ 161 | public static function prepend($array, $value, $key = null) 162 | { 163 | if (is_null($key)) { 164 | array_unshift($array, $value); 165 | } else { 166 | $array = [$key => $value] + $array; 167 | } 168 | return $array; 169 | } 170 | /** 171 | * Get a value from the array, and remove it. 172 | * 173 | * @param array $array 174 | * @param string $key 175 | * @param mixed $default 176 | * @return mixed 177 | */ 178 | public static function pull(&$array, $key, $default = null) 179 | { 180 | $value = static::get($array, $key, $default); 181 | static::forget($array, $key); 182 | return $value; 183 | } 184 | /** 185 | * Get one or a specified number of random values from an array. 186 | * 187 | * @param array $array 188 | * @param int|null $number 189 | * @return mixed 190 | * 191 | * @throws \InvalidArgumentException 192 | */ 193 | public static function getRandom($array, $number = null) 194 | { 195 | $requested = is_null($number) ? 1 : $number; 196 | $count = count($array); 197 | if ($requested > $count) { 198 | throw new InvalidArgumentException( 199 | "You requested {$requested} items, but there are only {$count} items available." 200 | ); 201 | } 202 | if (is_null($number)) { 203 | return $array[array_rand($array)]; 204 | } 205 | if ((int) $number === 0) { 206 | return []; 207 | } 208 | $keys = array_rand($array, $number); 209 | $results = []; 210 | foreach ((array) $keys as $key) { 211 | $results[] = $array[$key]; 212 | } 213 | return $results; 214 | } 215 | 216 | /** 217 | * Recursively sort an array by keys and values. 218 | * 219 | * @param array $array 220 | * @return array 221 | */ 222 | public static function sortRecursive($array) 223 | { 224 | foreach ($array as &$value) { 225 | if (is_array($value)) { 226 | $value = static::sortRecursive($value); 227 | } 228 | } 229 | if (static::isAssoc($array)) { 230 | ksort($array); 231 | } else { 232 | sort($array); 233 | } 234 | return $array; 235 | } 236 | 237 | /** 238 | * Convert the array into a query string. 239 | * 240 | * @param array $array 241 | * @return string 242 | */ 243 | public static function query($array) 244 | { 245 | return http_build_query($array, null, '&', PHP_QUERY_RFC3986); 246 | } 247 | 248 | /** 249 | * Filter the array using the given callback. 250 | * 251 | * @param array $array 252 | * @param callable $callback 253 | * @return array 254 | */ 255 | public static function where($array, callable $callback) 256 | { 257 | return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); 258 | } 259 | } -------------------------------------------------------------------------------- /framework/Helpers/Folder.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class Folder extends Helper 20 | { 21 | /** 22 | * Require all files in a folder, including subfolders 23 | * 24 | * @param $folder An absolute system path 25 | */ 26 | public static function requireAll ($folder) 27 | { 28 | $scan = preg_grep('/^([^.])/', scandir($folder)); 29 | foreach ($scan as $file) { 30 | if(is_dir ($folder.'/'.$file)) { 31 | self::requireAll($folder.'/'.$file); 32 | } 33 | else { 34 | require_once($folder.'/'.$file); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /framework/Helpers/Inflector.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class Inflector extends Helper 19 | { 20 | static $plural = [ 21 | '/(quiz)$/i' => "$1zes", 22 | '/^(ox)$/i' => "$1en", 23 | '/([m|l])ouse$/i' => "$1ice", 24 | '/(matr|vert|ind)ix|ex$/i' => "$1ices", 25 | '/(x|ch|ss|sh)$/i' => "$1es", 26 | '/([^aeiouy]|qu)y$/i' => "$1ies", 27 | '/(hive)$/i' => "$1s", 28 | '/(?:([^f])fe|([lr])f)$/i' => "$1$2ves", 29 | '/(shea|lea|loa|thie)f$/i' => "$1ves", 30 | '/sis$/i' => "ses", 31 | '/([ti])um$/i' => "$1a", 32 | '/(tomat|potat|ech|her|vet)o$/i'=> "$1oes", 33 | '/(bu)s$/i' => "$1ses", 34 | '/(alias)$/i' => "$1es", 35 | '/(octop)us$/i' => "$1i", 36 | '/(ax|test)is$/i' => "$1es", 37 | '/(us)$/i' => "$1es", 38 | '/s$/i' => "s", 39 | '/$/' => "s" 40 | ]; 41 | 42 | static $singular = [ 43 | '/(quiz)zes$/i' => "$1", 44 | '/(matr)ices$/i' => "$1ix", 45 | '/(vert|ind)ices$/i' => "$1ex", 46 | '/^(ox)en$/i' => "$1", 47 | '/(alias)es$/i' => "$1", 48 | '/(octop|vir)i$/i' => "$1us", 49 | '/(cris|ax|test)es$/i' => "$1is", 50 | '/(shoe)s$/i' => "$1", 51 | '/(o)es$/i' => "$1", 52 | '/(bus)es$/i' => "$1", 53 | '/([m|l])ice$/i' => "$1ouse", 54 | '/(x|ch|ss|sh)es$/i' => "$1", 55 | '/(m)ovies$/i' => "$1ovie", 56 | '/(s)eries$/i' => "$1eries", 57 | '/([^aeiouy]|qu)ies$/i' => "$1y", 58 | '/([lr])ves$/i' => "$1f", 59 | '/(tive)s$/i' => "$1", 60 | '/(hive)s$/i' => "$1", 61 | '/(li|wi|kni)ves$/i' => "$1fe", 62 | '/(shea|loa|lea|thie)ves$/i'=> "$1f", 63 | '/(^analy)ses$/i' => "$1sis", 64 | '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => "$1$2sis", 65 | '/([ti])a$/i' => "$1um", 66 | '/(n)ews$/i' => "$1ews", 67 | '/(h|bl)ouses$/i' => "$1ouse", 68 | '/(corpse)s$/i' => "$1", 69 | '/(us)es$/i' => "$1", 70 | '/s$/i' => "" 71 | ]; 72 | 73 | static $irregular = [ 74 | 'move' => 'moves', 75 | 'foot' => 'feet', 76 | 'goose' => 'geese', 77 | 'sex' => 'sexes', 78 | 'child' => 'children', 79 | 'man' => 'men', 80 | 'tooth' => 'teeth', 81 | 'person' => 'people' 82 | ]; 83 | 84 | static $uncountable = [ 85 | 'sheep', 86 | 'fish', 87 | 'deer', 88 | 'series', 89 | 'species', 90 | 'money', 91 | 'rice', 92 | 'information', 93 | 'equipment' 94 | ]; 95 | 96 | /** 97 | * Make a singular string plural 98 | * 99 | * @param string $word 100 | * @return string 101 | */ 102 | public static function pluralize( $string ) 103 | { 104 | // In the case that singular and plural are the same 105 | if ( in_array( strtolower( $string ), self::$uncountable ) ) { 106 | return $string; 107 | } 108 | 109 | // Check for irregular singular forms 110 | foreach ( self::$irregular as $pattern => $result ) 111 | { 112 | $pattern = '/' . $pattern . '$/i'; 113 | 114 | if ( preg_match( $pattern, $string ) ) { 115 | return preg_replace( $pattern, $result, $string); 116 | } 117 | } 118 | 119 | // Check for matches using regular expressions 120 | foreach ( self::$plural as $pattern => $result ) 121 | { 122 | if ( preg_match( $pattern, $string ) ) { 123 | return preg_replace( $pattern, $result, $string ); 124 | } 125 | } 126 | 127 | return $string; 128 | } 129 | 130 | /** 131 | * Make a plural string singular 132 | * 133 | * @param string $word 134 | * @return string 135 | */ 136 | public static function singularize( $string ) 137 | { 138 | // In the case that singular and plural are the same 139 | if ( in_array( strtolower( $string ), self::$uncountable ) ) { 140 | return $string; 141 | } 142 | 143 | // Check for irregular plural forms 144 | foreach ( self::$irregular as $result => $pattern ) 145 | { 146 | $pattern = '/' . $pattern . '$/i'; 147 | 148 | if ( preg_match( $pattern, $string ) ) { 149 | return preg_replace( $pattern, $result, $string); 150 | } 151 | } 152 | 153 | // Check for matches using regular expressions 154 | foreach ( self::$singular as $pattern => $result ) 155 | { 156 | if ( preg_match( $pattern, $string ) ) { 157 | return preg_replace( $pattern, $result, $string ); 158 | } 159 | } 160 | 161 | return $string; 162 | } 163 | 164 | /** 165 | * Count and maybe pluralize a number of elements 166 | * 167 | * @param number $count 168 | * @param string $word 169 | * @return string 170 | */ 171 | public static function reckon($count, $word) 172 | { 173 | if ($count == 1) { 174 | return "1 $word"; 175 | } else { 176 | return $count . " " . self::pluralize($word); 177 | } 178 | } 179 | } -------------------------------------------------------------------------------- /framework/Helpers/Scripts.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class Scripts extends Helper 19 | { 20 | /** 21 | * Include Sci admin scripts 22 | */ 23 | public static function includeAdmin() 24 | { 25 | wp_enqueue_style( 'wp-color-picker' ); 26 | wp_enqueue_script( 'wp-color-picker' ); 27 | wp_enqueue_media(); 28 | wp_enqueue_script('Sci_scripts', plugins_url('Sci/Resources/js/admin_scripts.js', __FILE__ ), false, '0.1', true); 29 | } 30 | } -------------------------------------------------------------------------------- /framework/Helpers/Str.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class Str extends Helper 20 | { 21 | /** 22 | * Cuts a text given a string limit, keeping complete words 23 | * 24 | * @param string $string 25 | * @param int $word_limit_count 26 | * @return string 27 | */ 28 | public static function limitWords($string, $word_limit_count) 29 | { 30 | $words = explode(' ', $string, ($word_limit_count + 1)); 31 | if(count($words) > $word_limit_count) array_pop($words); 32 | return implode(' ', $words); 33 | } 34 | 35 | /** 36 | * In a post context, cuts a text fiven a string limit, keeping complete words [get_the_content()] 37 | * 38 | * @param string $content 39 | * @param int $word_limit_count 40 | * @return string 41 | */ 42 | public static function contentLimitWords($content, $word_limit_count) 43 | { 44 | $content = explode(' ', wp_strip_all_tags($content), $word_limit_count); 45 | if (count($content)>=$word_limit_count) { 46 | array_pop($content); 47 | $content = implode(" ",$content).'...'; 48 | } 49 | else { 50 | $content = implode(" ",$content); 51 | } 52 | $content = preg_replace('/\[.+\]/','', $content); 53 | $content = str_replace(']]>', ']]>', $content); 54 | return $content; 55 | } 56 | 57 | /** 58 | * Checks if a URL is valid 59 | * 60 | * @param string $url 61 | * @return bool 62 | */ 63 | public static function isValidUrl ($url) 64 | { 65 | if($url == '') { return false; } 66 | $url = filter_var($url, FILTER_SANITIZE_URL); 67 | if (!filter_var($url, FILTER_VALIDATE_URL) === false) { 68 | return $url; 69 | } 70 | return false; 71 | } 72 | 73 | /** 74 | * Checks if a string starts by a substring 75 | * 76 | * @param string $string 77 | * @param string $substring 78 | * @param bool $caseSensitive 79 | * @return bool 80 | */ 81 | public static function startsWith($string, $subString, $caseSensitive = false) 82 | { 83 | if ($caseSensitive === false) { 84 | $string = mb_strtolower($string); 85 | $subString = mb_strtolower($subString); 86 | } 87 | 88 | if (mb_substr($string, 0, mb_strlen($subString)) == $subString) return true; 89 | return false; 90 | } 91 | 92 | /** 93 | * Checks if a string ends by a substring 94 | * 95 | * @param string $string 96 | * @param string $substring 97 | * @param bool $caseSensitive 98 | * @return bool 99 | */ 100 | public static function endsWith($string, $subString, $caseSensitive = false) 101 | { 102 | if ($caseSensitive === false) { 103 | $string = mb_strtolower($string); 104 | $subString = mb_strtolower($subString); 105 | } 106 | 107 | $strlen = strlen($string); 108 | $subStringLength = strlen($subString); 109 | 110 | if ($subStringLength > $strlen) return false; 111 | return substr_compare($string, $subString, $strlen - $subStringLength, $subStringLength) === 0; 112 | } 113 | 114 | /** 115 | * Checks if a string contains a substring 116 | * 117 | * @param string $string 118 | * @param string $substring 119 | * @param bool $caseSensitive 120 | * @return bool 121 | */ 122 | public static function contains($string, $substring, $caseSensitive = false) 123 | { 124 | if ($caseSensitive === false) { 125 | $string = mb_strtolower($string); 126 | $substring = mb_strtolower($substring); 127 | } 128 | 129 | if (mb_substr_count($string, $substring) > 0) return true; 130 | return false; 131 | } 132 | 133 | /** 134 | * Transforms a plural string into singular 135 | * 136 | * @param string $string 137 | * @return string 138 | */ 139 | public static function toSingular($string) 140 | { 141 | return Inflector::singularize($string); 142 | } 143 | 144 | /** 145 | * Transforms a singular string into plural 146 | * 147 | * @param string $string 148 | * @return string 149 | */ 150 | public static function toPlural($string) 151 | { 152 | return Inflector::pluralize($string); 153 | } 154 | 155 | /** 156 | * Transforms a singular string into plural 157 | * 158 | * @param number $count 159 | * @param string $word 160 | * @return string 161 | */ 162 | public static function reckon($number, $string) 163 | { 164 | return Inflector::reckon($string); 165 | } 166 | } -------------------------------------------------------------------------------- /framework/Helpers/Url.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class Url extends Helper 19 | { 20 | /** 21 | * Get an array with the URL segments 22 | * @string $url Any URL 23 | * @return array 24 | */ 25 | private static function segments ($url = false) 26 | { 27 | $segments = array(); 28 | if (!$url) $url = substr(preg_replace('/\?.*/', '', $_SERVER['REQUEST_URI']), 1); 29 | foreach (explode('/', $url) as $key => $param) { 30 | $segments[$key] = str_replace('/', '', $param); 31 | } 32 | return $segments; 33 | } 34 | } -------------------------------------------------------------------------------- /framework/Helpers/V.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class V extends Helper 19 | { 20 | /** 21 | * Get the content of a variable only if is set, default or empty if not. 22 | * 23 | * @param mixed $var 24 | * @param bool $default The default fallback value 25 | * @return mixed 26 | */ 27 | public static function get(&$var, $default = false) 28 | { 29 | return (isset($var) && ($var!='')) ? $var : $default; 30 | } 31 | 32 | /** 33 | * Echo the content of a variable only if is set. 34 | * 35 | * @param mixed 36 | */ 37 | public static function e(&$var) 38 | { 39 | if (isset($var)) echo($var); 40 | } 41 | 42 | /** 43 | * Escape a variable or array of values. 44 | * 45 | * @param mixed $data 46 | * @return mixed 47 | */ 48 | public static function escape( $data ) { 49 | return esc_sql($data); 50 | } 51 | 52 | /** 53 | * In a select field, prints the value and selected HTML attributes 54 | * 55 | * @param mixed $var The variable to check 56 | * @param mixed $value The option value 57 | */ 58 | public static function selectVar(&$var, $value = false) 59 | { 60 | if (isset($var) && $var == $value) echo('selected '); 61 | echo('value="'.$value.'"'); 62 | } 63 | 64 | /** 65 | * Escape GET array values 66 | */ 67 | public static function escapeGet () 68 | { 69 | foreach ($_GET as $clave => $valor) { 70 | $_GET[$clave] = esc_sql($_GET[$clave]); 71 | } 72 | } 73 | 74 | /** 75 | * Escapes POST array values 76 | */ 77 | public static function escapePost () 78 | { 79 | foreach ($_POST as $clave => $valor) { 80 | $_POST[$clave] = esc_sql($_POST[$clave]); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /framework/Manager.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class Manager 20 | { 21 | use Singleton; 22 | 23 | /** @var $sci The Sci class reference */ 24 | protected $sci; 25 | 26 | /** 27 | * Class constructor 28 | */ 29 | protected function __construct() 30 | { 31 | $this->sci = Sci::class; 32 | } 33 | } -------------------------------------------------------------------------------- /framework/Plugin/Managers/PluginManager.php: -------------------------------------------------------------------------------- 1 | 17 | * @copyright 2020 Kenodo LTD 18 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 19 | * @version 1.0.0 20 | * @link https://www.sciwp.com 21 | * @since Version 1.0.0 22 | */ 23 | class PluginManager extends Manager 24 | { 25 | /** @var array $plugins Stores a list of the registered plugins */ 26 | private $plugins = array(); 27 | 28 | /** @var $autoloader Reference to the Autoloader class */ 29 | private $autoloader; 30 | 31 | /** @var string $mainPluginKey Stores the main plugin key */ 32 | private $mainPluginKey = false; 33 | 34 | public function __construct(ProviderManager $providerManager) 35 | { 36 | parent::__construct(); 37 | $this->providerManager = $providerManager; 38 | $this->autoloader = Autoloader::class; 39 | } 40 | 41 | /** 42 | * Load a plugin into the plugin manager 43 | * 44 | * @param string $plugin_file The plugin file path 45 | * @param string|bool $pluginId The plugin id 46 | * @return Plugin 47 | */ 48 | public function register($plugin, $pluginId = false, $addon = false) 49 | { 50 | 51 | if (!$pluginId) $pluginId = str_replace( ' ', '-', strtolower(basename($plugin->getDir()))); 52 | 53 | if (isset($this->plugins[$pluginId])) { 54 | throw new Exception('The plugin with id ' . $pluginId . ' is already registered.'); 55 | } 56 | 57 | $this->plugins[$pluginId] = $plugin; 58 | 59 | if (!$addon) $this->mainPluginKey = $pluginId; 60 | 61 | // Add the plugin to the Autoloader 62 | $autoload = $plugin->config->get('autoloader/autoload'); 63 | $autoloadData = [ 64 | 'namespace' => $plugin->getNamespace(), 65 | 'dir' => $plugin->getDir(), 66 | 'main_dir' => $plugin->getMainDir(), 67 | 'module_dir' => $plugin->getModulesDir(), 68 | 'cache_enabled' => $plugin->getAutoloaderCacheEnabled(), 69 | 'reflexive' => $plugin->config->get('autoloader/reflexive'), 70 | 'autoload' => $autoload ? $autoload : [], 71 | ]; 72 | 73 | $this->autoloader::addPlugin($pluginId, $autoloadData); 74 | 75 | if ($providers = $plugin->config->get('providers')) { 76 | $this->providerManager->register((Array) $providers); 77 | } 78 | 79 | $services = $plugin->config->get('services'); 80 | if ($services) { 81 | foreach ($services as $key => $service) { 82 | $instance = Sci::make($service, [$pluginId, $plugin]); 83 | if (method_exists($service, 'configure')) { 84 | $instance->configure(); 85 | } 86 | $plugin->services()->add($key, $instance); 87 | } 88 | } 89 | 90 | return $this->plugins[$pluginId]; 91 | } 92 | 93 | /** 94 | * Get all plugins 95 | * 96 | * @return Plugin[] 97 | */ 98 | public function all() 99 | { 100 | return $this->plugins; 101 | } 102 | 103 | /** 104 | * Get all loaded plugins 105 | * @param string $id The plugin id 106 | * @return Plugin 107 | */ 108 | public function get($pluginId) 109 | { 110 | if (!isset($this->plugins[$pluginId])) { 111 | throw new Exception('The plugin ' . $pluginId . ' is not registered.'); 112 | } 113 | return $this->plugins[$pluginId]; 114 | } 115 | 116 | /** 117 | * Get the main plugin 118 | * 119 | * @return Plugin 120 | */ 121 | public function getMain() 122 | { 123 | if ($this->mainPluginKey) return $this->plugins[$this->mainPluginKey]; 124 | return false; 125 | } 126 | } -------------------------------------------------------------------------------- /framework/Plugin/Plugin.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Plugin 22 | { 23 | /** @var $name The plugin name */ 24 | private $name; 25 | 26 | /** @var string $file The main Plugin file */ 27 | private $file; 28 | 29 | /** @var $dir The Plugin base full path dir */ 30 | private $dir; 31 | 32 | /** @var string $mainDir Stores de plugin main full path folder */ 33 | private $mainDir; 34 | 35 | /** @var string $modulesDir Stores de plugin modules full path folder */ 36 | private $modulesDir; 37 | 38 | /** @var string $namespace The Plugin base namespace */ 39 | private $namespace; 40 | 41 | /** @var string $url The Plugin url */ 42 | private $url; 43 | 44 | /** @var Array $name The Plugin config cache array */ 45 | private $configCache = []; 46 | 47 | /** @var string $textDomain The Plugin text domain */ 48 | private $textDomain; 49 | 50 | /** @var string $domainPath The Plugin text domain dir path */ 51 | private $domainPath; 52 | 53 | /** @var Collection $services Collection to store the services */ 54 | private $services; 55 | 56 | /** @var PluginManager $pluginManager The plugin manager */ 57 | protected $pluginManager; 58 | 59 | /** @var Array $autoloaderCache If the autoloader cache is enabled */ 60 | private $autoloaderCache; 61 | 62 | /** @var Collection $config Collection to store config data */ 63 | public $config; 64 | 65 | /** @var Sci $sci Sci instance */ 66 | public $sci; 67 | 68 | public function __construct($pluginFile, PluginManager $pluginManager, Collection $services, Collection $config) 69 | { 70 | $this->sci = Sci::instance(); 71 | 72 | // Injected instances 73 | $this->pluginManager = $pluginManager; 74 | $this->services = $services; 75 | $this->config = $config; 76 | 77 | $this->file = $pluginFile; 78 | $this->dir = rtrim( dirname( $this->file ), '/' ); 79 | $this->url = plugin_dir_url( dirname( $this->file ) ); 80 | 81 | $configData = file_exists( $this->dir . '/config.php' ) ? include $this->dir . '/config.php' : []; 82 | $this->config->add($configData); 83 | $dirName = strtolower( basename( $this->dir ) ); 84 | 85 | if ($this->config->check('rebuild', true) || !file_exists( $this->dir . '/cache/config.cache.php' )) { 86 | $this->configCache = []; 87 | //These values are secondary values, used in case they are not provided in the config file 88 | $name = $this->getMetaField('Plugin Name' ); 89 | $textDomain = $this->getMetaField( 'Text Domain' ); 90 | $domainPath = $this->getMetaField( 'Domain Path' ); 91 | $this->configCache['name'] = $name ? $name : $dirName; 92 | $this->configCache['text_domain'] = $textDomain ? $textDomain : $dirName; 93 | $this->configCache['domain_path'] = $domainPath ? $domainPath : 'languages'; 94 | 95 | // Create directory if it does not exist 96 | if (!file_exists($this->dir . '/cache')) mkdir($this->dir . '/cache', 0777, true); 97 | 98 | // Update the config cache file 99 | file_put_contents ( $this->dir . '/cache/config.cache.php', "configCache , true) . ';'); 100 | }; 101 | 102 | $this->configCache = include $this->dir . '/cache/config.cache.php'; 103 | 104 | // Set the plugin name 105 | if (isset( $this->configCache['name'] ) && strlen( $this->configCache['name'] )) { 106 | $this->name = $this->configCache['name']; 107 | } else { 108 | $this->name = $dirName; 109 | } 110 | 111 | if (!$this->config->length('text_domain')) { 112 | $this->textDomain = isset($this->configCache['text_domain']) && strlen($this->configCache['text_domain']) ? $this->configCache['text_domain'] : $dirName; 113 | } 114 | 115 | $this->configureDomainPath(); 116 | 117 | $this->namespace = $this->getNamespace(); 118 | 119 | $this->configureMainDir(); 120 | 121 | $this->configureModulesDirectory(); 122 | 123 | $this->autoloaderCache = $this->config->check('autoloader/cache', true); 124 | } 125 | 126 | /** 127 | * Add a new plugin 128 | * 129 | * @param string $pluginFile The plugin file path 130 | * @return Plugin 131 | */ 132 | public static function create ($pluginFile) 133 | { 134 | $plugin = Sci::make(Plugin::class, [$pluginFile]); 135 | return $plugin; 136 | } 137 | 138 | /** 139 | * Configure the text domain path 140 | * 141 | * @return void 142 | */ 143 | private function configureDomainPath() 144 | { 145 | if ($this->config->length('domain_path')) { 146 | $this->domainPath = trim($this->config->get('domain_path'), '/'); 147 | } else if (isset($this->configCache['domain_path']) && strlen($this->configCache['domain_path'])) { 148 | $this->domainPath = trim($this->configCache['domain_path'], '/'); 149 | } else { 150 | $this->domainPath = trim('languages'); 151 | } 152 | } 153 | 154 | /** 155 | * Configure then main directory 156 | * 157 | * @return void 158 | */ 159 | private function configureMainDir() 160 | { 161 | $configMainDir = $this->config->get('dir/main'); 162 | 163 | if ($configMainDir) { 164 | $this->mainDir = trim($configMainDir, '/'); 165 | $this->mainDir = $configMainDir === '' ? $this->dir : $this->dir . '/' . $configMainDir; 166 | return; 167 | } 168 | 169 | $this->mainDir = file_exists($this->dir . '/app') ? $this->dir . '/app' : $this->dir; 170 | } 171 | 172 | 173 | /** 174 | * Configure the modules directory 175 | * 176 | * @return void 177 | */ 178 | private function configureModulesDirectory() 179 | { 180 | $configModulesDir = $this->config->get('dir/modules'); 181 | 182 | if ($configModulesDir) { 183 | $this->modulesDir = trim($configModulesDir, '/'); 184 | if ($configModulesDir == '') { 185 | $this->modulesDir = file_exists($this->dir . '/modules') ? $this->dir . '/modules' : false ; 186 | } else { 187 | $this->modulesDir = $this->dir .'/'. $configModulesDir; 188 | } 189 | return; 190 | } 191 | 192 | $this->modulesDir = file_exists($this->dir . '/modules') ? $this->dir . '/modules' : false; 193 | } 194 | 195 | /** 196 | * Add the plugin to the plugin manager 197 | * 198 | * @return Plugin 199 | */ 200 | public function register ($pluginId = false, $addon = false) { 201 | $this->pluginManager->register($this, $pluginId, $addon); 202 | return $this; 203 | } 204 | 205 | /** 206 | * Get all the services 207 | * 208 | * @return array Array with services 209 | */ 210 | public function services () 211 | { 212 | return $this->services; 213 | } 214 | 215 | /** 216 | * Get a single service 217 | * 218 | * @return mixed The requested service 219 | */ 220 | public function service ($serviceId) 221 | { 222 | return $this->services->get($serviceId); 223 | } 224 | 225 | public function getName () 226 | { 227 | if ($this) 228 | return $this->config['name']; 229 | } 230 | 231 | /** 232 | * Get the plugin configuration 233 | * 234 | * @param string $setting The setting to get 235 | * @return mixed The setting 236 | */ 237 | public function config ($setting = null) 238 | { 239 | if ($setting) return $this->config->get($setting); 240 | return $this->config; 241 | } 242 | 243 | /** 244 | * Get the namespace form the main plugin file 245 | * 246 | * @return string The plugin root namespace 247 | */ 248 | public function getNamespace () 249 | { 250 | if ($this->namespace) return $this->namespace; 251 | 252 | if ($this->config->length('namespace')) return $this->config->get('namespace'); 253 | 254 | if (isset( $this->configCache['namespace'] ) && strlen( $this->configCache['namespace'] )) { 255 | return $this->configCache['namespace']; 256 | } 257 | 258 | $file_content = file_get_contents($this->file); 259 | if (preg_match('#^\s*namespace\s+(.+?);$#sm', $file_content, $m)) $namespace = $m[1]; 260 | else $namespace = strtolower( basename( $this->dir ) ); 261 | 262 | $this->configCache['namespace'] = $namespace; 263 | $fileContents = "configCache, true) . ';'; 264 | 265 | // Create directory if it does not exist 266 | if (!file_exists($this->dir . '/cache')) mkdir($this->dir . '/cache', 0777, true); 267 | 268 | file_put_contents ( $this->dir . '/cache/config.cache.php', $fileContents ); 269 | 270 | return $namespace; 271 | } 272 | 273 | /** 274 | * Get the namespace form the main plugin file 275 | * 276 | * @return string The plugin main namespace 277 | */ 278 | public function getMainNamespace () 279 | { 280 | return $this->mainNamespace; 281 | } 282 | 283 | /** 284 | * Get a WordPress header field form the main plugin file 285 | * 286 | * @param string $field The header field 287 | * @return string The header field value 288 | */ 289 | public function getMetaField($field) 290 | { 291 | $to_return = ""; 292 | $handle = fopen($this->file, "r"); 293 | if ($handle) { 294 | while (($line = fgets($handle)) !== false) { 295 | if (preg_match( '/^[\* ]*?'.$field.'.*?:(.*?)$/', trim($line), $matches ) && count($matches) > 1) { 296 | $to_return = $matches[1]; 297 | } 298 | } 299 | fclose($handle); 300 | } 301 | return trim($to_return); 302 | } 303 | 304 | /** 305 | * Get the Plugin file 306 | * 307 | * @return string The Plugin main file 308 | */ 309 | public function getFile() 310 | { 311 | return $this->file; 312 | } 313 | 314 | /** 315 | * Get the Plugin dir 316 | * 317 | * @return string The Plugin base dir 318 | */ 319 | public function getDir() 320 | { 321 | return $this->dir; 322 | } 323 | 324 | /** 325 | * Get the Moduledir 326 | * 327 | * @return string The Plugin modules folder 328 | */ 329 | public function getModulesDir() 330 | { 331 | return $this->modulesDir; 332 | } 333 | 334 | /** 335 | * Get the Maindir 336 | * 337 | * @return string The Plugin main folder 338 | */ 339 | public function getMainDir() 340 | { 341 | return $this->mainDir; 342 | } 343 | 344 | /** 345 | * Get the Maindir 346 | * 347 | * @return string The Plugin main folder 348 | */ 349 | public function getAutoloaderCacheEnabled() 350 | { 351 | return $this->autoloaderCache; 352 | } 353 | } -------------------------------------------------------------------------------- /framework/Plugin/Services/ActivationService.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class ActivationService 19 | { 20 | /** @var string $plugin The plugin this service belongs to. */ 21 | private $plugin; 22 | 23 | /** @var string $key The plugin key */ 24 | private $key; 25 | 26 | /** @var string $checks Stores a list of the activation checks */ 27 | public $checks = array(); 28 | 29 | /** @var string $actions Stores a list of the activation actions */ 30 | private $actions = array(); 31 | 32 | /** 33 | * Class constructor 34 | */ 35 | public function __construct($key, Plugin $plugin) 36 | { 37 | $this->key = $key; 38 | $this->plugin = $plugin; 39 | } 40 | 41 | /** 42 | * Initializes the class 43 | * 44 | * @param Plugin|string $plugin The plugin/id 45 | * @return self 46 | */ 47 | public function configure() 48 | { 49 | register_activation_hook($this->plugin->getFile(), array($this,'run')); 50 | return $this; 51 | } 52 | 53 | /** 54 | * Add a check to the plugin activation 55 | * 56 | * @param string $name The condition name 57 | * @param string $callback The callback function 58 | * @param array $params The function parameters 59 | * @return self 60 | */ 61 | public function addCheck($name, $callback, $params = false) 62 | { 63 | $check = array('name' => $name, 'callback' => $callback); 64 | if ($params) { 65 | $check['params'] = (array) $params; 66 | } 67 | $this->checks[] = $check; 68 | return $this; 69 | } 70 | 71 | /** 72 | * Ads an action to execute on the plugin activation 73 | * 74 | * @param string $name The action name 75 | * @param mixed $name The action function 76 | * @param array $params The function parameters 77 | * @return self 78 | */ 79 | public function addAction($name, $callback, $params = false) 80 | { 81 | $action = array('name' => $name, 'callback' => $callback); 82 | if ($params) { 83 | $action['params'] = (array) $params; 84 | } 85 | $this->actions[] = $action; 86 | return $this; 87 | } 88 | 89 | /** 90 | * Plugin activation 91 | * 92 | * @return void 93 | */ 94 | public function run() 95 | { 96 | global $wp_version; 97 | 98 | $config = $this->plugin->config()->get('activation'); 99 | $requirements = true; 100 | $message = ""; 101 | 102 | if (isset($config['php'])) { 103 | if (!is_array($config['php']) && $config['php']) { 104 | if ( version_compare( PHP_VERSION, $config['php'], '<' ) ) { 105 | $requirements = false; 106 | $message .= '

'.sprintf('The %1$s plugin requires PHP version %2$s or greater.', '' . $this->plugin->getName() . '', $config['php']).'

'; 107 | } 108 | } else if (isset($config['php']['enabled']) && $config['php']['enabled']) { 109 | if ( version_compare( PHP_VERSION, $config['php']['version'], '<' ) ) { 110 | $requirements = false; 111 | if (isset($config['php']['message'])) { 112 | $error = $config['php']['message']; 113 | } else { 114 | $error = 'The %1$s plugin requires the PHP version %2$s or greater. Please make sure it is installed and try again.'; 115 | } 116 | $message .= '

'.sprintf($error, '' . $this->plugin->getName() . '', $config['php']['version']).'

'; 117 | } 118 | } 119 | } 120 | 121 | if (isset($config['wordpress'])) { 122 | if (!is_array($config['wordpress']) && $config['wordpress']) { 123 | if (version_compare($wp_version, $config['wordpress'], '<' )) { 124 | $requirements = false; 125 | $message .= '

'.sprintf('The %1$s plugin requires WordPress version %2$s or greater.', '' . $this->plugin->getName() . '', $config['wordpress']).'

'; 126 | } 127 | } else if (isset($config['wordpress']['enabled']) && $config['wordpress']['enabled']) { 128 | if (version_compare($wp_version, $config['wordpress']['version'], '<' )) { 129 | $requirements = false; 130 | if (isset($config['wordpress']['message'])) { 131 | $error = $config['wordpress']['message']; 132 | } else { 133 | $error = 'The %1$s plugin requires the plugin %2$s. Please make sure it is installed and try again.'; 134 | } 135 | $message .= '

'.sprintf($error, '' . $this->plugin->getName() .'', $config['wordpress']['version']).'

'; 136 | } 137 | } 138 | } 139 | 140 | if (isset($config['plugins'])) { 141 | 142 | if (!is_array($config['plugins'])) { 143 | $config['plugins'] = [$config['plugins']]; 144 | } 145 | 146 | if (is_array($config['plugins']) && count($config['plugins'])) { 147 | 148 | $active_plugins = get_option('active_plugins'); 149 | foreach($active_plugins as $key => $plugin) { 150 | $plugin_arr = explode('/', trim($plugin,'/')); 151 | $active_plugins[$key] = is_array($plugin_arr) ? $plugin_arr[0] : trim($plugin); 152 | } 153 | 154 | foreach ((array) $config['plugins'] as $key => $requiredPlugin) { 155 | 156 | if (!is_array($requiredPlugin)) { 157 | if (!in_array($requiredPlugin, $active_plugins)) { 158 | $requirements = false; 159 | $error = 'The %1$s plugin requires the plugin %2$s. Please make sure it is installed and enabled and try again.'; 160 | $message .= '

'.sprintf($error, ''. $this->plugin->getName() .'', ''.$requiredPlugin.'').'

'; 161 | } 162 | } else { 163 | if (!in_array($key, $active_plugins)) { 164 | $requirements = false; 165 | if (isset($requiredPlugin['message'])) { 166 | $error = $requiredPlugin['message']; 167 | } else { 168 | $error = 'The %1$s plugin requires the plugin %2$s. Please make sure it is installed and enabled and try again.'; 169 | } 170 | $name = isset($requiredPlugin['name']) ? $requiredPlugin['name'] : $key; 171 | $message .= '

'.sprintf($error, '' . $this->plugin->getName() . '', ''.$name.'').'

'; 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | foreach ($this->checks as $check) { 179 | $callback = $check['callback']; 180 | if (is_string($callback) && strpos($callback, ".") !== false) { 181 | // File inclusion 182 | $result = include ($callback); 183 | } else { 184 | if (is_array($callback)) { 185 | // Instance 186 | if (is_object($callback[0]) && is_string($callback[1])) { 187 | if ( isset($check['params']) ) { 188 | // Instance with parameters 189 | $result = call_user_func_array($callback, $check['params']); 190 | } else { 191 | // Instance without parameters 192 | $result = call_user_func($callback); 193 | } 194 | } 195 | else if (is_string($callback[0]) && class_exists($callback[0]) && is_string($callback[1])) { 196 | $instance = $this->sci::make($callback[0]); 197 | if ( isset($check['params']) ) { 198 | // Instance with parameters 199 | $result = call_user_func_array([$instance, $callback[1]], $check['params']); 200 | } else { 201 | // Instance without parameters 202 | $result = call_user_func([$instance, $callback[1]]); 203 | } 204 | } 205 | else { 206 | trigger_error("Invalid instance or instance function for the activation check" . $check['name']. ".", E_USER_ERROR); 207 | } 208 | } else { 209 | // Functions and static methods 210 | if ( isset($check['params']) ) { 211 | // Instance with parameters 212 | $result = call_user_func_array($callback, $check['params']); 213 | } else { 214 | // Instance without parameters 215 | $result = call_user_func($callback); 216 | } 217 | } 218 | } 219 | if ( $result !== true ) { 220 | $requirements = false; 221 | $message .= '

'.$result.'

'; 222 | } 223 | } 224 | 225 | if (!$requirements) { 226 | deactivate_plugins( plugin_basename( __FILE__ ) ) ; 227 | wp_die($message,'Plugin Activation Error', array( 'response'=>200, 'back_link'=>TRUE ) ); 228 | } 229 | 230 | foreach ($this->actions as $action) { 231 | $callback = $action['callback']; 232 | // File inclusion 233 | if (is_string($callback) && strpos($callback, ".") !== false) { 234 | include ($callback); 235 | } else { 236 | // Instance 237 | if (is_array($callback)) { 238 | if (is_object($callback[0]) && is_string($callback[1])) { 239 | if ( isset($action['params']) ) { 240 | // Instance with parameters 241 | call_user_func_array($callback, $action['params']); 242 | } else { 243 | // Instance without parameters 244 | call_user_func($callback); 245 | } 246 | } 247 | else if (is_string($callback[0]) && class_exists($callback[0]) && is_string($callback[1])) { 248 | $instance = $this->sci::make($callback[0]); 249 | if ( isset($check['params']) ) { 250 | // Instance with parameters 251 | call_user_func_array([$instance, $callback[1]], $check['params']); 252 | } else { 253 | // Instance without parameters 254 | call_user_func([$instance, $callback[1]]); 255 | } 256 | } 257 | else { 258 | trigger_error("Invalid instance or instance function for the activation action" . $action['name']. ".", E_USER_ERROR); 259 | } 260 | } else { 261 | // Functions and static methods 262 | if ( isset($action['params']) ) { 263 | // Function with parameters 264 | $result = call_user_func_array($callback, $action['params']); 265 | } else { 266 | // Function without parameters 267 | $result = call_user_func($callback); 268 | } 269 | } 270 | } 271 | } 272 | flush_rewrite_rules(); 273 | } 274 | } -------------------------------------------------------------------------------- /framework/Plugin/Services/DeactivationService.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class DeactivationService 19 | { 20 | /** @var string $plugin The plugin this service belongs to. */ 21 | private $plugin; 22 | 23 | /** @var string $key The plugin key */ 24 | private $key; 25 | 26 | /** @var string $actions Stores a list of the deactivation actions */ 27 | private $actions = array(); 28 | 29 | /** 30 | * Class constructor 31 | */ 32 | public function __construct($key, Plugin $plugin) 33 | { 34 | $this->key = $key; 35 | $this->plugin = $plugin; 36 | } 37 | 38 | /** 39 | * Initializes the class 40 | * 41 | * @param Plugin|string $plugin The plugin/id 42 | * @return self 43 | */ 44 | public function configure() 45 | { 46 | register_deactivation_hook($this->plugin->getFile(), array($this,'run')); 47 | return $this; 48 | } 49 | 50 | /** 51 | * Ads an action to execute on the plugin deactivation 52 | * 53 | * @param string $name The action name 54 | * @param mixed $name The action function 55 | * @param array $params The function parameters 56 | * @return self 57 | */ 58 | public function addAction($name, $callback, $params = false) 59 | { 60 | $action = array('name' => $name, 'callback' => $callback); 61 | 62 | if ($params) $action['params'] = (array) $params; 63 | $this->actions[] = $action; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * Plugin deactivation 70 | * 71 | * @return void 72 | */ 73 | public function run() 74 | { 75 | if (!current_user_can( 'activate_plugins' )) return; 76 | 77 | foreach ($this->actions as $action) { 78 | 79 | $callback = $action['callback']; 80 | 81 | if (is_string($callback) && strpos($callback, ".") !== false) { 82 | // File inclusion 83 | include ($callback); 84 | } else { 85 | // Instance 86 | if (is_array($callback)) { 87 | if (is_object($callback[0]) && is_string($callback[1])) { 88 | if ( isset($action['params']) ) { 89 | // Instance with parameters 90 | call_user_func_array($callback, $action['params']); 91 | } else { 92 | // Instance without parameters 93 | call_user_func($callback); 94 | } 95 | } 96 | else if (is_string($callback[0]) && class_exists($callback[0]) && is_string($callback[1])) { 97 | $instance = $this->sci::make($callback[0]); 98 | if ( isset($check['params']) ) { 99 | // Instance with parameters 100 | call_user_func_array([$instance, $callback[1]], $check['params']); 101 | } else { 102 | // Instance without parameters 103 | call_user_func([$instance, $callback[1]]); 104 | } 105 | } 106 | else { 107 | trigger_error("Invalid instance or instance function for the activation action" . $action['name']. ".", E_USER_ERROR); 108 | } 109 | } else { 110 | // Functions and static methods 111 | if ( isset($action['params']) ) { 112 | // Function with parameters 113 | $result = call_user_func_array($callback, $action['params']); 114 | } else { 115 | // Function without parameters 116 | $result = call_user_func($callback); 117 | } 118 | } 119 | } 120 | } 121 | flush_rewrite_rules(); 122 | } 123 | } -------------------------------------------------------------------------------- /framework/Plugin/Services/OptionService.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class OptionService 19 | { 20 | /** @var Plugin $plugin The plugin this service belongs to */ 21 | private $plugin; 22 | 23 | /** @var string $key The plugin key */ 24 | private $key; 25 | 26 | /** 27 | * Class constructor 28 | */ 29 | public function __construct($key, Plugin $plugin) 30 | { 31 | $this->key = $key; 32 | $this->plugin = $plugin; 33 | } 34 | 35 | /** 36 | * Returns an option in the array of options stored as a single WP option 37 | * 38 | * @param array|string $option 39 | * @param boolean $default 40 | * @return mixed 41 | */ 42 | public function get( $option, $default = false ) 43 | { 44 | if ( is_array($option) && count($option) > 1 ) { 45 | $name = $option[0]; 46 | $fieldContent = get_option( $this->key . '_' . $option[1] ); 47 | } else { 48 | $name = $option; 49 | $fieldContent = get_option( $this->key ); 50 | } 51 | if ( false === $fieldContent ) return $default; 52 | return isset($fieldContent[$name]) ? $fieldContent[$name] : $default; 53 | } 54 | 55 | /** 56 | * Updates an element in the array of options used for this plugin and 57 | * stored as a WP unique option The option name is the Plugin ID 58 | * 59 | * @param array|string $option 60 | * @param mixed $value 61 | * @return mixed 62 | */ 63 | public function set( $option, $value ) 64 | { 65 | if ( is_array($option) && count($option) > 1 ) { 66 | $name = $option[0]; 67 | $option = $this->key . '_' . $option[1]; 68 | 69 | } else { 70 | $name = $option; 71 | $option = $this->key; 72 | } 73 | $option_val = get_option( $option ); 74 | $option_val = ( false === $option_val ) ? array() : (array) $option_val; 75 | $option_val = array_merge( $option_val, array( $name => $value ) ); 76 | return update_option( $option, $option_val ); 77 | } 78 | 79 | /** 80 | * Deletes an option in the array of options stored as a single WP option 81 | * 82 | * @param array $option 83 | * @return boolean 84 | */ 85 | public function remove($option) 86 | { 87 | if ( is_array($option) && count($option) > 1 ) { 88 | $option = $option[0]; 89 | $fieldName = $this->key . '_' . $option[1]; 90 | } else { 91 | $fieldName = $this->key; 92 | } 93 | 94 | $fieldContents = get_option($fieldName); 95 | if (false === $fieldContents) return false; 96 | 97 | if (isset($fieldContents[$option])) { 98 | unset($fieldContents[$option]); 99 | 100 | print_r($fieldContents); 101 | update_option( $fieldName, $fieldContents ); 102 | return true; 103 | } 104 | return false; 105 | } 106 | 107 | /** 108 | * Returns the array of options stored as a WP option 109 | * 110 | * @param string $name 111 | * @return array 112 | */ 113 | public function getSet( $name = null ) 114 | { 115 | if ( is_numeric($name) || (is_string($name) && strlen($name)) ) { 116 | return get_option( $this->key . '_' . $name ); 117 | } else if( $name === null || $name == true ) { 118 | return get_option( $this->key ); 119 | } 120 | return false; 121 | } 122 | 123 | /** 124 | * Updates an the array of options stored as a WP option 125 | * 126 | * @param string $name 127 | * @param array $data 128 | * @return mixed 129 | */ 130 | public function storeSet( $name = null, $data ) 131 | { 132 | if ( is_numeric($name) || (is_string($name) && strlen($name)) ) { 133 | return update_option( $this->key . '_' . $name, $data ); 134 | } 135 | else if( $name === null || $name == true ) { 136 | return update_option( $this->key, $data ); 137 | } 138 | return false; 139 | } 140 | 141 | /** 142 | * Deletes an the array of options stored as a WP option 143 | * 144 | * @param string $name 145 | * @return boolean 146 | */ 147 | public function removeSet( $name = null ) 148 | { 149 | if ( is_numeric($name) || (is_string($name) && strlen($name)) ) { 150 | return delete_option( $this->key . '_' . $name ); 151 | } 152 | else if( $name === null || $name == true ) { 153 | return delete_option( $this->key ); 154 | } 155 | return false; 156 | } 157 | } -------------------------------------------------------------------------------- /framework/Resources/js/admin_scripts.js: -------------------------------------------------------------------------------- 1 | (function( $ ) { 2 | jQuery(document).ready( function() { 3 | 'use strict'; 4 | var cs__image_frame, image_data; 5 | $(function() { 6 | if ( undefined !== cs__image_frame ) { 7 | cs__image_frame.open(); return; 8 | } 9 | }); 10 | }); 11 | 12 | jQuery(document).on('click', '.Sci_img_select', function(e) { 13 | var clickimagen=event.target; 14 | cs__image_frame = wp.media.frames.cs__image_frame = wp.media({ 15 | title: $(clickimagen).attr("data-title"), 16 | multiple: false 17 | }); 18 | cs__image_frame.on( 'select', function() { 19 | image_data = cs__image_frame.state().get( 'selection' ).first().toJSON(); 20 | if(image_data['id'] && image_data['url']){ 21 | $(clickimagen).parent('div').find('.Sci_img_id').val(image_data['id']); 22 | //console.log($(clickimagen).parent('div').find('.cs__imgid').val()); 23 | $(clickimagen).parent('div').find('.Sci_img_img').html(""); 24 | $(clickimagen).parent('div').find('.Sci_img_del').css('display', 'inline-block'); 25 | } 26 | }); 27 | cs__image_frame.open(); 28 | }); 29 | 30 | jQuery(document).on('click', '.Sci_img_del', function(e) { 31 | $(this).parent('div').find('.Sci_img_img').empty(); 32 | $(this).parent('div').find('input[type=text]').val(''); 33 | $(this).css('display', 'none'); 34 | }); 35 | })( jQuery ); 36 | 37 | jQuery( document ).ready( function( $ ) { 38 | tinymce.init( { 39 | selector: '.Sci_mce', 40 | mode : "specific_textareas", 41 | editor_selector : ".Sci_mce", 42 | elements : 'pre-details', 43 | height : "320px", 44 | theme: "modern", 45 | skin: "lightgray", 46 | menubar : false, 47 | statusbar : false, 48 | plugins : "paste", 49 | paste_auto_cleanup_on_paste : true, 50 | paste_postprocess : function( pl, o ) { 51 | o.node.innerHTML = o.node.innerHTML.replace( / +/ig, " " ); 52 | } 53 | } ); 54 | } ); 55 | 56 | jQuery(document).ready(function($){ 57 | jQuery('.Sci_color_picker').wpColorPicker(); 58 | }); 59 | -------------------------------------------------------------------------------- /framework/Router/Controller.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | abstract class Controller 17 | { 18 | } -------------------------------------------------------------------------------- /framework/Router/Managers/RestManager.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class RestManager extends Manager 20 | { 21 | /** @var array $routes Stores a list of the registered routes */ 22 | private $routes = array(); 23 | 24 | /** @var boolean $isActionInit If the WP actions have been added or not. */ 25 | private $isActionInit = false; 26 | 27 | /** 28 | * Class constructor 29 | * 30 | * @return RestManager 31 | */ 32 | protected function __construct() 33 | { 34 | parent::__construct(); 35 | } 36 | 37 | /** 38 | * Register a new route into the route manager 39 | * 40 | * @param Rest $route The route instance 41 | * @param string $name The route name 42 | * @return RouteManager 43 | */ 44 | public function register($route, $name = false) 45 | { 46 | if (!$name) $name = $this->getRoutesNextArrKey(); 47 | 48 | $this->routes[$name] = $route; 49 | 50 | if (!$this->isActionInit) { 51 | add_action( 'rest_api_init', [$this,'addRestRoutes'], 1); 52 | $this->isActionInit = true; 53 | } 54 | 55 | return $this; 56 | } 57 | 58 | /** 59 | * Get next array numeric key 60 | * 61 | * @return integer 62 | */ 63 | public function getRoutesNextArrKey() 64 | { 65 | if (count($this->routes)) { 66 | $numericKeys = array_filter(array_keys($this->routes), 'is_int'); 67 | if (count($numericKeys)) { 68 | return max($numericKeys) + 1; 69 | } 70 | } 71 | return 1; 72 | } 73 | 74 | /** 75 | * Add routes to WordPress 76 | * 77 | * @return RestManager 78 | */ 79 | public function addRestRoutes() 80 | { 81 | foreach($this->routes as $key => $route) { 82 | register_rest_route($route->getNamespace(), $route->regex, array( 83 | 'methods' => $route->getMethods(), 84 | 'callback' => [$route, 'loadAction'], 85 | 'args' => $route->getArgs(), 86 | )); 87 | } 88 | 89 | return $this; 90 | } 91 | } -------------------------------------------------------------------------------- /framework/Router/Managers/RouteManager.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class RouteManager extends Manager 20 | { 21 | /** @var array $routes Stores a list of the registered routes */ 22 | private $routes = array(); 23 | 24 | /** @var boolean $filtersAadded If the WP filters have been added or not. */ 25 | private $filtersAadded = false; 26 | 27 | /** @var array $params Parameters to pass to the action function or method */ 28 | private $params = array(); 29 | 30 | /** @var array $cache Stores de cached rewrite rules */ 31 | public $cache = array(); 32 | 33 | /** @var string $dirCache Stores de cache file fir path */ 34 | private $dirCache; 35 | 36 | /** @var string $fileCache Stores de cache file path */ 37 | private $fileCache; 38 | 39 | /** @var boolean $rewriteRulesFlushed Stores if the rules have been flushed */ 40 | private $rewriteRulesFlushed = false; 41 | 42 | /** 43 | * Class constructor 44 | */ 45 | protected function __construct() 46 | { 47 | parent::__construct(); 48 | $this->dirCache = dirname(dirname(dirname(substr(plugin_dir_path( __FILE__ ), 0, -1)))) . '/cache/'; 49 | $this->fileCache = $this->dirCache . 'route.cache.php'; 50 | $this->cache = is_file($this->fileCache) ? (array) include $this->fileCache : []; 51 | } 52 | 53 | /** 54 | * Saves the route cache 55 | * 56 | * @return bool 57 | */ 58 | public function saveCache() 59 | { 60 | if (!file_exists($this->dirCache)) mkdir($this->dirCache); 61 | file_put_contents($this->fileCache, 'cache, true) . ';') 62 | or die('Cannot write the file: '.$this->fileCache); 63 | } 64 | 65 | /** 66 | * Register a new route into the route manager 67 | * 68 | * @param Route $route The route instance 69 | * @param string $name The route name 70 | * @return RouteManager 71 | */ 72 | public function register($route, $name = false) 73 | { 74 | if (!$name) $name = $this->getRoutesNextArrKey(); 75 | 76 | $this->routes[$name] = $route; 77 | 78 | if (!$this->filtersAadded) { 79 | add_action( 'init', array($this,'addRewriteRulesAction'), 1); 80 | add_filter( 'query_vars', function( $query_vars ) { 81 | $query_vars[] = 'sci'; 82 | return $query_vars; 83 | }); 84 | add_action( 'template_include', array($this,'loadRouteAction'), 10); 85 | $this->filtersAadded = true; 86 | } 87 | 88 | if (!isset($this->cache[$route->regex]) || $this->cache[$route->regex] !== $name) { 89 | 90 | if (!$this->rewriteRulesFlushed) { 91 | add_action( 'init', array($this,'flushRewriteRules'), 1); 92 | $this->rewriteRulesFlushed = true; 93 | } 94 | 95 | } 96 | return $this; 97 | } 98 | 99 | /** 100 | * Get next array numeric key 101 | * 102 | * @return integer 103 | */ 104 | public function getRoutesNextArrKey() 105 | { 106 | if (count($this->routes)) { 107 | $numericKeys = array_filter(array_keys($this->routes), 'is_int'); 108 | if (count($numericKeys)) { 109 | return max($numericKeys) + 1; 110 | } 111 | } 112 | return 1; 113 | } 114 | 115 | /** 116 | * Flush rewrite rules 117 | */ 118 | public function flushRewriteRules() { 119 | $this->cache = []; 120 | foreach($this->routes as $key => $route) { 121 | $this->cache[$route->regex] = $key; 122 | } 123 | $this->saveCache(); 124 | flush_rewrite_rules(true); 125 | } 126 | 127 | /** 128 | * Generate rewrite rules when fushed 129 | * 130 | * @return RouteManager 131 | */ 132 | public function addRewriteRulesAction() 133 | { 134 | add_filter( 'generate_rewrite_rules', function ( $wp_rewrite ) { 135 | $routes = array(); 136 | 137 | foreach($this->routes as $key => $route) { 138 | $routes[$route->regex] = 'index.php?sci='.$key; 139 | } 140 | 141 | $wp_rewrite->rules = array_merge( 142 | $routes, 143 | $wp_rewrite->rules 144 | ); 145 | }); 146 | 147 | return $this; 148 | } 149 | 150 | /** 151 | * Return if the current request is async 152 | * 153 | * @return boolean 154 | */ 155 | public function isAsync() 156 | { 157 | if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { 158 | return true; 159 | } 160 | return false; 161 | } 162 | 163 | 164 | /** 165 | * Load the action matching the requested route 166 | * 167 | * @param string $template The WordPress template to load 168 | * @return mixed 169 | */ 170 | public function loadRouteAction($template) 171 | { 172 | $sciVar = get_query_var( 'sci'); 173 | 174 | if (!$sciVar) return $template; 175 | 176 | if (!isset($this->routes[$sciVar])) return $template; 177 | 178 | $route = $this->routes[$sciVar]; 179 | 180 | if (!in_array($_SERVER['REQUEST_METHOD'], $route->getMethods())) return $template; 181 | 182 | if ($route->getAsync() !== $this->isAsync()) return $template; 183 | 184 | $route->loadAction(); 185 | } 186 | } -------------------------------------------------------------------------------- /framework/Router/Request.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class Request 19 | { 20 | /** @var array $params The array with route parameters */ 21 | private static $params = []; 22 | 23 | /** 24 | * Load error page 25 | */ 26 | public static function error($errorMessage = '404: Not Found' ) 27 | { 28 | global $wp_query; 29 | 30 | $wp_query->set_404(); 31 | 32 | add_action( 'wp_title', function () { 33 | return '404: Not Found'; 34 | }, 9999 ); 35 | 36 | status_header( 404 ); 37 | nocache_headers(); 38 | 39 | require get_404_template(); 40 | 41 | exit; 42 | } 43 | 44 | /** 45 | * Set parameters 46 | * 47 | * @param array $params Array with parameters 48 | * @return Request 49 | */ 50 | public static function setParams($params) 51 | { 52 | self::$params = $params; 53 | return self::class; 54 | } 55 | 56 | /** 57 | * Get parameters 58 | * 59 | * @return array 60 | */ 61 | public static function params() 62 | { 63 | return self::$params; 64 | } 65 | 66 | /** 67 | * Get parameter 68 | * 69 | * @var string $param The param name 70 | * @var mixed $default The default value to return of the param is not found 71 | * @return mixed 72 | */ 73 | public static function param($param, $default = null) 74 | { 75 | if (isset(self::$params[$param])) { 76 | return $param; 77 | } else { 78 | return $default; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /framework/Router/Rest.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Rest 22 | { 23 | use \Sci\Traits\Sci; 24 | 25 | /** @var WP_REST_Request $request WordPress request */ 26 | private static $request; 27 | 28 | /** @var string $namespace */ 29 | public $namespace; 30 | 31 | /** @var string $route */ 32 | private $route; 33 | 34 | /** @var mixed $action */ 35 | private $action; 36 | 37 | /** @var string $regex */ 38 | public $regex; 39 | 40 | /** @var array $params */ 41 | private $params = array(); 42 | 43 | /** @var array $validators */ 44 | private $validators = array(); 45 | 46 | /** @var array $methods Request methods */ 47 | private $methods; 48 | 49 | /** @var array $args Route args */ 50 | private $args = []; 51 | 52 | /** 53 | * Class constructor 54 | * 55 | * @var string $namespace The Api namespace 56 | * @var string|array[string] $methods The request method 57 | * @param string $route The rest route expression 58 | * @param mixed $action The rest action, file or function 59 | * @var RestManager $restManager Rest manager instance 60 | */ 61 | public function __construct($namespace, $methods, $route, $action, RestManager $restManager) 62 | { 63 | $this->restManager = $restManager; 64 | 65 | $this->namespace = $namespace; 66 | 67 | $this->methods = (array) $methods; 68 | foreach($this->methods as $key => $value) { 69 | $this->methods[$key] = strtoupper($value); 70 | } 71 | 72 | // Remove trailing slashes 73 | $route = trim($route, '/'); 74 | 75 | // Get parameters 76 | preg_match_all('/\{(.*?)(\?)?(\|((.*?)({.*})?)?)?\}/', rtrim($route, '/'), $matches); 77 | 78 | if (is_array($matches) && isset($matches[1])) { 79 | foreach ((array) $matches[1] as $key => $match) { 80 | $this->params[$match] = isset($matches[4][$key]) && $matches[4][$key] ? '(?P<'.$match.'>'.$matches[4][$key].')' : '(?P<'.$match.'>[A-Za-z0-9\-\_]+)'; 81 | if($matches[2][$key] == '?') { 82 | $this->params[$match] = '?' . $this->params[$match] . '?'; 83 | } 84 | } 85 | } 86 | 87 | $this->route = preg_replace('/\{(.*?)(\?)?(\|((.*?)({.*})?)?)?\}/', '{$1}', $route); 88 | $this->generateRegex(); 89 | 90 | $this->action = $action; 91 | return $this; 92 | } 93 | 94 | /** 95 | * Return the request object 96 | * 97 | * @return WP_REST_Request 98 | */ 99 | public static function request() { 100 | return self::$request; 101 | } 102 | 103 | /** 104 | * Add a route 105 | * 106 | * @param string $namespace The Api namespace 107 | * @param string $method The route request method 108 | * @param string $route The rest route expression 109 | * @param mixed $action The rest action, file or function 110 | * @return Rest 111 | */ 112 | public static function create($namespace, $method, $route, $action) 113 | { 114 | return Sci::make(self::class, [$namespace, $method, $route, $action]); 115 | } 116 | 117 | /** 118 | * Create and register a route 119 | * 120 | * @param string $namespace The Api namespace 121 | * @param string $method The route request method 122 | * @param string $route The rest route expression 123 | * @param mixed $action The rest action, file or function 124 | * @return Rest 125 | */ 126 | public static function commit($namespace, $method, $route, $action) 127 | { 128 | $route = self::create($namespace, $method, $route, $action); 129 | $route->register(); 130 | return $route; 131 | } 132 | 133 | /** 134 | * Add a new route answering to the get method 135 | * 136 | * @param string $namespace The Api namespace 137 | * @param string $route The rest route expression 138 | * @param mixed $action The rest action, file or function 139 | * @return Rest 140 | */ 141 | public static function get($namespace, $route, $action) 142 | { 143 | $route = self::create($namespace, 'get', $route, $action); 144 | return $route; 145 | } 146 | 147 | /** 148 | * Add a new route answering to the post method 149 | * 150 | * @param string $namespace The Api namespace 151 | * @param string $route The rest route expression 152 | * @param mixed $action The rest action, file or function 153 | * @return Rest 154 | */ 155 | public static function post($namespace, $route, $action) 156 | { 157 | $route = self::create($namespace, 'post', $route, $action); 158 | return $route; 159 | } 160 | 161 | /** 162 | * Add a new route answering to the put method 163 | * 164 | * @param string $namespace The Api namespace 165 | * @param string $route The rest route expression 166 | * @param mixed $action The rest action, file or function 167 | * @return Rest 168 | */ 169 | public static function put($route, $action) 170 | { 171 | $route = self::create($namespace, 'put', $route, $action); 172 | return $route; 173 | } 174 | 175 | /** 176 | * Add a new route answering to the patch method 177 | * 178 | * @param string $namespace The Api namespace 179 | * @param string $route The rest route expression 180 | * @param mixed $action The rest action, file or function 181 | * @return Rest 182 | */ 183 | public static function patch($namespace, $route, $action) 184 | { 185 | $route = self::create($namespace, 'patch', $route, $action); 186 | return $route; 187 | } 188 | 189 | /** 190 | * Add a new route answering to the delete method 191 | * 192 | * @param string $namespace The Api namespace 193 | * @param string $route The rest route expression 194 | * @param mixed $action The rest action, file or function 195 | * @return Rest 196 | */ 197 | public static function delete($namespace, $route, $action) 198 | { 199 | $route = self::create($namespace, 'delete', $route, $action); 200 | return $route; 201 | } 202 | 203 | /** 204 | * Add a new route answering to the options method 205 | * 206 | * @param string $namespace The Api namespace 207 | * @param string $route The rest route expression 208 | * @param mixed $action The rest action, file or function 209 | * @return Rest 210 | */ 211 | public static function options($namespace, $route, $action) 212 | { 213 | $route = self::create($namespace, 'options', $route, $action); 214 | return $route; 215 | } 216 | 217 | /** 218 | * Add a new route answering all methods 219 | * 220 | * @param string $namespace The Api namespace 221 | * @param string $route The rest route expression 222 | * @param mixed $action The rest action, file or function 223 | * @return Rest 224 | */ 225 | public static function any($namespace, $route, $action) 226 | { 227 | $route = self::create($namespace, ['get', 'post', 'put', 'patch', 'delete', 'options'], $route, $action); 228 | return $route; 229 | } 230 | 231 | /** 232 | * Add a new route answering the selected methods 233 | * 234 | * @param string $namespace The Api namespace 235 | * @param string $route The rest route expression 236 | * @param mixed $action The rest action, file or function 237 | * @return Rest 238 | */ 239 | public static function match($namespace, $methods, $route, $action) 240 | { 241 | $route = self::create($namespace, $methods, $route, $action); 242 | return $route; 243 | } 244 | 245 | /** 246 | * Add the route to the route manager 247 | * 248 | * @param string $name The rest route name 249 | * @return Rest 250 | */ 251 | public function register($name = false) { 252 | if ($name) $this->restManager->register($this, $name); 253 | else $this->restManager->register($this); 254 | return $this; 255 | } 256 | 257 | /** 258 | * Add parameter restrictions 259 | * 260 | * @param string|array $args[0] Parameter name or array 261 | * @param string $args[1] Regex restriction 262 | * @return Rest 263 | */ 264 | public function where(...$args) 265 | { 266 | if (!is_array($args[0])) { 267 | $args = array($args[0] => $args[1]); 268 | } else { 269 | $args = $args[0]; 270 | } 271 | foreach ($args as $key => $arg) { 272 | $optionalCharacter = false; 273 | if (substr($this->params[$key], -1) == '?') { 274 | $this->params[$key] = '?(?P<'.$key.'>' . $arg . ')?'; 275 | } else { 276 | $this->params[$key] = '(?P<'.$key.'>' . $arg . ')'; 277 | } 278 | } 279 | $this->generateRegex(); 280 | return $this; 281 | } 282 | 283 | /** 284 | * Add WP args 285 | * 286 | * @param string|array $args array of args 287 | * @return Rest 288 | */ 289 | public function args($args) 290 | { 291 | $this->args = (array) $args; 292 | return $this; 293 | } 294 | 295 | /** 296 | * Generate regular expression 297 | * 298 | * @return Rest 299 | */ 300 | public function generateRegex() 301 | { 302 | $this->regex = str_replace('/', '\/', $this->route) . '\/?$'; 303 | foreach ($this->params as $key => $regex) { 304 | $this->regex = preg_replace("/(\{".$key."\})/", $regex, $this->regex); 305 | } 306 | return $this; 307 | } 308 | 309 | /** 310 | * Get the route namespace 311 | * 312 | * @return string 313 | */ 314 | public function getNamespace() 315 | { 316 | return $this->namespace; 317 | } 318 | 319 | /** 320 | * Get the route action 321 | * 322 | * @return string|array 323 | */ 324 | public function getAction() 325 | { 326 | return $this->action; 327 | } 328 | 329 | /** 330 | * Load the action matching the requested route 331 | * 332 | * @param WP_REST_Request $request The WordPress request object 333 | * @return mixed 334 | */ 335 | public function loadAction(WP_REST_Request $request) 336 | { 337 | global $wp; 338 | 339 | self::$request = $request; 340 | 341 | $requestParams = []; 342 | 343 | preg_match_all('/'.$this->regex.'/', $wp->request, $matches); 344 | 345 | if (is_array($matches) && isset($matches[1])) { 346 | $count = 0; 347 | $paramNamesArr = array_keys($this->params); 348 | 349 | foreach($matches as $key => $match) { 350 | if ($key > 0 && $match[0]) { 351 | $requestParams[$paramNamesArr[$count]] = $match[0]; 352 | $count++; 353 | } 354 | } 355 | } 356 | 357 | if (is_string($this->action)) { 358 | 359 | if (strpos($this->action, ".") && file_exists($this->action)) { 360 | return include ($this->action); 361 | } else if (!empty($requestParams)) { 362 | return Sci::make($this->action, $requestParams); 363 | } else { 364 | return Sci::make($this->action); 365 | } 366 | 367 | } else if (is_callable( $this->action )){ 368 | 369 | $f = new ReflectionFunction($this->action); 370 | $callParams = array(); 371 | 372 | foreach ($f->getParameters() as $key => $param) { 373 | if ($param->getClass()) { 374 | if (isset($requestParams[$param->getName()]) && is_array($requestParams[$param->getName()])) { 375 | 376 | $callParams[] = Sci::make($param->getClass()->name, $requestParams[$param->getName()]); 377 | } else { 378 | 379 | // it's a funcion or a static method 380 | $callParams[] = Sci::make($param->getClass()->name); 381 | } 382 | } else { 383 | // If it is a simple parameter 384 | if (isset($requestParams[$param->getName()])) { 385 | $callParams[] = $requestParams[$param->getName()]; 386 | } else if ($param->isDefaultValueAvailable()) { 387 | $callParams[] = $param->getDefaultValue(); 388 | } 389 | } 390 | } 391 | 392 | return call_user_func_array($this->action, $callParams); 393 | 394 | } else { 395 | return Sci::make($this->action); 396 | } 397 | } 398 | 399 | /** 400 | * Get the request methods 401 | * 402 | * @return array 403 | */ 404 | public function getMethods() 405 | { 406 | return $this->methods; 407 | } 408 | 409 | /** 410 | * Get the regular expression 411 | * 412 | * @return string 413 | */ 414 | public function getRegex() 415 | { 416 | return $this->regex; 417 | } 418 | 419 | /** 420 | * Get the route args 421 | * 422 | * @return array 423 | */ 424 | public function getArgs() 425 | { 426 | return $this->args; 427 | } 428 | 429 | /** 430 | * Get the parameters 431 | * 432 | * @return array 433 | */ 434 | public function getParams() 435 | { 436 | return $this->params; 437 | } 438 | } -------------------------------------------------------------------------------- /framework/Router/Route.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Route 22 | { 23 | use \Sci\Traits\Sci; 24 | 25 | /** @var string $route */ 26 | private $route; 27 | 28 | /** @var Mixed $action */ 29 | private $action; 30 | 31 | /** @var string $regex */ 32 | public $regex; 33 | 34 | /** @var array $params */ 35 | private $params = array(); 36 | 37 | /** @var array $methods Request methods */ 38 | private $methods; 39 | 40 | /** @var boolean $async Run only of it's an ajax request */ 41 | private $async = false; 42 | 43 | /** @var string $layout Add wordpress layout */ 44 | private $layout = true; 45 | 46 | /** @var RouteManager $routeManager */ 47 | private $routeManager; 48 | 49 | /** 50 | * Class constructor 51 | * 52 | * @var string $route 53 | * @var mixed $action 54 | * @return Route 55 | */ 56 | public function __construct($methods, $route, $action, RouteManager $routeManager) 57 | { 58 | $this->routeManager = $routeManager; 59 | 60 | $this->methods = (array) $methods; 61 | foreach($this->methods as $key => $value) { 62 | $this->methods[$key] = strtoupper($value); 63 | } 64 | 65 | // Remove trailing slashes 66 | $route = trim($route, '/'); 67 | 68 | // Get parameters 69 | preg_match_all('/\{(.*?)(\?)?(\|((.*?)({.*})?)?)?\}/', rtrim($route, '/'), $matches); 70 | 71 | if (is_array($matches) && isset($matches[1])) { 72 | foreach ((array) $matches[1] as $key => $match) { 73 | $this->params[$match] = isset($matches[4][$key]) && $matches[4][$key] ? '(?P<'.$match.'>'.$matches[4][$key].')' : '(?P<'.$match.'>[A-Za-z0-9\-\_]+)'; 74 | if($matches[2][$key] == '?') { 75 | $this->params[$match] = '?' . $this->params[$match] . '?'; 76 | } 77 | /** NEW PARAM: add order, regex and name. Then, add to a request object, which will be linked to the current route */ 78 | } 79 | } 80 | 81 | $this->route = preg_replace('/\{(.*?)(\?)?(\|((.*?)({.*})?)?)?\}/', '{$1}', $route); 82 | 83 | $this->generateRegex(); 84 | 85 | $this->action = $action; 86 | return $this; 87 | } 88 | 89 | /** 90 | * Add a route 91 | * 92 | * @param string $method The route request method 93 | * @param string $route The route expression 94 | * @param mixed $action The action, file or function 95 | * @return Route 96 | */ 97 | public static function create($method, $route, $action) 98 | { 99 | return Sci::make(self::class, [$method, $route, $action]); 100 | } 101 | 102 | /** 103 | * Create and register a route 104 | * 105 | * @param string $method The route request method 106 | * @param string $route The route expression 107 | * @param mixed $action The action, file or function 108 | * @return Route 109 | */ 110 | public static function commit($method, $route, $action) 111 | { 112 | $route = self::create($method, $route, $action); 113 | $route->register(); 114 | return $route; 115 | } 116 | 117 | /** 118 | * Add a new route answering to the get method 119 | * 120 | * @param string $route The route expression 121 | * @param mixed $action The action, file or function 122 | * @return Route 123 | */ 124 | public static function get($route, $action) 125 | { 126 | $route = self::create('get', $route, $action); 127 | return $route; 128 | } 129 | 130 | /** 131 | * Add a new route answering to the post method 132 | * 133 | * @param string $route The route expression 134 | * @param mixed $action The action, file or function 135 | * @return Route 136 | */ 137 | public static function post($route, $action) 138 | { 139 | $route = self::create('post', $route, $action); 140 | return $route; 141 | } 142 | 143 | /** 144 | * Add a new route answering to the put method 145 | * 146 | * @param string $route The route expression 147 | * @param mixed $action The action, file or function 148 | * @return Route 149 | */ 150 | public static function put($route, $action) 151 | { 152 | $route = self::create('put', $route, $action); 153 | return $route; 154 | } 155 | 156 | /** 157 | * Add a new route answering to the patch method 158 | * 159 | * @param string $route The route expression 160 | * @param mixed $action The action, file or function 161 | * @return Route 162 | */ 163 | public static function patch($route, $action) 164 | { 165 | $route = self::create('patch', $route, $action); 166 | return $route; 167 | } 168 | 169 | /** 170 | * Add a new route answering to the delete method 171 | * 172 | * @param string $route The route expression 173 | * @param mixed $action The action, file or function 174 | * @return Route 175 | */ 176 | public static function delete($route, $action) 177 | { 178 | $route = self::create('delete', $route, $action); 179 | return $route; 180 | } 181 | 182 | /** 183 | * Add a new route answering to the options method 184 | * 185 | * @param string $route The route expression 186 | * @param mixed $action The action, file or function 187 | * @return Route 188 | */ 189 | public static function options($route, $action) 190 | { 191 | $route = self::create('options', $route, $action); 192 | return $route; 193 | } 194 | 195 | /** 196 | * Add a new route answering all methods 197 | * 198 | * @param string $route The route expression 199 | * @param mixed $action The action, file or function 200 | * @return Route 201 | */ 202 | public static function any($route, $action) 203 | { 204 | $route = self::create(['get', 'post', 'put', 'patch', 'delete', 'options'], $route, $action); 205 | return $route; 206 | } 207 | 208 | /** 209 | * Add the route to the route manager 210 | * 211 | * @param string $name 212 | * @return Route 213 | */ 214 | public function register($name = false) 215 | { 216 | if ($name) $this->routeManager->register($this, $name); 217 | else $this->routeManager->register($this); 218 | return $this; 219 | } 220 | 221 | /** 222 | * Add parameter restrictions 223 | * 224 | * @param string|array $args[0] Parameter name or array 225 | * @param string $args[1] Regex restriction 226 | * @return Route 227 | */ 228 | public function where(...$args) 229 | { 230 | if (!is_array($args[0])) { 231 | $args = array($args[0] => $args[1]); 232 | } else { 233 | $args = $args[0]; 234 | } 235 | foreach ($args as $key => $arg) { 236 | $optionalCharacter = false; 237 | if (substr($this->params[$key], -1) == '?') { 238 | $this->params[$key] = '?(?P<'.$key.'>' . $arg . ')?'; 239 | } else { 240 | $this->params[$key] = '(?P<'.$key.'>' . $arg . ')'; 241 | } 242 | } 243 | $this->generateRegex(); 244 | return $this; 245 | } 246 | 247 | /** 248 | * Set the request to accept async calls 249 | * 250 | * @return Route 251 | */ 252 | public function async($value = true) 253 | { 254 | $this->async = $value; 255 | return $this; 256 | } 257 | 258 | /** 259 | * Sets if the response will contain WordPress layout 260 | * 261 | * @return Route 262 | */ 263 | public function layout($value = false) 264 | { 265 | $this->layout = $value; 266 | return $this; 267 | } 268 | 269 | /** 270 | * Generate regular expression 271 | * 272 | * @return Route 273 | */ 274 | public function generateRegex() 275 | { 276 | $this->regex = str_replace('/', '\/', $this->route) . '\/?$'; 277 | //$this->regex = '/^' .$this->route. '$/' 278 | foreach ($this->params as $key => $regex) { 279 | $this->regex = preg_replace("/(\{".$key."\})/", $regex, $this->regex); 280 | } 281 | return $this; 282 | } 283 | 284 | /** 285 | * Get the route action 286 | * 287 | * @return string|array 288 | */ 289 | public function getAction() 290 | { 291 | return $this->action; 292 | } 293 | 294 | /** 295 | * Load the route action 296 | * 297 | * @return void 298 | */ 299 | public function loadAction() 300 | { 301 | global $wp; 302 | $requestParams = []; 303 | 304 | preg_match_all('/'.$this->regex.'/', $wp->request, $matches); 305 | 306 | if (is_array($matches) && isset($matches[1])) { 307 | $count = 0; 308 | $paramNamesArr = array_keys($this->params); 309 | 310 | foreach($matches as $key => $match) { 311 | if ($key > 0 && $match[0]) { 312 | $requestParams[$paramNamesArr[$count]] = $match[0]; 313 | $count++; 314 | } 315 | } 316 | } 317 | 318 | Request::setParams($requestParams); 319 | 320 | if ($this->layout && !$this->async) { 321 | wp_head(); 322 | get_header(); 323 | } 324 | 325 | if (is_string($this->action)) { 326 | 327 | if (strpos($this->action, ".") && file_exists($this->action)) { 328 | include ($this->action); 329 | } else if (!empty($requestParams)) { 330 | Sci::make($this->action, $requestParams); 331 | } else { 332 | Sci::make($this->action); 333 | } 334 | 335 | } else if (is_callable( $this->action )){ 336 | 337 | $f = new \ReflectionFunction($this->action); 338 | $callParams = array(); 339 | 340 | foreach ($f->getParameters() as $key => $param) { 341 | if ($param->getClass()) { 342 | if (isset($requestParams[$param->getName()]) && is_array($requestParams[$param->getName()])) { 343 | 344 | $callParams[] = Sci::make($param->getClass()->name, $requestParams[$param->getName()]); 345 | } else { 346 | 347 | // it's a funcion or a static method 348 | $callParams[] = Sci::make($param->getClass()->name); 349 | } 350 | } else { 351 | // If it is a simple parameter 352 | if (isset($requestParams[$param->getName()])) { 353 | $callParams[] = $requestParams[$param->getName()]; 354 | } else if ($param->isDefaultValueAvailable()) { 355 | $callParams[] = $param->getDefaultValue(); 356 | } 357 | } 358 | } 359 | call_user_func_array($this->action, $callParams); 360 | 361 | } else { 362 | Sci::make($this->action); 363 | } 364 | 365 | if ($this->layout && !$this->async) { 366 | 367 | get_footer(); 368 | } 369 | } 370 | 371 | /** 372 | * Get the request methods 373 | * 374 | * @return array 375 | */ 376 | public function getMethods() 377 | { 378 | return $this->methods; 379 | } 380 | 381 | /** 382 | * Get if it´s an async route 383 | * 384 | * @return boolean 385 | */ 386 | public function getAsync() 387 | { 388 | return $this->async; 389 | } 390 | 391 | 392 | /** 393 | * Get if the response has WordPress layout 394 | * 395 | * @return boolean 396 | */ 397 | public function getLayout() 398 | { 399 | return $this->layout; 400 | } 401 | 402 | /** 403 | * Get the regular expression 404 | * 405 | * @return string 406 | */ 407 | public function getRegex() 408 | { 409 | return $this->regex; 410 | } 411 | 412 | /** 413 | * Get the parameters 414 | * 415 | * @return array 416 | */ 417 | public function getParams() 418 | { 419 | return $this->params; 420 | } 421 | } -------------------------------------------------------------------------------- /framework/Sci.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Sci 22 | { 23 | /** @var Sci $_instance The class instance. */ 24 | protected static $_instance; 25 | 26 | /** @var string $file The main plugin file */ 27 | protected static $file; 28 | 29 | /** @var string[] $requirements */ 30 | protected static $requirements = [ 31 | 'PHP' => '7.2', 32 | 'WP' => '5.0', 33 | ]; 34 | 35 | /** @var PluginManager[] $plugiManager Stores references to PluginManager. */ 36 | private $pluginManager; 37 | 38 | /** @var Container $container Stores bindings and creation actions */ 39 | protected $container; 40 | 41 | /** 42 | * Returns a unique instance or creates a new one 43 | * 44 | * @return Sci 45 | */ 46 | public static function instance () 47 | { 48 | if (!isset( self::$_instance)) { 49 | self::$_instance = new Sci; 50 | self::$_instance->container = Container::instance(); 51 | } 52 | return self::$_instance; 53 | } 54 | 55 | /** 56 | * Create a new Sci instance 57 | * 58 | * @param string $file 59 | * @param string $name 60 | * @return Sci 61 | */ 62 | public static function create($file, $name = null) 63 | { 64 | self::$file = $file; 65 | register_activation_hook( self::$file, [self::class, 'activation']); 66 | 67 | try { 68 | $sci = self::instance(); 69 | $sci->pluginManager = self::make(PluginManager::class); 70 | add_action( 'activated_plugin', [self::class, 'loadFirst']); 71 | 72 | // Register the current plugin so it uses the framework 73 | if ($name !== null ) Plugin::create($file)->register($name); 74 | 75 | } catch (Exception $e) { 76 | wp_die($e->getMessage(),'Plugin Activation Error', array( 'response'=>200, 'back_link'=>TRUE ) ); 77 | } 78 | 79 | return $sci; 80 | } 81 | 82 | /** 83 | * Check PHP and WP core requirements 84 | * 85 | * @return void 86 | */ 87 | public static function activation() 88 | { 89 | global $wp_version; 90 | 91 | $flags = []; 92 | $errorText = ''; 93 | 94 | if ( version_compare( PHP_VERSION, self::$requirements['PHP'], '<' ) ) { 95 | $flags[] = 'PHP'; 96 | $errorText .= '

MVC WP Framework plugin requires PHP version '.self::$requirements['PHP'].' or greater.

'; 97 | } 98 | 99 | if (version_compare($wp_version, self::$requirements['WP'], '<' )) { 100 | $flags[] = 'WordPress'; 101 | $errorText .= '

MVC WP Framework plugin requires WordPress version '.self::$requirements['WP'].' or greater.

'; 102 | } 103 | 104 | if (!count($flags)) return; 105 | 106 | deactivate_plugins(self::$file); 107 | wp_die($errorText,'Plugin Activation Error', array( 'response'=>200, 'back_link'=>TRUE ) ); 108 | } 109 | 110 | /** 111 | * This plugin should have priority loading 112 | * 113 | * @return void 114 | */ 115 | public static function loadFirst () 116 | { 117 | $file = basename(dirname(dirname(__FILE__) )) . '/main.php'; 118 | $plugins = get_option( 'active_plugins' ); 119 | if (!count($plugins)) return; 120 | 121 | if ( $key = array_search( $file, $plugins ) ) { 122 | array_splice( $plugins, $key, 1 ); 123 | array_unshift( $plugins, $file ); 124 | update_option( 'active_plugins', $plugins ); 125 | } 126 | } 127 | 128 | /** 129 | * Get the container 130 | * 131 | * @return Container 132 | */ 133 | public function container() 134 | { 135 | return $this->container; 136 | } 137 | 138 | /** 139 | * Get a plugin 140 | * @param string $plugin The plugin id 141 | * @return Plugin 142 | */ 143 | public function plugin($pluginId) 144 | { 145 | return $this->pluginManager->get($pluginId); 146 | } 147 | 148 | /** 149 | * Get all plugin 150 | * 151 | * @return Plugin 152 | */ 153 | 154 | public function plugins() 155 | { 156 | return $this->pluginManager->all(); 157 | } 158 | 159 | /** 160 | * This magic method allows to use the get method both statically and within an instance 161 | * 162 | * @param string $name The function name 163 | * @param array $arguments The function a arguments 164 | */ 165 | public function __call($name, $arguments = null) 166 | { 167 | if ($name === 'make') return self::instance()->container->make(...$arguments); 168 | if ($name === 'bind') return self::instance()->container->bind(...$arguments); 169 | if ($name === 'singleton') return self::instance()->container->singleton(...$arguments); 170 | if ($name === 'alias') return self::instance()->container->alias(...$arguments); 171 | if ($name === 'created') return self::instance()->container->created(...$arguments); 172 | } 173 | 174 | /** 175 | * This magic method allows to use the get method both statically and within an instance 176 | * 177 | * @param string $name The function name 178 | * @param array $arguments The function a arguments 179 | */ 180 | public static function __callStatic($name, $arguments = null) 181 | { 182 | if ($name === 'make') return self::instance()->container->make(...$arguments); 183 | if ($name === 'bind') return self::instance()->container->bind(...$arguments); 184 | if ($name === 'singleton') return self::instance()->container->singleton(...$arguments); 185 | if ($name === 'alias') return self::instance()->container->alias(...$arguments); 186 | if ($name === 'created') return self::instance()->container->created(...$arguments); 187 | } 188 | } -------------------------------------------------------------------------------- /framework/Support/Collection.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | class Collection implements CollectionInterface 17 | { 18 | use \Sci\Traits\Sci; 19 | 20 | /** @var array $items Stores a list of the registered items */ 21 | private $items = []; 22 | 23 | /** 24 | * Add a new collection 25 | * 26 | * @param mixed $items 27 | * @return Collection 28 | */ 29 | public static function create($items = []) 30 | { 31 | return new self((array) $items); 32 | } 33 | 34 | /** 35 | * Create a new collection 36 | * 37 | * @param mixed $items 38 | * @return void 39 | */ 40 | public function __construct($items = []) 41 | { 42 | $this->items = (array) $items; 43 | } 44 | 45 | /** 46 | * Determine if an item exists in the collection 47 | * 48 | * @param mixed $value 49 | * @return bool 50 | */ 51 | public function contains($value) 52 | { 53 | if (func_num_args() === 1) return in_array($value, $this->items); 54 | 55 | $key = array_search($value, $this->items); 56 | if ($key === false) return false; 57 | return true; 58 | } 59 | 60 | /** 61 | * Get all the items 62 | * 63 | * @return array 64 | */ 65 | public function all() 66 | { 67 | return $this->items; 68 | } 69 | 70 | /** 71 | * Get an element 72 | * 73 | * @param string|number|null $key 74 | * @return mixed 75 | */ 76 | public function get($key = null) 77 | { 78 | if ($key == null) return $this->all(); 79 | 80 | if (isset($this->items[$key])) return $this->items[$key]; 81 | 82 | if (strpos($key, '/') === false) return false; 83 | 84 | $itemsArr = $this->items; 85 | $pathArr = explode("/",trim($key, '/')); 86 | 87 | foreach ($pathArr as $subKey) { 88 | if (!isset($itemsArr[$subKey])) { 89 | return false; 90 | } else { 91 | $itemsArr = $itemsArr[$subKey]; 92 | } 93 | } 94 | 95 | return $itemsArr; 96 | } 97 | 98 | /** 99 | * Check an element 100 | * 101 | * @param string $key 102 | * @param string $value 103 | * @return object|static 104 | */ 105 | public function check($key, $value) 106 | { 107 | $element = $this->get($key); 108 | if ($element === $value) return true; 109 | return false; 110 | } 111 | 112 | /** 113 | * Get the length of an element 114 | * 115 | * @param string $key 116 | * @param integer $length 117 | * @return integer|boolean 118 | */ 119 | public function length($key, $length = null) 120 | { 121 | if (!isset($this->items[$key])) return false; 122 | 123 | if (is_string($this->items[$key])) { 124 | if($length === null) return strlen($this->items[$key]); 125 | else return strlen($this->items[$key]) === $length; 126 | } 127 | 128 | if (is_array($this->items[$key])) { 129 | if($length === null) return count($this->items[$key]); 130 | else return count($this->items[$key]) === $length; 131 | } 132 | 133 | return false; 134 | } 135 | 136 | /** 137 | * Set a value for an element 138 | * 139 | * @param string|arra $key 140 | * @param mixed $item 141 | * @return Collection 142 | */ 143 | public function set($key, $item = null) 144 | { 145 | if (is_array($key)) { 146 | foreach($key as $item => $value) { 147 | $this->items[$item] = $value; 148 | } 149 | } else { 150 | $this->items[$key] = $item; 151 | } 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Add an item 158 | * 159 | * @param string|array $itemId 160 | * @param mixed $item 161 | * @return Collection 162 | */ 163 | public function add($key, $item = null) 164 | { 165 | return $this->set($key, $item); 166 | } 167 | 168 | /** 169 | * Remove an item 170 | * 171 | * @param string|array $key 172 | * @return Collection 173 | */ 174 | public function remove($key) 175 | { 176 | if (is_array($key)) { 177 | foreach ($k as $key) { 178 | unset($this->items[$k]); 179 | } 180 | } else { 181 | unset($this->items[$key]); 182 | } 183 | 184 | return $this; 185 | } 186 | } -------------------------------------------------------------------------------- /framework/Support/CollectionInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2020 Kenodo LTD 9 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 10 | * @version 1.0.0 11 | * @link https://www.sciwp.com 12 | * @since Version 1.0.0 13 | */ 14 | defined('ABSPATH') OR exit('No direct script access allowed'); 15 | 16 | interface CollectionInterface 17 | { 18 | /** 19 | * Get all the elements 20 | * 21 | * @return array 22 | */ 23 | public function all(); 24 | 25 | /** 26 | * Get an element 27 | * 28 | * @param string $id 29 | * @return mixed 30 | */ 31 | public function get($id); 32 | 33 | /** 34 | * Add an element 35 | * 36 | * @param string|array $element_id 37 | * @param mixed $element 38 | * @return CollectionInterface 39 | */ 40 | public function add($element_id, $element); 41 | 42 | /** 43 | * Remove an element 44 | * 45 | * @param string|array $element_id 46 | * @return CollectionInterface 47 | */ 48 | public function remove($element_id); 49 | } -------------------------------------------------------------------------------- /framework/Support/Helper.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2020 Kenodo LTD 12 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 13 | * @version 1.0.0 14 | * @link https://www.sciwp.com 15 | * @since Version 1.0.0 16 | */ 17 | class Helper 18 | { 19 | use StaticClass; 20 | } -------------------------------------------------------------------------------- /framework/Support/Managers/ProviderManager.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2020 Kenodo LTD 15 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 16 | * @version 1.0.0 17 | * @link https://www.sciwp.com 18 | * @since Version 1.0.0 19 | */ 20 | class ProviderManager extends Manager 21 | { 22 | /** @var array $providers Stores a list of the registered providers */ 23 | private $providers = array(); 24 | 25 | /** 26 | * Class constructor 27 | */ 28 | protected function __construct() 29 | { 30 | parent::__construct(); 31 | add_action( 'plugins_loaded', array($this, 'boot'), 1 ); 32 | } 33 | 34 | /** 35 | * Register Provider into the Provider Manager 36 | * 37 | * @param object|array $providers The plugin file path 38 | * @return ProviderManager 39 | */ 40 | public function register($providers) 41 | { 42 | foreach ((array)$providers as $provider) { 43 | 44 | if (!is_object($provider)) { 45 | $provider = $this->sci::make($provider); 46 | } 47 | 48 | if (!is_subclass_of($provider, Provider::class)) { 49 | throw new Exception('Only child classes or instances of the Provider class are accepted as providers.'); 50 | } 51 | 52 | $this->providers[] = $provider; 53 | 54 | if ( method_exists ( $provider , 'registered' ) ) { 55 | $provider->registered(); 56 | } 57 | } 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Calls the boot method for all the providers 64 | * 65 | * @return ProviderManager 66 | */ 67 | public function boot() 68 | { 69 | foreach ($this->providers as $provider) { 70 | if ( method_exists ( $provider , 'boot' ) ) { 71 | $provider->boot(); 72 | } 73 | } 74 | 75 | return $this; 76 | } 77 | } -------------------------------------------------------------------------------- /framework/Support/Provider.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2020 Kenodo LTD 14 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 15 | * @version 1.0.0 16 | * @link https://www.sciwp.com 17 | * @since Version 1.0.0 18 | */ 19 | class Provider 20 | { 21 | use \Sci\Traits\Sci; 22 | 23 | /** @var array $bindings Class bindings that should be registered. */ 24 | public $bindings; 25 | 26 | /** @var array $singletons Class singletons that should be registered. */ 27 | public $singletons; 28 | 29 | /** @var ProviderManager $providerManager */ 30 | private $providerManager; 31 | 32 | /** 33 | * Class constructor 34 | * 35 | * @var ProviderManager $providerManager 36 | * @return Provider 37 | */ 38 | public function __construct(ProviderManager $providerManager) 39 | { 40 | $this->providerManager = $providerManager; 41 | } 42 | 43 | /** 44 | * Add a provider 45 | * 46 | * @return Provider 47 | */ 48 | public static function create() 49 | { 50 | return Sci::make(self::class); 51 | } 52 | 53 | /** 54 | * Add the provider to the provider manager 55 | * 56 | * @param string $name The provider id 57 | * @return Provider 58 | */ 59 | public function register($name = false) 60 | { 61 | if ($name) { 62 | $this->providerManager->register($this, $name); 63 | } else { 64 | $this->providerManager->register($this); 65 | } 66 | return $this; 67 | } 68 | 69 | /** 70 | * Executed when the provider is registered 71 | */ 72 | public function registered() { 73 | } 74 | 75 | /** 76 | * Executed when all plugins are loaded 77 | */ 78 | public function boot() { 79 | } 80 | } -------------------------------------------------------------------------------- /framework/Template/Managers/TemplateManager.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class TemplateManager extends Manager 22 | { 23 | /** @var array $templates The array of templates that the plugins include. */ 24 | private $templates = array(); 25 | 26 | /** @var boolean $filtersAdded If the WP filters have been added or not. */ 27 | private $filtersAdded = false; 28 | 29 | /** @var string[] $postTypesWithTemplates The post types with templates. */ 30 | private $postTypesWithTemplates = []; 31 | 32 | /** 33 | * Class constructor 34 | */ 35 | protected function __construct() 36 | { 37 | parent::__construct(); 38 | } 39 | 40 | /** 41 | * Add a new template to the template manager 42 | * 43 | * @param Template $template The template object 44 | * @param string|bool $key The template identification key 45 | * @return TemplateManager 46 | */ 47 | public function register($template, $key = false) 48 | { 49 | if (!is_object($template) || !($template instanceof Template)) { 50 | throw new Exception('Only instances of the Template class can be registered.'); 51 | } 52 | 53 | if (!$key) $key = $this->getTemplatesNextArrKey(); 54 | 55 | $this->templates[$key] = $template; 56 | 57 | foreach ($template->getPostTypes() as $postType) { 58 | if (!in_array($postType, $this->postTypesWithTemplates)) { 59 | $this->postTypesWithTemplates[] = $postType; 60 | } 61 | } 62 | 63 | if (!$this->filtersAdded) $this->addFilters(); 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * Get next array numeric key 70 | * 71 | * @return integer 72 | */ 73 | public function getTemplatesNextArrKey() 74 | { 75 | if (count($this->templates)) { 76 | $numericKeys = array_filter(array_keys($this->templates), 'is_int'); 77 | if (count($numericKeys)) { 78 | return max($numericKeys) + 1; 79 | } 80 | } 81 | return 1; 82 | } 83 | 84 | /** 85 | * Add filters to WordPress so the templates are processed 86 | * 87 | * @return TemplateManager 88 | */ 89 | public function addFilters() 90 | { 91 | // Add a filter to the attributes metabox to inject template into the cache. 92 | if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) { 93 | add_filter('page_attributes_dropdown_pages_args', [$this, 'registerTemplates']); 94 | } 95 | else { 96 | add_filter('theme_page_templates', [$this, 'addTemplatesToDropdown']); 97 | } 98 | 99 | // Add a filter to the save post to inject out template into the page cache 100 | add_filter('wp_insert_post_data', [$this, 'registerTemplates']); 101 | 102 | // Add a filter to the template include to determine if the page has our template assigned and return it's path 103 | add_filter('template_include', [$this, 'viewTemplate']); 104 | 105 | // Page attributes support for post types with templates 106 | add_action( 'admin_init', [$this, 'addPageAttributesSupport'] ); 107 | 108 | // Add Attributes meta box to custom post types with page-attributes option enabled 109 | add_action( 'add_meta_boxes', [$this, 'addPostTypeTemplateDropdown'] ); 110 | add_action( 'save_post', [$this, 'addSaveTemplateAction'] ); 111 | 112 | // To avoid repeating this action 113 | $this->filtersAdded = true; 114 | return $this; 115 | } 116 | 117 | /** 118 | * Add support for page-attributes 119 | * 120 | * @param string $postType The name of the the post type 121 | * 122 | * @return void 123 | */ 124 | function addPageAttributesSupport() 125 | { 126 | foreach ($this->postTypesWithTemplates as $postType) { 127 | if (!post_type_supports($postType, 'page-attributes') ) { 128 | add_post_type_support( $postType, 'page-attributes' ); 129 | } 130 | } 131 | } 132 | 133 | /** 134 | * Add the attributes meta box to posts with page-attributes enabled 135 | * 136 | * @return void 137 | */ 138 | function addPostTypeTemplateDropdown() 139 | { 140 | global $post; 141 | if ( 'page' != $post->post_type && post_type_supports($post->post_type, 'page-attributes') ) { 142 | add_meta_box( 'custompageparentdiv', __('Template'), [$this, 'addPostTypeAttributesMetaBox'], NULL, 'side', 'core'); 143 | } 144 | } 145 | 146 | /** 147 | * Add the attributes meta box with the template selector 148 | * 149 | * @param WP_POST $post The post object 150 | * @return void 151 | */ 152 | function addPostTypeAttributesMetaBox($post) 153 | { 154 | $template = get_post_meta( $post->ID, '_wp_page_template', 1 ); 155 | ?> 156 | 161 | templates as $key => $template) { 189 | if (in_array(get_post_type(), $template->getPostTypes())) { 190 | $postTemplates[$key] = $template->getName(); 191 | } 192 | } 193 | 194 | return $postTemplates; 195 | } 196 | 197 | /** 198 | * Adds our template to the pages cache in order to trick WordPress 199 | * into thinking the template file exists where it doens't really exist. 200 | * 201 | * @param mixed $atts 202 | * @return mixed 203 | */ 204 | public function registerTemplates( $atts ) 205 | { 206 | // Create the key used for the themes cache 207 | $cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() ); 208 | 209 | // Retrieve the cache list. If it doesn't exist, or it's empty prepare an array 210 | $templates = wp_get_theme()->get_page_templates(); 211 | if (empty($templates)) $templates = array(); 212 | 213 | // New cache, therefore remove the old one 214 | wp_cache_delete($cache_key , 'themes'); 215 | 216 | // Add our templates to the list of templates by merging them with the existing templates array. 217 | foreach ($this->templates as $key => $template) { 218 | $templates[$key] = $template->getName(); 219 | } 220 | 221 | //$templates = array_merge( $templates, $this->templates ); 222 | 223 | // Add the modified cache to allow WordPress to pick it up for listing available templates 224 | wp_cache_add($cache_key, $templates, 'themes', 1800); 225 | 226 | return $atts; 227 | } 228 | 229 | /** 230 | * Checks if the template is assigned to the page 231 | * 232 | * @param string $template Template id or template path 233 | * @return array 234 | */ 235 | public function viewTemplate( $templatePath ) 236 | { 237 | global $wp_version; 238 | 239 | if (is_search()) return $templatePath; 240 | 241 | global $post; 242 | if (!$post) return $templatePath; 243 | 244 | $selectedTemplate = get_post_meta($post->ID, '_wp_page_template', true); 245 | 246 | $templates = array(); 247 | foreach ($this->templates as $key => $tpl) { 248 | if (in_array(get_post_type(), $tpl->getPostTypes())) { 249 | $templates[$key] = $tpl; 250 | } 251 | } 252 | 253 | if (!isset( $templates[$selectedTemplate])) return $templatePath; 254 | 255 | if (file_exists($templates[$selectedTemplate]->getThemePath())) return $templates[$selectedTemplate]->getThemePath(); 256 | 257 | if (file_exists( $templates[$selectedTemplate]->getPath() )) return $templates[$selectedTemplate]->getPath(); 258 | 259 | return $templatePath; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /framework/Template/Services/TemplateService.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class TemplateService 22 | { 23 | /** @var string $plugin The plugin this servuice belongs to. */ 24 | private $plugin; 25 | 26 | /** @var string $key The plugin key */ 27 | private $key; 28 | 29 | /** @var TemplateManager $templateManager The instance of the template manager. */ 30 | private $templateManager; 31 | 32 | /** 33 | * Constructor 34 | */ 35 | public function __construct($key, Plugin $plugin, TemplateManager $templateManager) 36 | { 37 | $this->key = $key; 38 | $this->plugin = $plugin; 39 | $this->templateManager = $templateManager; 40 | } 41 | 42 | /** 43 | * Allows to add a template using a relative route 44 | * 45 | * @param string $template The plugin relative route to the template file 46 | * @param string $name The name to display in WordPress for the template 47 | * @param string|array $postTypes The post type or post types to add to the template 48 | * @param string $themePath The path relative to the theme where the plugin should also look for 49 | * @return void 50 | */ 51 | public function template($template, $name = false, $postTypes = false, $themePath = false) 52 | { 53 | if (is_array($template)) { 54 | $template['path'] = $this->plugin->getDir() . '/' . $template['path']; 55 | } else { 56 | $template = $this->plugin->getDir() . '/' . $template; 57 | } 58 | 59 | return Template::create($template, $name, $postTypes, $themePath); 60 | } 61 | 62 | /** 63 | * Allows to add a set of templates in array format 64 | * 65 | * @param array $templatesDataArr Set of arrays with template data 66 | * @param boolean $register If the templates should be registered 67 | * @return void 68 | */ 69 | public function templates($templatesDataArr, $register = false) 70 | { 71 | foreach ($templatesDataArr as $key => $templateData) { 72 | $template = $this->template($templateData); 73 | if($register) { 74 | $template->register($key); 75 | } 76 | } 77 | return $this; 78 | } 79 | 80 | /** 81 | * Initializes the class 82 | * 83 | * @return self 84 | */ 85 | public function configure() 86 | { 87 | $templates = $this->plugin->config()->get('templates'); 88 | 89 | if (!$templates) return; 90 | 91 | foreach ( (array) $templates as $key => $template) { 92 | 93 | if (is_array($template)) { 94 | $template['path'] = $this->plugin->getDir() . '/' . $template['path']; 95 | } else { 96 | $template = [ 97 | 'path' => $this->plugin->getDir() . '/' . $template, 98 | 'name' => $key, 99 | 'post_types' => ['post'] 100 | ]; 101 | } 102 | 103 | Template::create($template)->register($key); 104 | } 105 | 106 | return $this; 107 | } 108 | } -------------------------------------------------------------------------------- /framework/Template/Template.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.mvcwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class Template 22 | { 23 | /** @var TemplateManager $templateManager The Sci template manager */ 24 | protected $templateManager; 25 | 26 | /** @var string $path The template path relative to the plugin base folder */ 27 | protected $path; 28 | 29 | /** @var string $themePath The path relative to the theme where the plugin should also look for */ 30 | protected $themePath; 31 | 32 | /** @var string $name The name to display in WordPress for the template */ 33 | protected $name; 34 | 35 | /** @var string $postTypes The post type to add the template to */ 36 | protected $postTypes; 37 | 38 | /** 39 | * Create a new template 40 | * 41 | * @param string|array $template The template file or array with the other fields 42 | * @param string $name The name to display in WordPress for the template 43 | * @param string|array $postTypes The post type or post types to add to the template 44 | * @param string $themePath The path relative to the theme where the plugin should also look for 45 | */ 46 | public function __construct($template, $name = false, $postTypes = false, $themePath = false, TemplateManager $templateManager) 47 | { 48 | $this->templateManager = $templateManager; 49 | 50 | if (is_array($template)) { 51 | 52 | if (!isset($template['path']) || !$template['path']) { 53 | throw new Exception('A template path is required.'); 54 | } 55 | 56 | $path = $template['path']; 57 | 58 | if (!$name && isset($template['name'])) { 59 | $name = $template['name']; 60 | } 61 | 62 | if (!$postTypes && isset($template['post_types'])) { 63 | $postTypes = $template['post_types']; 64 | } 65 | 66 | if (!$themePath && isset($template['theme_path'])) { 67 | $themePath = $template['theme_path']; 68 | } 69 | 70 | } else { 71 | $path = $template; 72 | } 73 | 74 | if (!$name) throw new Exception('A template name is required.'); 75 | 76 | $this->path = $path; 77 | $this->name = $name; 78 | $this->postTypes = $postTypes ? (array) $postTypes : []; 79 | if ($themePath) $this->themePath = $themePath; 80 | } 81 | 82 | /** 83 | * Add a new template 84 | * 85 | * @param string $template The template file or array with the other fields 86 | * @param string $name The name to display in WordPress for the template 87 | * @param string|array $postTypes The post type or post types to add to the template 88 | * @param string $themePath The path relative to the theme where the plugin should also look for 89 | * @return Template 90 | */ 91 | public static function create($template, $name = false, $postTypes = false, $themePath = false) 92 | { 93 | return Sci::make(self::class, [$template, $name, $postTypes, $themePath]); 94 | } 95 | 96 | /** 97 | * Add the template to the template manager 98 | * @param string $key The template key 99 | * @return Template 100 | */ 101 | public function register($key = false) 102 | { 103 | if (!$key) $key = str_replace(' ', '-', strtolower($this->name)); 104 | $this->templateManager->register($this, $key); 105 | return $this; 106 | } 107 | 108 | /** 109 | * Returns the template plugin path 110 | * 111 | * @return string 112 | */ 113 | public function getPath() 114 | { 115 | return $this->path; 116 | } 117 | 118 | /** 119 | * Returns the template theme path 120 | * 121 | * @return string 122 | */ 123 | public function getThemePath() 124 | { 125 | return get_theme_root() . '/'. get_stylesheet() . '/' . ltrim($this->themePath, '/'); 126 | } 127 | 128 | /** 129 | * Returns the post name 130 | * 131 | * @return string 132 | */ 133 | public function getName() 134 | { 135 | return $this->name; 136 | } 137 | 138 | /** 139 | * Returns the post types 140 | * 141 | * @return array 142 | */ 143 | public function getPostTypes() 144 | { 145 | return $this->postTypes; 146 | } 147 | 148 | /** 149 | * Set the plugin 150 | * 151 | * @param string|Plugin $plugin 152 | * @return Template 153 | */ 154 | public function setPlugin($plugin_id) 155 | { 156 | $this->plugin = $plugin instanceof Plugin ? $plugin : $this->Sci->plugin($plugin_id); 157 | return $this; 158 | } 159 | 160 | /** 161 | * Set the template path in the plugin 162 | * 163 | * @param string $path The path of the template 164 | * @return Template 165 | */ 166 | public function setPath($path) 167 | { 168 | $this->path = $path; 169 | return $this; 170 | } 171 | 172 | /** 173 | * Set the template path in the theme 174 | * 175 | * @param string $path The path of the template file in the theme 176 | * @return Template 177 | */ 178 | public function setThemePath($themePath) 179 | { 180 | $this->themePath = $themePath; 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * Se the template name 187 | * 188 | * @param array|string $postTypes The name to display in WordPress 189 | * @return Template 190 | */ 191 | public function setName($name) 192 | { 193 | $this->name = $name; 194 | return $this; 195 | } 196 | 197 | /** 198 | * Set the post types array 199 | * 200 | * @param array|string $postTypes A post type or an array of post types 201 | * @return Template 202 | */ 203 | public function setPostTypes($postTypes) 204 | { 205 | $this->postTypes = (array) $postTypes; 206 | return $this; 207 | } 208 | } -------------------------------------------------------------------------------- /framework/Traits/MethodBinding.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | trait MethodBinding 17 | { 18 | /** @var \ArrayObject Contains non static methods */ 19 | private $_methods = array(); 20 | 21 | /** @var \ArrayObject Contains static methods */ 22 | public static $_static_methods = array(); 23 | 24 | /** 25 | * Adds a regular method to an object 26 | * 27 | * @param string $name The method name 28 | * @param callable $callable The function to add 29 | */ 30 | public function addMethod($name, $callable) 31 | { 32 | if (!is_callable($callable)) { 33 | throw new InvalidArgumentException('Second param must be callable'); 34 | } 35 | $this->_methods[$name] = Closure::bind($callable, $this, get_class()); 36 | } 37 | 38 | /** 39 | * Adds a static method to a class 40 | * 41 | * @param string $name The method name 42 | * @param callable $callable The static function to add 43 | */ 44 | public static function addStaticMethod($name, $callable) 45 | { 46 | if (!is_callable($callable)) { 47 | throw new InvalidArgumentException('Second param must be callable'); 48 | } 49 | self::$_static_methods[$name] = \Closure::bind($callable, NULL, __CLASS__); 50 | } 51 | 52 | /** 53 | * Magic method used to call regular methods. 54 | * 55 | * @param string $name The method name 56 | * @param array $args The method args 57 | */ 58 | final public function __call($methodName, array $args) 59 | { 60 | if ( isset($this->methods[$methodName]) ) { 61 | return call_user_func_array($this->methods[$methodName], $args); 62 | } 63 | throw new \RunTimeException('Call to undefined instance method: '.$methodName.' for the class '.get_class($this)); 64 | } 65 | 66 | /** 67 | * Magic method used to call static methods. 68 | * 69 | * @param string $name The method name 70 | * @param array $args The method args 71 | */ 72 | final public static function __callStatic($name, array $args) 73 | { 74 | if (isset(self::$_static_methods[$name])) { 75 | return call_user_func(self::$_static_methods[$name], $args); 76 | } 77 | throw new \RunTimeException('Call to undefined static method: '.$name.' for the class'.static::__CLASS__ ); 78 | } 79 | } -------------------------------------------------------------------------------- /framework/Traits/Sci.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | trait Sci 19 | { 20 | /** @var Sci $Sci Stores the Sci reference */ 21 | public $sci; 22 | 23 | /** 24 | * Get the main Sci class instance 25 | */ 26 | public function Sci() 27 | { 28 | if ($this->sci === null) { 29 | $this->sci = Core::instance(); 30 | } 31 | return $this->sci; 32 | } 33 | } -------------------------------------------------------------------------------- /framework/Traits/Singleton.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | trait Singleton 19 | { 20 | /** @var array stores all singleton instances */ 21 | private static $_instances = array(); 22 | 23 | /** 24 | * Class constructor 25 | * 26 | * @return void 27 | */ 28 | protected function __construct() {} 29 | 30 | /** 31 | * Clone 32 | * 33 | * @return void 34 | */ 35 | final private function __clone() {} 36 | 37 | /** 38 | * Wakeup 39 | * 40 | * @return void 41 | */ 42 | protected function __wakeup() {} 43 | 44 | /** 45 | * Create or return an instance 46 | * 47 | * When creating and instance, this class is able the read the constructor parameters of the 48 | * singleton class, read and send the arguments and inject new instances of the dependences 49 | * if no instances are sent as arguments 50 | * 51 | * @return Singleton 52 | */ 53 | public static function instance () 54 | { 55 | $called_class = get_called_class(); 56 | if ( !isset( self::$_instances[$called_class] ) ) { 57 | $args = func_get_args(); 58 | $reflector = new \ReflectionClass($called_class); 59 | $constructor = $reflector->getConstructor(); 60 | 61 | if($constructor->getParameters()) { 62 | // The class constructor has declared arguments 63 | foreach ($constructor->getParameters() as $key => $parameter) { 64 | if ($parameter->getClass()) { 65 | if (isset($args[$key]) && is_array($args[$key])) { 66 | $inst_args[] = Sci::make($parameter->getClass()->name, $args[$key]); 67 | } else { 68 | $inst_args[] = Sci::make($parameter->getClass()->name); 69 | } 70 | } else { 71 | $inst_args[] = isset($args[$key]) ? $args[$key] : null; 72 | } 73 | } 74 | self::$_instances[$called_class] = new $called_class ( ...$inst_args ); 75 | } 76 | else { 77 | // The class constructor does not have declared arguments 78 | self::$_instances[$called_class] = new $called_class ( ...$args ); 79 | } 80 | self::$_instances[$called_class]->Sci = Sci::instance(); 81 | } 82 | return self::$_instances[$called_class]; 83 | } 84 | } -------------------------------------------------------------------------------- /framework/Traits/StaticClass.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | trait StaticClass 17 | { 18 | /** 19 | * Class constructor 20 | */ 21 | final protected function __construct(){} 22 | 23 | /** 24 | * Clone 25 | */ 26 | final private function __clone(){} 27 | 28 | /** 29 | * Wakeup 30 | */ 31 | final protected function __wakeup(){} 32 | } -------------------------------------------------------------------------------- /framework/View.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2020 Kenodo LTD 16 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 17 | * @version 1.0.0 18 | * @link https://www.sciwp.com 19 | * @since Version 1.0.0 20 | */ 21 | class View 22 | { 23 | /** @var array $params Parameter array */ 24 | protected $params = array(); 25 | 26 | /** @var string $file */ 27 | protected $file; 28 | 29 | /** @var string $plugin */ 30 | protected $plugin; 31 | 32 | /** @var string $module */ 33 | protected $module; 34 | 35 | /** 36 | * Constructor 37 | * 38 | * @param string $file $The view file without extensiona nd relative to the views folder 39 | * @param string|Plugin $plugin The plugin instance or plugin id 40 | * @param string $module The module name 41 | * @param PluginManager $pluginManager Plugin manager instance 42 | */ 43 | public function __construct($file, $plugin = null, $module = null, PluginManager $pluginManager) 44 | { 45 | $this->pluginManager = $pluginManager; 46 | $this->file = $file; 47 | 48 | if ($plugin instanceof Plugin) { 49 | $this->plugin = $plugin; 50 | } else if ($plugin) { 51 | $this->plugin = $this->pluginManager->get($plugin); 52 | } else if ($this->pluginManager->getMain()) { 53 | $this->plugin = $this->pluginManager->getMain(); 54 | } else { 55 | throw new Exception('You should specify a plugin when creating a view.'); 56 | } 57 | 58 | if ($module) $this->module = $module; 59 | } 60 | 61 | /** 62 | * Create a new template 63 | * 64 | * @param string $file The view file without extensiona nd relative to the views folder 65 | * @param string|Plugin $plugin The plugin instance or plugin id 66 | * @param string $module The module name 67 | * @return View 68 | */ 69 | public static function create($file, $plugin = null, $module = null) 70 | { 71 | return Sci::make(self::class, [$file, $plugin, $module]); 72 | } 73 | 74 | /** 75 | * Gets the full view path 76 | * 77 | * @return string 78 | */ 79 | private function getViewPath() 80 | { 81 | $viewsFolder = $this->plugin->config('views/dir'); 82 | if (!$viewsFolder) $viewsFolder = 'views'; 83 | 84 | $path = $this->file; 85 | 86 | if ($this->module !== null) { 87 | $path = $this->plugin->getModulesDir() . '/' . $this->module . '/' . $viewsFolder . '/' . $path; 88 | } else { 89 | $path = $this->plugin->getMainDir() . '/' . $viewsFolder. '/' . $path; 90 | } 91 | 92 | 93 | if (file_exists($path. '.view.php')) return $path. '.view.php'; 94 | else if (file_exists($path. '.php')) return $path. '.php'; 95 | 96 | throw new Exception('It was not possible to find the template ' . $path . '(.view).php'); 97 | } 98 | 99 | /** 100 | * Renders the view 101 | * 102 | * @param string $content Some content 103 | * @return void 104 | */ 105 | public function render($content = '') 106 | { 107 | $file = $this->getViewPath(); 108 | 109 | foreach($this->params as $key => $value) { 110 | ${$key} = $value; 111 | } 112 | 113 | return include ($file); 114 | } 115 | 116 | /** 117 | * Gets the result of rendering the view 118 | * 119 | * @return String 120 | */ 121 | public function process() 122 | { 123 | $file = $this->getViewPath(); 124 | 125 | ob_start(); 126 | $this->render($file); 127 | $render = ob_get_contents(); 128 | ob_end_clean(); 129 | ob_end_flush(); 130 | return ($render); 131 | } 132 | 133 | /** 134 | * Set the view params 135 | * 136 | * @return View 137 | */ 138 | public function params($params = array(), $override = false) 139 | { 140 | if ($override) $this->params = $params; 141 | else $this->params = array_merge($this->params, $params); 142 | return $this; 143 | } 144 | 145 | /** 146 | * Set a view param 147 | * 148 | * @return View 149 | */ 150 | public function param($key, $value) 151 | { 152 | $this->params[$key] = $value; 153 | return $this; 154 | } 155 | } -------------------------------------------------------------------------------- /framework/run.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2020 Kenodo LTD 11 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 12 | * @version 1.0.0 13 | * @link https://www.sciwp.com 14 | * @since Version 1.0.0 15 | */ 16 | 17 | // Files and vars used in this script 18 | $pluginDir = str_replace('/', '\\', rtrim(plugin_dir_path(dirname( __FILE__ , 1 )),'/')); 19 | $pluginFolder = basename($pluginDir); 20 | $parsedPluginFolder = preg_replace("/[^a-z0-9]/", '', strtolower($pluginFolder)); 21 | 22 | if (str_replace('/', '\\', WP_PLUGIN_DIR) == $pluginDir) $isCorePlugin = true; 23 | else $isCorePlugin = false; 24 | 25 | if ($isCorePlugin) { 26 | 27 | 28 | } else if (!$isCorePlugin) { 29 | 30 | $configFile = plugin_dir_path(dirname(__FILE__)) . 'config.php'; 31 | 32 | $cacheDir = plugin_dir_path( dirname(__FILE__) ) . 'cache/'; 33 | $configCacheFile = $cacheDir . 'config.cache.php'; 34 | 35 | $baseNamespace = explode('\\', __NAMESPACE__)[0]; 36 | 37 | /** 38 | * {Dynamic}ReplacePatternFunction 39 | * 40 | * Replace a string in all files of a folder, dynamic function name to avoid collisions and improve 41 | * compatibility with bundled Sci plugins 42 | * 43 | * @param $replacePatternFunction The function to process the string 44 | * @param $folder The folder to search for files 45 | * @param $oldString The string to be replaced 46 | * @param $newString The replacement string 47 | */ 48 | ${$parsedPluginFolder.'ReplacePatternFunction'} = function($replacePatternFunction, $folder, $oldString, $newString) 49 | { 50 | foreach (glob($folder."/*.php") as $filename) { 51 | $fileContent = file_get_contents($filename); 52 | 53 | $fileContent = preg_replace( 54 | "/(namespace +\\\?)(" . $oldString . ")((?:\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]+)*[ \n]*;)/", 55 | "$1{$newString}$3", 56 | $fileContent, 57 | 1 58 | ); 59 | 60 | $fileContent = preg_replace( 61 | "/".$oldString."(\\\[a-zA-Z0-9_\x7f-\xff]+)/", 62 | "{$newString}$1", 63 | $fileContent 64 | ); 65 | 66 | file_put_contents($filename, $fileContent); 67 | } 68 | $dirs = array_filter(glob($folder.'/'.'*', GLOB_ONLYDIR)); 69 | foreach($dirs as $dir) { 70 | $replacePatternFunction($replacePatternFunction, $dir, $oldString, $newString); 71 | } 72 | }; 73 | 74 | ${$parsedPluginFolder.'ReplaceSci'} = function($replaceSciFunction, $folder, $newString) 75 | { 76 | foreach (glob($folder."/*.php") as $filename) { 77 | 78 | $fileContent = file_get_contents($filename); 79 | 80 | if ($filename !== __FILE__) { 81 | $fileContent = preg_replace( 82 | "/namespace(\s*)Sci/", 83 | "namespace " . $newString . "\Sci", 84 | $fileContent, 85 | 1 86 | ); 87 | 88 | $fileContent = preg_replace( 89 | "/use(\s*)Sci/", 90 | "use " . $newString . "\Sci", 91 | $fileContent, 92 | 1 93 | ); 94 | 95 | $fileContent = preg_replace( 96 | "/use(\s*)\\\Sci/", 97 | "use \\" . $newString . "\Sci", 98 | $fileContent, 99 | 1 100 | ); 101 | } else { 102 | $fileContent = preg_replace( 103 | "/namespace(\s*)Sci/", 104 | "namespace " . $newString, 105 | $fileContent, 106 | 1 107 | ); 108 | 109 | $fileContent = preg_replace( 110 | "/use(\s*)Sci/", 111 | "use " . $newString, 112 | $fileContent, 113 | 1 114 | ); 115 | } 116 | 117 | file_put_contents($filename, $fileContent); 118 | } 119 | 120 | $dirs = array_filter(glob($folder.'/'.'*', GLOB_ONLYDIR)); 121 | foreach($dirs as $dir) { 122 | $replaceSciFunction($replaceSciFunction, $dir, $newString); 123 | } 124 | }; 125 | 126 | // Load config file 127 | if (!file_exists($configFile)) die('Cannot open the config file: ' . $configFile); 128 | 129 | $config = file_exists($configFile) ? include $configFile : []; 130 | 131 | $configCache = file_exists($configCacheFile) ? include $configCacheFile : ['namespace' => null, 'autoloader' => ['cache' => null]]; 132 | 133 | $rebuildNamespace = !isset($configCache['parsed_plugin_folder']) 134 | || (isset($config['rebuild']) && $config['rebuild'] === true) 135 | || (isset($config['namespace']) && $config['namespace'] !== $baseNamespace) 136 | || ucfirst($configCache['parsed_plugin_folder']) !== ucfirst($parsedPluginFolder); 137 | 138 | if ($rebuildNamespace) { 139 | 140 | if (isset($config['namespace']) && $config['namespace']) { 141 | $namespace = $config['namespace']; 142 | } else { 143 | $namespace = call_user_func( function() use ($parsedPluginFolder) { 144 | 145 | // Try to get the namespace from the main.php file 146 | $handle = fopen(plugin_dir_path( dirname(__FILE__) ) . '/main.php', "r"); 147 | 148 | if ($handle) { 149 | while (($line = fgets($handle)) !== false) { 150 | if (strpos($line, 'namespace') === 0) { 151 | $parts = preg_split('/\s+/', $line); 152 | if (isset($parts[1])) { 153 | return rtrim(trim($parts[1]), ';'); 154 | } 155 | } 156 | } 157 | fclose($handle); 158 | } 159 | 160 | // Fallback to the plugin folder name 161 | return ucfirst($parsedPluginFolder); 162 | }); 163 | } 164 | 165 | if ($namespace !== $baseNamespace) { 166 | 167 | if ($baseNamespace == 'Sci') { 168 | ${$parsedPluginFolder . 'ReplaceSci'}( 169 | ${$parsedPluginFolder . 'ReplaceSci'}, 170 | dirname(__FILE__), 171 | 'MyPlugin' 172 | ); 173 | } else { 174 | ${$parsedPluginFolder . 'ReplacePatternFunction'}( 175 | ${$parsedPluginFolder . 'ReplacePatternFunction'}, 176 | dirname(__FILE__), 177 | $baseNamespace, 178 | $namespace 179 | ); 180 | $configCache['plugin_folder'] = $pluginFolder; 181 | $configCache['parsed_plugin_folder'] = $parsedPluginFolder; 182 | 183 | if (!file_exists($cacheDir)) mkdir($cacheDir); 184 | file_put_contents ($configCacheFile, "init(); 217 | } 218 | 219 | die('Please rebuild MVC WP.'); 220 | 221 | } 222 | -------------------------------------------------------------------------------- /main.php: -------------------------------------------------------------------------------- 1 | plugin_basename(__FILE__), 42 | 'proper_folder_name' => 'sciwp', 43 | 'api_url' => 'https://api.github.com/repos/sciwp/sciwp-framework', 44 | 'raw_url' => 'https://raw.github.com/sciwp/sciwp-framework/master', 45 | 'github_url' => 'https://github.com/sciwp/sciwp-framework', 46 | 'zip_url' => 'https://github.com/sciwp/sciwp-framework/archive/master.zip', 47 | 'sslverify' => true, 48 | 'requires' => '5.0', 49 | 'tested' => '5.0', 50 | 'readme' => 'README.md', 51 | 'access_token' => '', 52 | ]); 53 | 54 | require_once plugin_dir_path(__FILE__).'framework/Sci.php'; 55 | require_once plugin_dir_path(__FILE__).'framework/Autoloader.php'; 56 | 57 | Autoloader::start('core'); 58 | Sci::create(__FILE__); 59 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | # SCI WP Framework 2 | 3 | Contributors: neeonez 4 | Tags: framework, mvc, orm, autoloader, models, views, controllers, services, plugins, dependency injection, DI, scripts, styles, templates, router, routes. 5 | Requires at least: 5.2 6 | Tested up to: 5.3 7 | Requires PHP: 7.2 8 | Stable tag: trunk 9 | License: GNU Lesser General Public License 10 | License URI: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 11 | 12 | MVC Features for WordPress. 13 | 14 | == Description == 15 | 16 | This plugin is useful for users or companies who want to create custom plugins for their personal or internal usage. 17 | 18 | Features: 19 | 20 | 1. ORM with common CRUD operations and Query builder 21 | 2. MVC Architecture (Controllers, Models, Views) 22 | 3. Service container supporting parametrized dependency injection 23 | 4. Namespaces and PSR-4 compliant autoloader 24 | 5. Configure custom URL routes hierarchically 25 | 6. Install once and use with all plugins you want 26 | 7. Collections, Services and dynamic method bindings 27 | 8. Activation and deactivation actions and checks 28 | 9. Asset manager for JS scripts and CSS files 29 | 10. Service providers 30 | 11. Template manager 31 | 32 | 33 | Important: This plugin is not a starter template or something you can bundle. In case you want to bundle the included framework with your own plugin and distribute it, 34 | you should use the embedded framework version instead, which is avaiable at GitHub. You can also find a starter boilerplate at GitHub. 35 | Althouth sometimes it might be easy to do it, you should never bundle another plugin directly, as it can cause big compatibility problems for other users using the plugin. 36 | 37 | == Installation == 38 | 39 | 40 | You can install this plugin by these two methods: 41 | 42 | 1. You can install it form the WordPress Plugin Manager 43 | 2. Or you can download the zip file, unzip it and upload the "mvc-wp" directory to the WordPress `/wp-content/plugins/` directory. 44 | 45 | 46 | == Tutorial == 47 | 48 | 49 | You can find the documentation here: http://sciwp.com/ 50 | 51 | == Changelog == 52 | 53 | = 1.0 = 54 | * Initial release -------------------------------------------------------------------------------- /setup.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2020 Kenodo LTD 13 | * @license https://opensource.org/licenses/LGPL-2.1 GNU Lesser GPL version 2.1 14 | * @version 1.0.0 15 | * @link https://www.sciwp.com 16 | * @since Version 1.0.0 17 | */ 18 | class Setup 19 | { 20 | /** 21 | * Renames the plugin base folder 22 | * 23 | * @return void 24 | */ 25 | public static function checkPluginFolder($folder) 26 | { 27 | if (basename(__DIR__) == $folder) return; 28 | 29 | $currentFolder = trim(trim(plugin_dir_path(__FILE__),"/"),"\\"); 30 | $newFolder = trim(trim(dirname(plugin_dir_path(__FILE__)),"/"),"\\") . DIRECTORY_SEPARATOR . $folder; 31 | 32 | rename($currentFolder, $newFolder) && wp_die("Ups, seems you forgot to rename the plugin folder to \"".$folder."\". Don't worry, the mad sciencists have done it for you. Click back and try activating the plugin again.", 'SCIWP Framework', array( 'response'=>200, 'back_link'=>TRUE ) ); 33 | 34 | wp_die("Ups, there was an issue renaming your plugin folder name, please rename it manually to \"".$folder."\" and try again.", 'SCIWP Framework', array( 'response'=>200, 'back_link'=>TRUE ) ); 35 | } 36 | 37 | /** 38 | * Renames the plugin base folder 39 | * 40 | * @return void 41 | */ 42 | public static function checkUpdates($config) 43 | { 44 | if (is_admin()) { 45 | new \WP_GitHub_Updater($config); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /updater.php: -------------------------------------------------------------------------------- 1 | 12 | * @link http://jkudish.com 13 | * @package WP_GitHub_Updater 14 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 15 | * @copyright Copyright (c) 2011-2013, Joachim Kudish 16 | * 17 | * GNU General Public License, Free Software Foundation 18 | * 19 | * 20 | * This program is free software; you can redistribute it and/or modify 21 | * it under the terms of the GNU General Public License as published by 22 | * the Free Software Foundation; either version 2 of the License, or 23 | * (at your option) any later version. 24 | * 25 | * This program is distributed in the hope that it will be useful, 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | * GNU General Public License for more details. 29 | * 30 | * You should have received a copy of the GNU General Public License 31 | * along with this program; if not, write to the Free Software 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33 | */ 34 | class WP_GitHub_Updater { 35 | 36 | /** 37 | * GitHub Updater version 38 | */ 39 | const VERSION = 1.6; 40 | 41 | /** 42 | * @var $config the config for the updater 43 | * @access public 44 | */ 45 | var $config; 46 | 47 | /** 48 | * @var $missing_config any config that is missing from the initialization of this instance 49 | * @access public 50 | */ 51 | var $missing_config; 52 | 53 | /** 54 | * @var $github_data temporiraly store the data fetched from GitHub, allows us to only load the data once per class instance 55 | * @access private 56 | */ 57 | private $github_data; 58 | 59 | 60 | /** 61 | * Class Constructor 62 | * 63 | * @since 1.0 64 | * @param array $config the configuration required for the updater to work 65 | * @see has_minimum_config() 66 | * @return void 67 | */ 68 | public function __construct( $config = array() ) { 69 | 70 | $defaults = array( 71 | 'slug' => plugin_basename( __FILE__ ), 72 | 'proper_folder_name' => dirname( plugin_basename( __FILE__ ) ), 73 | 'sslverify' => true, 74 | 'access_token' => '', 75 | ); 76 | 77 | $this->config = wp_parse_args( $config, $defaults ); 78 | 79 | // if the minimum config isn't set, issue a warning and bail 80 | if ( ! $this->has_minimum_config() ) { 81 | $message = 'The GitHub Updater was initialized without the minimum required configuration, please check the config in your plugin. The following params are missing: '; 82 | $message .= implode( ',', $this->missing_config ); 83 | _doing_it_wrong( __CLASS__, $message , self::VERSION ); 84 | return; 85 | } 86 | 87 | $this->set_defaults(); 88 | 89 | add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'api_check' ) ); 90 | 91 | // Hook into the plugin details screen 92 | add_filter( 'plugins_api', array( $this, 'get_plugin_info' ), 10, 3 ); 93 | add_filter( 'upgrader_post_install', array( $this, 'upgrader_post_install' ), 10, 3 ); 94 | 95 | // set timeout 96 | add_filter( 'http_request_timeout', array( $this, 'http_request_timeout' ) ); 97 | 98 | // set sslverify for zip download 99 | add_filter( 'http_request_args', array( $this, 'http_request_sslverify' ), 10, 2 ); 100 | } 101 | 102 | public function has_minimum_config() { 103 | 104 | $this->missing_config = array(); 105 | 106 | $required_config_params = array( 107 | 'api_url', 108 | 'raw_url', 109 | 'github_url', 110 | 'zip_url', 111 | 'requires', 112 | 'tested', 113 | 'readme', 114 | ); 115 | 116 | foreach ( $required_config_params as $required_param ) { 117 | if ( empty( $this->config[$required_param] ) ) 118 | $this->missing_config[] = $required_param; 119 | } 120 | 121 | return ( empty( $this->missing_config ) ); 122 | } 123 | 124 | 125 | /** 126 | * Check wether or not the transients need to be overruled and API needs to be called for every single page load 127 | * 128 | * @return bool overrule or not 129 | */ 130 | public function overrule_transients() { 131 | return ( defined( 'WP_GITHUB_FORCE_UPDATE' ) && WP_GITHUB_FORCE_UPDATE ); 132 | } 133 | 134 | 135 | /** 136 | * Set defaults 137 | * 138 | * @since 1.2 139 | * @return void 140 | */ 141 | public function set_defaults() { 142 | if ( !empty( $this->config['access_token'] ) ) { 143 | 144 | // See Downloading a zipball (private repo) https://help.github.com/articles/downloading-files-from-the-command-line 145 | extract( parse_url( $this->config['zip_url'] ) ); // $scheme, $host, $path 146 | 147 | $zip_url = $scheme . '://api.github.com/repos' . $path; 148 | $zip_url = add_query_arg( array( 'access_token' => $this->config['access_token'] ), $zip_url ); 149 | 150 | $this->config['zip_url'] = $zip_url; 151 | } 152 | 153 | 154 | if ( ! isset( $this->config['new_version'] ) ) 155 | $this->config['new_version'] = $this->get_new_version(); 156 | 157 | if ( ! isset( $this->config['last_updated'] ) ) 158 | $this->config['last_updated'] = $this->get_date(); 159 | 160 | if ( ! isset( $this->config['description'] ) ) 161 | $this->config['description'] = $this->get_description(); 162 | 163 | $plugin_data = $this->get_plugin_data(); 164 | if ( ! isset( $this->config['plugin_name'] ) ) 165 | $this->config['plugin_name'] = $plugin_data['Name']; 166 | 167 | if ( ! isset( $this->config['version'] ) ) 168 | $this->config['version'] = $plugin_data['Version']; 169 | 170 | if ( ! isset( $this->config['author'] ) ) 171 | $this->config['author'] = $plugin_data['Author']; 172 | 173 | if ( ! isset( $this->config['homepage'] ) ) 174 | $this->config['homepage'] = $plugin_data['PluginURI']; 175 | 176 | if ( ! isset( $this->config['readme'] ) ) 177 | $this->config['readme'] = 'README.md'; 178 | 179 | } 180 | 181 | 182 | /** 183 | * Callback fn for the http_request_timeout filter 184 | * 185 | * @since 1.0 186 | * @return int timeout value 187 | */ 188 | public function http_request_timeout() { 189 | return 2; 190 | } 191 | 192 | /** 193 | * Callback fn for the http_request_args filter 194 | * 195 | * @param unknown $args 196 | * @param unknown $url 197 | * 198 | * @return mixed 199 | */ 200 | public function http_request_sslverify( $args, $url ) { 201 | if ( $this->config[ 'zip_url' ] == $url ) 202 | $args[ 'sslverify' ] = $this->config[ 'sslverify' ]; 203 | 204 | return $args; 205 | } 206 | 207 | 208 | /** 209 | * Get New Version from GitHub 210 | * 211 | * @since 1.0 212 | * @return int $version the version number 213 | */ 214 | public function get_new_version() { 215 | $version = get_site_transient( md5($this->config['slug']).'_new_version' ); 216 | 217 | if ( $this->overrule_transients() || ( !isset( $version ) || !$version || '' == $version ) ) { 218 | 219 | $raw_response = $this->remote_get( trailingslashit( $this->config['raw_url'] ) . basename( $this->config['slug'] ) ); 220 | 221 | if ( is_wp_error( $raw_response ) ) 222 | $version = false; 223 | 224 | if (is_array($raw_response)) { 225 | if (!empty($raw_response['body'])) 226 | preg_match( '/.*Version\:\s*(.*)$/mi', $raw_response['body'], $matches ); 227 | } 228 | 229 | if ( empty( $matches[1] ) ) 230 | $version = false; 231 | else 232 | $version = $matches[1]; 233 | 234 | // back compat for older readme version handling 235 | // only done when there is no version found in file name 236 | if ( false === $version ) { 237 | $raw_response = $this->remote_get( trailingslashit( $this->config['raw_url'] ) . $this->config['readme'] ); 238 | 239 | if ( is_wp_error( $raw_response ) ) 240 | return $version; 241 | 242 | preg_match( '#^\s*`*~Current Version\:\s*([^~]*)~#im', $raw_response['body'], $__version ); 243 | 244 | if ( isset( $__version[1] ) ) { 245 | $version_readme = $__version[1]; 246 | if ( -1 == version_compare( $version, $version_readme ) ) 247 | $version = $version_readme; 248 | } 249 | } 250 | 251 | // refresh every 6 hours 252 | if ( false !== $version ) 253 | set_site_transient( md5($this->config['slug']).'_new_version', $version, 60*60*6 ); 254 | } 255 | 256 | return $version; 257 | } 258 | 259 | 260 | /** 261 | * Interact with GitHub 262 | * 263 | * @param string $query 264 | * 265 | * @since 1.6 266 | * @return mixed 267 | */ 268 | public function remote_get( $query ) { 269 | if ( ! empty( $this->config['access_token'] ) ) 270 | $query = add_query_arg( array( 'access_token' => $this->config['access_token'] ), $query ); 271 | 272 | $raw_response = wp_remote_get( $query, array( 273 | 'sslverify' => $this->config['sslverify'] 274 | ) ); 275 | 276 | return $raw_response; 277 | } 278 | 279 | 280 | /** 281 | * Get GitHub Data from the specified repository 282 | * 283 | * @since 1.0 284 | * @return array $github_data the data 285 | */ 286 | public function get_github_data() { 287 | if ( isset( $this->github_data ) && ! empty( $this->github_data ) ) { 288 | $github_data = $this->github_data; 289 | } else { 290 | $github_data = get_site_transient( md5($this->config['slug']).'_github_data' ); 291 | 292 | if ( $this->overrule_transients() || ( ! isset( $github_data ) || ! $github_data || '' == $github_data ) ) { 293 | $github_data = $this->remote_get( $this->config['api_url'] ); 294 | 295 | if ( is_wp_error( $github_data ) ) 296 | return false; 297 | 298 | $github_data = json_decode( $github_data['body'] ); 299 | 300 | // refresh every 6 hours 301 | set_site_transient( md5($this->config['slug']).'_github_data', $github_data, 60*60*6 ); 302 | } 303 | 304 | // Store the data in this class instance for future calls 305 | $this->github_data = $github_data; 306 | } 307 | 308 | return $github_data; 309 | } 310 | 311 | 312 | /** 313 | * Get update date 314 | * 315 | * @since 1.0 316 | * @return string $date the date 317 | */ 318 | public function get_date() { 319 | $_date = $this->get_github_data(); 320 | return ( !empty( $_date->updated_at ) ) ? date( 'Y-m-d', strtotime( $_date->updated_at ) ) : false; 321 | } 322 | 323 | 324 | /** 325 | * Get plugin description 326 | * 327 | * @since 1.0 328 | * @return string $description the description 329 | */ 330 | public function get_description() { 331 | $_description = $this->get_github_data(); 332 | return ( !empty( $_description->description ) ) ? $_description->description : false; 333 | } 334 | 335 | 336 | /** 337 | * Get Plugin data 338 | * 339 | * @since 1.0 340 | * @return object $data the data 341 | */ 342 | public function get_plugin_data() { 343 | include_once ABSPATH.'/wp-admin/includes/plugin.php'; 344 | $data = get_plugin_data( WP_PLUGIN_DIR.'/'.$this->config['slug'] ); 345 | return $data; 346 | } 347 | 348 | 349 | /** 350 | * Hook into the plugin update check and connect to GitHub 351 | * 352 | * @since 1.0 353 | * @param object $transient the plugin data transient 354 | * @return object $transient updated plugin data transient 355 | */ 356 | public function api_check( $transient ) { 357 | 358 | // Check if the transient contains the 'checked' information 359 | // If not, just return its value without hacking it 360 | if ( empty( $transient->checked ) ) 361 | return $transient; 362 | 363 | // check the version and decide if it's new 364 | $update = version_compare( $this->config['new_version'], $this->config['version'] ); 365 | 366 | if ( 1 === $update ) { 367 | $response = new stdClass; 368 | $response->new_version = $this->config['new_version']; 369 | $response->slug = $this->config['proper_folder_name']; 370 | $response->url = add_query_arg( array( 'access_token' => $this->config['access_token'] ), $this->config['github_url'] ); 371 | $response->package = $this->config['zip_url']; 372 | 373 | // If response is false, don't alter the transient 374 | if ( false !== $response ) 375 | $transient->response[ $this->config['slug'] ] = $response; 376 | } 377 | 378 | return $transient; 379 | } 380 | 381 | 382 | /** 383 | * Get Plugin info 384 | * 385 | * @since 1.0 386 | * @param bool $false always false 387 | * @param string $action the API function being performed 388 | * @param object $args plugin arguments 389 | * @return object $response the plugin info 390 | */ 391 | public function get_plugin_info( $false, $action, $response ) { 392 | 393 | // Check if this call API is for the right plugin 394 | if ( !isset( $response->slug ) || $response->slug != $this->config['slug'] ) 395 | return false; 396 | 397 | $response->slug = $this->config['slug']; 398 | $response->plugin_name = $this->config['plugin_name']; 399 | $response->version = $this->config['new_version']; 400 | $response->author = $this->config['author']; 401 | $response->homepage = $this->config['homepage']; 402 | $response->requires = $this->config['requires']; 403 | $response->tested = $this->config['tested']; 404 | $response->downloaded = 0; 405 | $response->last_updated = $this->config['last_updated']; 406 | $response->sections = array( 'description' => $this->config['description'] ); 407 | $response->download_link = $this->config['zip_url']; 408 | 409 | return $response; 410 | } 411 | 412 | 413 | /** 414 | * Upgrader/Updater 415 | * Move & activate the plugin, echo the update message 416 | * 417 | * @since 1.0 418 | * @param boolean $true always true 419 | * @param mixed $hook_extra not used 420 | * @param array $result the result of the move 421 | * @return array $result the result of the move 422 | */ 423 | public function upgrader_post_install( $true, $hook_extra, $result ) { 424 | 425 | global $wp_filesystem; 426 | 427 | // Move & Activate 428 | $proper_destination = WP_PLUGIN_DIR.'/'.$this->config['proper_folder_name']; 429 | $wp_filesystem->move( $result['destination'], $proper_destination ); 430 | $result['destination'] = $proper_destination; 431 | $activate = activate_plugin( WP_PLUGIN_DIR.'/'.$this->config['slug'] ); 432 | 433 | // Output the update message 434 | $fail = __( 'The plugin has been updated, but could not be reactivated. Please reactivate it manually.', 'github_plugin_updater' ); 435 | $success = __( 'Plugin reactivated successfully.', 'github_plugin_updater' ); 436 | echo is_wp_error( $activate ) ? $fail : $success; 437 | return $result; 438 | 439 | } 440 | } --------------------------------------------------------------------------------