| @@ -47,8 +47,15 @@ | ||
| 47 | 47 | * put your comment there... |
| 48 | 48 | * |
| 49 | 49 | * @var mixed |
| 50 | 50 | */ |
| 51 | + protected static $instance = null; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * put your comment there... | |
| 55 | + * | |
| 56 | + * @var mixed | |
| 57 | + */ | |
| 51 | 58 | private $onActionIds = array(); |
| 52 | 59 | |
| 53 | 60 | /** |
| 54 | 61 | * put your comment there... |
| @@ -111,8 +118,15 @@ | ||
| 111 | 118 | * |
| 112 | 119 | * @var mixed |
| 113 | 120 | */ |
| 114 | 121 | protected $ongetfilters = array('parameters' => array('filters')); |
| 122 | + | |
| 123 | + /** | |
| 124 | + * put your comment there... | |
| 125 | + * | |
| 126 | + * @var mixed | |
| 127 | + */ | |
| 128 | + protected $onlinkedtemplates = array('parameters' => array('templates')); | |
| 115 | 129 | |
| 116 | 130 | /** |
| 117 | 131 | * put your comment there... |
| 118 | 132 | * |
| @@ -117,8 +131,29 @@ | ||
| 117 | 131 | * put your comment there... |
| 118 | 132 | * |
| 119 | 133 | * @var mixed |
| 120 | 134 | */ |
| 135 | + protected $onlinkscripts = array('parameters' => array('templates')); | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * put your comment there... | |
| 139 | + * | |
| 140 | + * @var mixed | |
| 141 | + */ | |
| 142 | + protected $onlinkstyles = array('parameters' => array('templates')); | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * put your comment there... | |
| 146 | + * | |
| 147 | + * @var mixed | |
| 148 | + */ | |
| 149 | + protected $onlinktemplate = array('parameters' => array('template')); | |
| 150 | + | |
| 151 | + /** | |
| 152 | + * put your comment there... | |
| 153 | + * | |
| 154 | + * @var mixed | |
| 155 | + */ | |
| 121 | 156 | protected $onmatchingurls = array('parameters' => array('urls')); |
| 122 | 157 | |
| 123 | 158 | /** |
| 124 | 159 | * put your comment there... |
| @@ -152,11 +187,32 @@ | ||
| 152 | 187 | * put your comment there... |
| 153 | 188 | * |
| 154 | 189 | * @var mixed |
| 155 | 190 | */ |
| 191 | + protected $onqueuecss = array('parameters' => array('style')); | |
| 192 | + | |
| 193 | + /** | |
| 194 | + * put your comment there... | |
| 195 | + * | |
| 196 | + * @var mixed | |
| 197 | + */ | |
| 198 | + protected $onqueuejavascript = array('parameters' => array('script')); | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * put your comment there... | |
| 202 | + * | |
| 203 | + * @var mixed | |
| 204 | + */ | |
| 156 | 205 | protected $onsetfilters = array('parameters' => array('filters')); |
| 157 | 206 | |
| 158 | 207 | /** |
| 208 | + * put your comment there... | |
| 209 | + * | |
| 210 | + * @var mixed | |
| 211 | + */ | |
| 212 | + protected $templates = array(); | |
| 213 | + | |
| 214 | + /** | |
| 159 | 215 | * Initialize controller object. |
| 160 | 216 | * |
| 161 | 217 | * @see CJTController for more details |
| 162 | 218 | * @return void |
| @@ -161,8 +217,15 @@ | ||
| 161 | 217 | * @see CJTController for more details |
| 162 | 218 | * @return void |
| 163 | 219 | */ |
| 164 | 220 | public function __construct() { |
| 221 | + // Only one instance is allowed. | |
| 222 | + if (self::$instance) { | |
| 223 | + throw new Exception('Trying to instantiate multiple coupling instances!!'); | |
| 224 | + } | |
| 225 | + // Hold the single instance we've! | |
| 226 | + self::$instance = $this; | |
| 227 | + $siteHook = cssJSToolbox::$config->core->siteHook; | |
| 165 | 228 | // Initialize controller. |
| 166 | 229 | parent::__construct(false); |
| 167 | 230 | // Import related libraries |
| 168 | 231 | CJTModel::import('block'); |
| @@ -170,9 +233,9 @@ | ||
| 170 | 233 | $this->defaultAction = null; |
| 171 | 234 | // Initialize controller. |
| 172 | 235 | $initCouplingCallback = $this->onassigncouplingcallback(array(&$this, 'initCoupling')); |
| 173 | 236 | add_action('admin_init', $initCouplingCallback); |
| 174 | - add_action('wp', $initCouplingCallback); | |
| 237 | + add_action($siteHook->tag, $initCouplingCallback, $siteHook->priority); | |
| 175 | 238 | // Add Shortcode callbacks. |
| 176 | 239 | add_shortcode('cjtoolbox', array(&$this, 'shortcode')); |
| 177 | 240 | } |
| 178 | 241 | |
| @@ -178,9 +241,23 @@ | ||
| 178 | 241 | |
| 179 | 242 | /** |
| 180 | 243 | * put your comment there... |
| 181 | 244 | * |
| 245 | + * @param mixed $id | |
| 182 | 246 | */ |
| 247 | + public function addOnActionIds($id) { | |
| 248 | + // Add ID is not exists. | |
| 249 | + if (!in_array($id, $this->onActionIds)) { | |
| 250 | + $this->onActionIds[] = $id; | |
| 251 | + } | |
| 252 | + // Chaining. | |
| 253 | + return $this; | |
| 254 | + } | |
| 255 | + | |
| 256 | + /** | |
| 257 | + * put your comment there... | |
| 258 | + * | |
| 259 | + */ | |
| 183 | 260 | public function getBlocks() { |
| 184 | 261 | // Set request view filters used for querying database. |
| 185 | 262 | $this->setRequestFilters(); |
| 186 | 263 | // Get blocks order. NOTE: This is all blocks order not only the queried/target blocks. |
| @@ -187,8 +264,13 @@ | ||
| 187 | 264 | $blocksOrder = array(); |
| 188 | 265 | $metaBoxesOrder = $this->onblocksorder($this->model->getOrder()); |
| 189 | 266 | // Get ORDER-INDEX <TO> BLOCK-ID mapping. |
| 190 | 267 | preg_match_all('/cjtoolbox-(\d+)/', $metaBoxesOrder['normal'], $blocksOrder, PREG_SET_ORDER); |
| 268 | + /** | |
| 269 | + * append more to orders produced by CJTBlocksCouplingController::setRequestFilter(). | |
| 270 | + * More to orders may allow other blocks to bein the output (e.g metaboxe blocks). | |
| 271 | + */ | |
| 272 | + $blocksOrder = array_merge($blocksOrder, $this->getFilters()->moreToOrder); | |
| 191 | 273 | // Prepare request URL to match against Links & Expressions. |
| 192 | 274 | $linksRequestURL = self::getRequestURL(); |
| 193 | 275 | $expressionsRequestURL = "{$linksRequestURL}?{$_SERVER['QUERY_STRING']}"; |
| 194 | 276 | extract($this->onmatchingurls(compact('linksRequestURL', 'expressionsRequestURL'))); |
| @@ -235,12 +317,8 @@ | ||
| 235 | 317 | /// @TODO: Matches may be used later to evaulate variables inside code block. |
| 236 | 318 | if($matchedExpression = @preg_match("/{$expression}/", $expressionsRequestURL)) { |
| 237 | 319 | break; |
| 238 | 320 | } |
| 239 | - else if ($matchedExpression === false) { // Error | |
| 240 | - $message .= "<div style='background-color:red;font-size:20px;'>There are expression error in '{$block->name}' Block!! Expr=({$expression})</div>"; | |
| 241 | - echo($message); | |
| 242 | - } | |
| 243 | 321 | } |
| 244 | 322 | } |
| 245 | 323 | /** |
| 246 | 324 | * Exclude Links & Expressions Blocks that doesn't has a match. |
| @@ -249,10 +327,13 @@ | ||
| 249 | 327 | if ($this->oncancelmatching(!($matchedExpression || $matchedLink))) { |
| 250 | 328 | continue; |
| 251 | 329 | } |
| 252 | 330 | } |
| 331 | + // Retrieve block code-files. | |
| 332 | + $block->code = $this->model->getBlockCode($block->id); | |
| 333 | + // Import Executable (PHP and HTML) templates. | |
| 334 | + $block->code = $block->code . $this->model->getExecTemplatesCode($block->id); | |
| 253 | 335 | // For every location store blocks code into single string |
| 254 | - /** @todo Use method other data:// wrapper, its only available in Hight version of PHP (5.3 or so!) */ | |
| 255 | 336 | $evaluatedCode = CJTPHPCodeEvaluator::getInstance($block)->exec()->getOutput(); |
| 256 | 337 | /** @todo Include Debuging info only if we're in debuging mode! */ |
| 257 | 338 | if (1) { |
| 258 | 339 | $evaluatedCode = "\n<!-- Block ({$blockId}) START-->\n{$evaluatedCode}\n<!-- Block ({$blockId}) END -->\n"; |
| @@ -258,11 +339,18 @@ | ||
| 258 | 339 | $evaluatedCode = "\n<!-- Block ({$blockId}) START-->\n{$evaluatedCode}\n<!-- Block ({$blockId}) END -->\n"; |
| 259 | 340 | } |
| 260 | 341 | $this->blocks['code'][$block->location] .= $this->onappendcode($evaluatedCode); |
| 261 | 342 | // Store all used Ids in the CORRECT ORDER. |
| 262 | - $this->onActionIds[] = $blockId; | |
| 343 | + $this->addOnActionIds($blockId); | |
| 263 | 344 | } |
| 264 | 345 | } |
| 346 | + $templates = $this->onActionIds ? $this->model->getLinkedTemplates($this->onActionIds) : array(); | |
| 347 | + // Classisfy as we process Scripts and Styles separatly (different hooks!). | |
| 348 | + foreach ($this->onlinkedtemplates($templates) as $id => $template) { | |
| 349 | + // Filer template! | |
| 350 | + extract($this->onlinktemplate(compact('template', 'id'))); | |
| 351 | + $this->templates[$template->type][$id] = $template; | |
| 352 | + } | |
| 265 | 353 | // Return true if there is at least 1 block return within the set. |
| 266 | 354 | return true; |
| 267 | 355 | } |
| 268 | 356 | |
| @@ -281,13 +369,21 @@ | ||
| 281 | 369 | */ |
| 282 | 370 | public function getFilters() { |
| 283 | 371 | return $this->ongetfilters($this->filters); |
| 284 | 372 | } |
| 285 | - | |
| 373 | + | |
| 286 | 374 | /** |
| 287 | 375 | * put your comment there... |
| 288 | 376 | * |
| 289 | 377 | */ |
| 378 | + public function getOnActionIds() { | |
| 379 | + return $this->onActionIds; | |
| 380 | + } | |
| 381 | + | |
| 382 | + /** | |
| 383 | + * put your comment there... | |
| 384 | + * | |
| 385 | + */ | |
| 290 | 386 | public static function getRequestURL() { |
| 291 | 387 | // URL Protocol. |
| 292 | 388 | $protocol = 'http' . ((isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) ? 's' : '') . '://'; |
| 293 | 389 | // Host name & port. |
| @@ -303,8 +399,16 @@ | ||
| 303 | 399 | /** |
| 304 | 400 | * put your comment there... |
| 305 | 401 | * |
| 306 | 402 | */ |
| 403 | + public function hasOnActionIds() { | |
| 404 | + return !empty($this->onActionIds); | |
| 405 | + } | |
| 406 | + | |
| 407 | + /** | |
| 408 | + * put your comment there... | |
| 409 | + * | |
| 410 | + */ | |
| 307 | 411 | public function initCoupling() { |
| 308 | 412 | // For some reasons wp action is fired twice. |
| 309 | 413 | // The wrong call won't has $wp_query object set, |
| 310 | 414 | // but this is only valid at Front end. |
| @@ -310,17 +414,23 @@ | ||
| 310 | 414 | // but this is only valid at Front end. |
| 311 | 415 | if (!is_admin() && !$GLOBALS['wp_query']) { |
| 312 | 416 | return; |
| 313 | 417 | } |
| 418 | + // Get current application hook prefix. | |
| 419 | + $actionsPrefix = is_admin() ? 'admin' : 'wp'; | |
| 314 | 420 | // Get cache or get blocks if not cached. |
| 315 | 421 | // If there is no cache or no blocks for output |
| 316 | 422 | // do nothing. |
| 317 | 423 | if ($this->getCached() || $this->getBlocks()) { |
| 318 | - $actionsPrefix = is_admin() ? 'admin' : 'wp'; | |
| 319 | 424 | // Output blocks on various locations! |
| 320 | 425 | add_action("{$actionsPrefix}_head", array(&$this, 'outputBlocks'), 30); |
| 321 | 426 | add_action("{$actionsPrefix}_footer", array(&$this, 'outputBlocks'), 30); |
| 427 | + // Links templates & styloes! | |
| 428 | + add_action("{$actionsPrefix}_enqueue_scripts", array(&$this, 'linkTemplates'), 30); | |
| 429 | + add_action("{$actionsPrefix}_print_styles", array(&$this, 'linkTemplates'), 30); | |
| 322 | 430 | } |
| 431 | + // Link style sheet in footer required custom implementation. | |
| 432 | + add_action("{$actionsPrefix}_print_footer_scripts", array(&$this, 'linkFooterStyleSheets'), 9); | |
| 323 | 433 | // Make sure this is executed only once. |
| 324 | 434 | // Sometimes wp hook run on backend and sometimes its not. |
| 325 | 435 | // This method handle both front and backend requests. |
| 326 | 436 | // Simply remove all hooks to ensure its run only one time. |
| @@ -331,8 +441,71 @@ | ||
| 331 | 441 | /** |
| 332 | 442 | * put your comment there... |
| 333 | 443 | * |
| 334 | 444 | */ |
| 445 | + public function linkFooterStyleSheets() { | |
| 446 | + // Initialize. | |
| 447 | + $styles = array(); | |
| 448 | + // Get queued style sheets! | |
| 449 | + global $wp_styles; | |
| 450 | + $queuedStyles =& $wp_styles->queue; | |
| 451 | + // Process only 'cjt' templates, | |
| 452 | + foreach ($queuedStyles as $index => $styleName) { | |
| 453 | + if (strpos($styleName, 'cjt-css-template-') === 0) { | |
| 454 | + // Get style name src file, prepend to Wordpress absolute path. | |
| 455 | + $style = $wp_styles->registered[$styleName]; | |
| 456 | + $styles[] = home_url($style->src); | |
| 457 | + // Stop Wordpress from output <link> tag outside head tag | |
| 458 | + // as it has no effect. | |
| 459 | + unset($queuedStyles[$index]); | |
| 460 | + } | |
| 461 | + } | |
| 462 | + // Enqueue Style Sheet loader javascript if there is any | |
| 463 | + // styles need to be loaded. | |
| 464 | + if (!empty($styles)) { | |
| 465 | + // jQuery is dpendency object required by the loader. | |
| 466 | + wp_enqueue_script('jquery'); | |
| 467 | + // Enqueue footer style sheet loader. | |
| 468 | + wp_enqueue_script('cjt-coupling-footer-css-loader', cssJSToolbox::getURI('controllers:coupling:js:footer-stylesheet-loader.js')); | |
| 469 | + // Output Javascript array to be filled with the styles! | |
| 470 | + $jsStyleSheetsList = json_encode($styles); | |
| 471 | + require cssJSToolbox::resolvePath('controllers:coupling:html:load-footer-style.html.php'); | |
| 472 | + } | |
| 473 | + } | |
| 474 | + | |
| 475 | + /** | |
| 476 | + * put your comment there... | |
| 477 | + * | |
| 478 | + */ | |
| 479 | + public function linkTemplates() { | |
| 480 | + $currentFilter = current_filter(); | |
| 481 | + // Derived template Type from Wordpress filter. | |
| 482 | + $filterFor = explode('_', $currentFilter); $filterFor = array_pop($filterFor); | |
| 483 | + $type = CJTCouplingModel::$templateTypes[$filterFor]; | |
| 484 | + // Following vars are referenced based on the current type. | |
| 485 | + $templates = isset($this->templates[$type]) ? $this->templates[$type] : array(); | |
| 486 | + // Filering! | |
| 487 | + $templates = $this->{"onlink{$filterFor}"}($templates); | |
| 488 | + /** | |
| 489 | + * @var WP_Dependencies | |
| 490 | + */ | |
| 491 | + $queue = $this->model->getQueueObject($filterFor); | |
| 492 | + // Add templates to the queye. | |
| 493 | + foreach ($templates as $template) { | |
| 494 | + // Registery only if not yet registered. | |
| 495 | + $template = $this->{"onqueue{$type}"}($template); | |
| 496 | + if (!isset($queue->registered[$template->queueName])) { | |
| 497 | + $queue->add($template->queueName, "/{$template->file}", null, $template->version); | |
| 498 | + } | |
| 499 | + // Always make sure the template is queued. | |
| 500 | + $queue->enqueue($template->queueName); | |
| 501 | + } | |
| 502 | + } | |
| 503 | + | |
| 504 | + /** | |
| 505 | + * put your comment there... | |
| 506 | + * | |
| 507 | + */ | |
| 335 | 508 | public function outputBlocks() { |
| 336 | 509 | // Derived location name from wordpress filter name. |
| 337 | 510 | $currentFilter = current_filter(); |
| 338 | 511 | // Map "wp hook location" to "block hook location". |
| @@ -354,8 +527,9 @@ | ||
| 354 | 527 | // Get request blocks. |
| 355 | 528 | $filters = $this->ondefaultfilters((object) array( |
| 356 | 529 | 'pinPoint' => 0x00000000, |
| 357 | 530 | 'customPins' => array(), |
| 531 | + 'moreToOrder' => array(), | |
| 358 | 532 | )); |
| 359 | 533 | if (is_admin()) { |
| 360 | 534 | // Include all backend blocks. |
| 361 | 535 | $filters->pinPoint |= CJTBlockModel::PINS_BACKEND; |
| @@ -375,8 +549,15 @@ | ||
| 375 | 549 | // Blocks with FRONT-PAGE selected. |
| 376 | 550 | if (is_front_page()) { |
| 377 | 551 | $filters->pinPoint |= CJTBlockModel::PINS_PAGES_FRONT_PAGE; |
| 378 | 552 | } |
| 553 | + /** | |
| 554 | + * In order for metabox block to get in the output we need | |
| 555 | + * to add metabox order for it. | |
| 556 | + * @see CJTBlocksCouplingController::getBlocks. | |
| 557 | + */ | |
| 558 | + $metabox = CJTModel::create('metabox', array($GLOBALS['post']->ID)); | |
| 559 | + $filters->moreToOrder[][1] = $metabox->getMetaboxId(); | |
| 379 | 560 | } // End is_page() |
| 380 | 561 | else if (is_attachment()) { |
| 381 | 562 | $filters->pinPoint |= CJTBlockModel::PINS_ATTACHMENT; |
| 382 | 563 | } |
| @@ -405,8 +586,15 @@ | ||
| 405 | 586 | 'pins' => $parentCategoriesIds, |
| 406 | 587 | 'flag' => CJTBlockModel::PINS_CATEGORIES_CUSTOM_CATEGORY, |
| 407 | 588 | ); |
| 408 | 589 | } |
| 590 | + /** | |
| 591 | + * In order for metabox block to get in the output we need | |
| 592 | + * to add metabox order for it. | |
| 593 | + * @see CJTBlocksCouplingController::getBlocks. | |
| 594 | + */ | |
| 595 | + $metabox = CJTModel::create('metabox', array($GLOBALS['post']->ID)); | |
| 596 | + $filters->moreToOrder[][1] = $metabox->getMetaboxId(); | |
| 409 | 597 | /** |
| 410 | 598 | * @TODO check for recent posts Based on user configuration. |
| 411 | 599 | * Recent posts should be detcted by comparing |
| 412 | 600 | * user condifguration with post date. |
| @@ -449,53 +637,33 @@ | ||
| 449 | 637 | $this->filters = $this->onsetfilters($filters); |
| 450 | 638 | } |
| 451 | 639 | |
| 452 | 640 | /** |
| 641 | + * Wordpress do shortcode callback for | |
| 642 | + * CJT Shortcodes ([cjtoolbox ....])! | |
| 643 | + * | |
| 644 | + * This method role is to load the shortcode routines | |
| 645 | + * in order to handle the request. | |
| 646 | + * | |
| 647 | + * It doesn't do anything except deferring the shortcode | |
| 648 | + * codes from loaded until shortcode is really used! | |
| 649 | + * | |
| 650 | + * @param mixed $attributes | |
| 651 | + */ | |
| 652 | + public function shortcode($attributes, $content) { | |
| 653 | + // Instantiate Shortcode handler class. | |
| 654 | + cssJSToolbox::import('controllers:coupling:shortcode:shortcode.php'); | |
| 655 | + $shortcode = new CJT_Controllers_Coupling_Shortcode($attributes, $content); | |
| 656 | + // Return Shortcode replacement! | |
| 657 | + return ((string) $shortcode); | |
| 658 | + } | |
| 659 | + | |
| 660 | + /** | |
| 453 | 661 | * put your comment there... |
| 454 | 662 | * |
| 455 | - * @param mixed $attributes | |
| 456 | 663 | */ |
| 457 | - public function shortcode($attributes) { | |
| 458 | - // Initialize vars. | |
| 459 | - $replacement = ''; | |
| 460 | - // Default Class. | |
| 461 | - if (!$attributes['class']) { | |
| 462 | - $class = 'block'; | |
| 463 | - } | |
| 464 | - switch ($class) { | |
| 465 | - case 'block': | |
| 466 | - // Get is the default "operation"! | |
| 467 | - if (!$attributes['op']) { | |
| 468 | - $attributes['op'] = 'get'; | |
| 469 | - } | |
| 470 | - switch ($attributes['op']) { | |
| 471 | - case 'get': | |
| 472 | - // Import dependecies. | |
| 473 | - cssJSToolbox::import('framework:db:mysql:xtable.inc.php'); | |
| 474 | - // Output block if 'force="true" or only if it wasn't already in the header/footer! | |
| 475 | - if ((($attributes['force'] == "true") || !in_array($attributes['id'], $this->onActionIds))) { | |
| 476 | - // Id is being used! | |
| 477 | - if ($attributes['force'] != 'true') { | |
| 478 | - $this->onActionIds[] = (int) $attributes['id']; | |
| 479 | - } | |
| 480 | - // Get block code. | |
| 481 | - $block = CJTxTable::getInstance('block') | |
| 482 | - ->set('id', $attributes['id']) | |
| 483 | - ->load(); | |
| 484 | - // Only ACTIVE blocks! | |
| 485 | - if ($block->get('state') != 'active') { | |
| 486 | - return; | |
| 487 | - } | |
| 488 | - $replacement = $block->get('code'); | |
| 489 | - } | |
| 490 | - break; | |
| 491 | - } | |
| 492 | - break; | |
| 493 | - default: | |
| 494 | - $replacement = cssJSToolbox::getText('Shortcode Type is not supported!! Only (block) type is currently available!!!'); | |
| 495 | - break; | |
| 496 | - } | |
| 497 | - return $replacement; | |
| 664 | + public static function & theInstance() { | |
| 665 | + return self::$instance; | |
| 498 | 666 | } |
| 499 | 667 | |
| 500 | 668 | } // End class. |
| 501 | 669 | |