PluginProbe
CSS & JavaScript Toolbox / 8.0
CSS & JavaScript Toolbox v8.0
trunk 0.3 0.8 10 10.1 11 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9 11.9.1 12 12.0 12.0.1 12.0.3 12.0.4 12.0.5 12.0.6 12.0.7 6.0 6.0.11 All 60 releases
css-javascript-toolbox / controllers / blocks-coupling.php

blocks-coupling.php in CSS & JavaScript Toolbox 8.0, at controllers/blocks-coupling.php

681 lines 19.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version $ Id; blocks-coupling.php 21-03-2012 03:22:10 Ahmed Said $
4 */
5
6 // Disallow direct access.
7 defined('ABSPATH') or die("Access denied");
8
9 /**
10 * Applying Code blocks for the curren request.
11 *
12 * This controller is always loaded.
13 *
14 * The class resposibility is to output the code blocks
15 * tha associated with current request.
16 *
17 * @author Ahmed Said
18 * @version 6
19 */
20 class CJTBlocksCouplingController extends CJTController {
21
22 /**
23 * put your comment there...
24 *
25 * @var mixed
26 */
27 protected $blocks = array(
28 'code' => array('header' => '', 'footer' => ''),
29 'scripts' => array('header' => array(), 'footer' => array()),
30 );
31
32 /**
33 * put your comment there...
34 *
35 * @var mixed
36 */
37 protected $controllerInfo = array('model' => 'coupling');
38
39 /**
40 * put your comment there...
41 *
42 * @var mixed
43 */
44 protected $filters = null;
45
46 /**
47 * put your comment there...
48 *
49 * @var mixed
50 */
51 protected static $instance = null;
52
53 /**
54 * put your comment there...
55 *
56 * @var mixed
57 */
58 private $onActionIds = array();
59
60 /**
61 * put your comment there...
62 *
63 * @var mixed
64 */
65 protected $onassigncouplingcallback = array('parameters' => array('callback'));
66
67 /**
68 * put your comment there...
69 *
70 * @var mixed
71 */
72 protected $onappendcode = array('parameters' => array('code'));
73
74 /**
75 * put your comment there...
76 *
77 * @var mixed
78 */
79 protected $onblockmatched = array('parameters' => array('block'));
80
81 /**
82 * put your comment there...
83 *
84 * @var mixed
85 */
86 protected $oncancelmatching = array('parameters' => array('matched'));
87
88 /**
89 * put your comment there...
90 *
91 * @var mixed
92 */
93 protected $ondefaultfilters = array('parameters' => array('filters'));
94
95 /**
96 * put your comment there...
97 *
98 * @var mixed
99 */
100 protected $ondo = array('parameters' => array('data', 'method', 'condition'));
101
102 /**
103 * put your comment there...
104 *
105 * @var mixed
106 */
107 protected $onblocksorder = array('parameters' => array('order'));
108
109 /**
110 * put your comment there...
111 *
112 * @var mixed
113 */
114 protected $ongetblocks = array('parameters' => array('blocks'));
115
116 /**
117 * put your comment there...
118 *
119 * @var mixed
120 */
121 protected $ongetcache = array('parameters' => array('cache'));
122
123 /**
124 * put your comment there...
125 *
126 * @var mixed
127 */
128 protected $ongetfilters = array('parameters' => array('filters'));
129
130 /**
131 * put your comment there...
132 *
133 * @var mixed
134 */
135 protected $onlinkedtemplates = array('parameters' => array('templates'));
136
137 /**
138 * put your comment there...
139 *
140 * @var mixed
141 */
142 protected $onlinkscripts = array('parameters' => array('templates'));
143
144 /**
145 * put your comment there...
146 *
147 * @var mixed
148 */
149 protected $onlinkstyles = array('parameters' => array('templates'));
150
151 /**
152 * put your comment there...
153 *
154 * @var mixed
155 */
156 protected $onlinktemplate = array('parameters' => array('template'));
157
158 /**
159 * put your comment there...
160 *
161 * @var mixed
162 */
163 protected $onmatchingurls = array('parameters' => array('urls'));
164
165 /**
166 * put your comment there...
167 *
168 * @var mixed
169 */
170 protected $onnoblocks = array('hookType' => CJTWordpressEvents::HOOK_ACTION);
171
172 /**
173 * put your comment there...
174 *
175 * @var mixed
176 */
177 protected $onoutput = array('parameters' => array('code', 'location'));
178
179 /**
180 * put your comment there...
181 *
182 * @var mixed
183 */
184 protected $onprocess = array('hookType' => CJTWordpressEvents::HOOK_ACTION);
185
186 /**
187 * put your comment there...
188 *
189 * @var mixed
190 */
191 protected $onprocessblock = array('parameters' => array('block'));
192
193 /**
194 * put your comment there...
195 *
196 * @var mixed
197 */
198 protected $onqueuecss = array('parameters' => array('style'));
199
200 /**
201 * put your comment there...
202 *
203 * @var mixed
204 */
205 protected $onqueuejavascript = array('parameters' => array('script'));
206
207 /**
208 * put your comment there...
209 *
210 * @var mixed
211 */
212 protected $onsetfilters = array('parameters' => array('filters'));
213
214 /**
215 * put your comment there...
216 *
217 * @var mixed
218 */
219 protected $templates = array();
220
221 /**
222 * Initialize controller object.
223 *
224 * @see CJTController for more details
225 * @return void
226 */
227 public function __construct() {
228 // Only one instance is allowed.
229 if (self::$instance) {
230 throw new Exception('Trying to instantiate multiple coupling instances!!');
231 }
232 // Hold the single instance we've!
233 self::$instance = $this;
234 $siteHook = cssJSToolbox::$config->core->siteHook;
235 // Initialize controller.
236 parent::__construct(false);
237 // Import related libraries
238 CJTModel::import('block');
239 // Not default action needed.
240 $this->defaultAction = null;
241 // Initialize controller.
242 $initCouplingCallback = $this->onassigncouplingcallback(array(&$this, 'initCoupling'));
243 add_action('admin_init', $initCouplingCallback);
244 add_action($siteHook->tag, $initCouplingCallback, $siteHook->priority);
245 // Add Shortcode callbacks.
246 add_shortcode('cjtoolbox', array(&$this, 'shortcode'));
247 }
248
249 /**
250 * put your comment there...
251 *
252 * @param mixed $id
253 */
254 public function addOnActionIds($id) {
255 // Add ID is not exists.
256 if (!in_array($id, $this->onActionIds)) {
257 $this->onActionIds[] = $id;
258 }
259 // Chaining.
260 return $this;
261 }
262
263 /**
264 * put your comment there...
265 *
266 */
267 public function getBlocks() {
268 // Set request view filters used for querying database.
269 $this->setRequestFilters();
270 // Get blocks order. NOTE: This is all blocks order not only the queried/target blocks.
271 $blocksOrder = array();
272 $metaBoxesOrder = $this->onblocksorder($this->model->getOrder());
273 // Get ORDER-INDEX <TO> BLOCK-ID mapping.
274 preg_match_all('/cjtoolbox-(\d+)/', $metaBoxesOrder['normal'], $blocksOrder, PREG_SET_ORDER);
275 /**
276 * append more to orders produced by CJTBlocksCouplingController::setRequestFilter().
277 * More to orders may allow other blocks to bein the output (e.g metaboxe blocks).
278 */
279 $blocksOrder = array_merge($blocksOrder, $this->getFilters()->moreToOrder);
280 // Prepare request URL to match against Links & Expressions.
281 $linksRequestURL = self::getRequestURL();
282 $expressionsRequestURL = "{$linksRequestURL}?{$_SERVER['QUERY_STRING']}";
283 extract($this->onmatchingurls(compact('linksRequestURL', 'expressionsRequestURL')));
284 // Get all blocks including (Links & Expressions Blocks).
285 $blocks = $this->ongetblocks($this->model->getPinsBlocks(CJTBlockModel::PINS_LINK_EXPRESSION,
286 $this->getFilters()->pinPoint,
287 $this->getFilters()->customPins));
288 if (empty($blocks)) {
289 $this->onnoblocks();
290 return false;
291 }
292 // Import related libraries.
293 cssJSToolbox::import('framework:php:evaluator:evaluator.inc.php');
294 /**
295 * Iterator over all blocks by using they order.
296 * For each block get code and scripts.
297 */
298 $this->onprocess();
299 foreach ($blocksOrder as $blockOrder) {
300 $blockId = (int) $blockOrder[1];
301 // As mentioned above. Orders is for all blocks not just those queried from db.
302 if (isset($blocks[$blockId])) {
303 $block = $this->onprocessblock($blocks[$blockId]);
304 /**
305 * Process Links & Expressions blocks.
306 * For better performace check only those with links and expressions flags.
307 */
308 if ($block->blocksGroup & CJTBlockModel::PINS_LINK_EXPRESSION) {
309 /**
310 * Initiliaze $matchedLink and $matchedExpression inside IF statment.
311 * Those variables need to refresh state at each block.
312 * If there is no link or expression flags, they will be FALSE.
313 * Otherwise they'll get the correct value inside each statement.
314 */
315 /// Check if there is a matched link.
316 if ($matchedLink = ($block->blocksGroup & CJTBlockModel::PINS_LINKS)) {
317 $links = explode("\n", trim($block->links));
318 $matchedLink = in_array($linksRequestURL, $links);
319 }
320 /// Check if there is a matched expression.
321 if ($matchedExpression = ($block->blocksGroup & CJTBlockModel::PINS_EXPRESSIONS)) {
322 $expressions = explode("\n", $block->expressions);
323 foreach ($expressions as $expression) {
324 /// @TODO: Matches may be used later to evaulate variables inside code block.
325 if($matchedExpression = @preg_match("/{$expression}/", $expressionsRequestURL)) {
326 break;
327 }
328 }
329 }
330 /**
331 * Exclude Links & Expressions Blocks that doesn't has a match.
332 * If there is no matched link or expression then exclude block.
333 */
334 if ($this->oncancelmatching(!($matchedExpression || $matchedLink))) {
335 continue;
336 }
337 }
338 // Allow extensions to control to prevent block from being in the output
339 if ($block = $this->onblockmatched($block)) {
340 // Retrieve block code-files.
341 $block->code = $this->model->getBlockCode($block->id);
342 // Import Executable (PHP and HTML) templates.
343 $block->code = $block->code . $this->model->getExecTemplatesCode($block->id);
344 // For every location store blocks code into single string
345 $evaluatedCode = CJTPHPCodeEvaluator::getInstance($block)->exec()->getOutput();
346 /** @todo Include Debuging info only if we're in debuging mode! */
347 if (1) {
348 $evaluatedCode = "\n<!-- Block ({$blockId}) START-->\n{$evaluatedCode}\n<!-- Block ({$blockId}) END -->\n";
349 }
350 $this->blocks['code'][$block->location] .= $this->onappendcode($evaluatedCode);
351 // Store all used Ids in the CORRECT ORDER.
352 $this->addOnActionIds($blockId);
353 }
354 }
355 }
356 $templates = $this->onActionIds ? $this->model->getLinkedTemplates($this->onActionIds) : array();
357 // Classisfy as we process Scripts and Styles separatly (different hooks!).
358 foreach ($this->onlinkedtemplates($templates) as $id => $template) {
359 // Filer template!
360 extract($this->onlinktemplate(compact('template', 'id')));
361 $this->templates[$template->type][$id] = $template;
362 }
363 // Return true if there is at least 1 block return within the set.
364 return true;
365 }
366
367 /**
368 * put your comment there...
369 *
370 */
371 public function getCached() {
372 // Cache is not implemented yet might be supported by extenal Extensions!
373 return $this->ongetcache(false);
374 }
375
376 /**
377 * put your comment there...
378 *
379 */
380 public function getFilters() {
381 return $this->ongetfilters($this->filters);
382 }
383
384 /**
385 * put your comment there...
386 *
387 */
388 public function getOnActionIds() {
389 return $this->onActionIds;
390 }
391
392 /**
393 * put your comment there...
394 *
395 */
396 public static function getRequestURL() {
397 // URL Protocol.
398 $protocol = 'http' . ((isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) ? 's' : '') . '://';
399 // Host name & port.
400 $host = $_SERVER['HTTP_HOST'];
401 $port = ($_SERVER["SERVER_PORT"] != "80") ? ":{$_SERVER["SERVER_PORT"]}" : '';
402 // Request URI.
403 $requestURI = $_SERVER['REQUEST_URI'];
404 // Final URL.
405 $url = "{$protocol}{$host}{$port}{$requestURI}";
406 return $url;
407 }
408
409 /**
410 * put your comment there...
411 *
412 */
413 public function hasOnActionIds() {
414 return !empty($this->onActionIds);
415 }
416
417 /**
418 * put your comment there...
419 *
420 */
421 public function initCoupling() {
422 // For some reasons wp action is fired twice.
423 // The wrong call won't has $wp_query object set,
424 // but this is only valid at Front end.
425 if (!is_admin() && !$GLOBALS['wp_query']) {
426 return;
427 }
428 // Get current application hook prefix.
429 $actionsPrefix = is_admin() ? 'admin' : 'wp';
430 // Get cache or get blocks if not cached.
431 // If there is no cache or no blocks for output
432 // do nothing.
433 if ($this->getCached() || $this->getBlocks()) {
434 // Output blocks on various locations!
435 add_action("{$actionsPrefix}_head", array(&$this, 'outputBlocks'), 30);
436 add_action("{$actionsPrefix}_footer", array(&$this, 'outputBlocks'), 30);
437 // Links templates & styloes!
438 add_action("{$actionsPrefix}_enqueue_scripts", array(&$this, 'linkTemplates'), 30);
439 add_action("{$actionsPrefix}_print_styles", array(&$this, 'linkTemplates'), 30);
440 }
441 // Link style sheet in footer required custom implementation.
442 add_action("{$actionsPrefix}_print_footer_scripts", array(&$this, 'linkFooterStyleSheets'), 9);
443 // Make sure this is executed only once.
444 // Sometimes wp hook run on backend and sometimes its not.
445 // This method handle both front and backend requests.
446 // Simply remove all hooks to ensure its run only one time.
447 remove_action('wp', array(&$this, 'initCoupling'));
448 remove_action('admin_init', array(&$this, 'initCoupling'));
449 }
450
451 /**
452 * put your comment there...
453 *
454 */
455 public function linkFooterStyleSheets() {
456 // Initialize.
457 $styles = array();
458 // Get queued style sheets!
459 global $wp_styles;
460 $queuedStyles =& $wp_styles->queue;
461 // Process only 'cjt' templates,
462 foreach ($queuedStyles as $index => $styleName) {
463 if (strpos($styleName, 'cjt-css-template-') === 0) {
464 // Get style name src file, prepend to Wordpress absolute path.
465 $style = $wp_styles->registered[$styleName];
466 $styles[] = home_url($style->src);
467 // Stop Wordpress from output <link> tag outside head tag
468 // as it has no effect.
469 unset($queuedStyles[$index]);
470 }
471 }
472 // Enqueue Style Sheet loader javascript if there is any
473 // styles need to be loaded.
474 if (!empty($styles)) {
475 // jQuery is dpendency object required by the loader.
476 wp_enqueue_script('jquery');
477 // Enqueue footer style sheet loader.
478 wp_enqueue_script('cjt-coupling-footer-css-loader', cssJSToolbox::getURI('controllers:coupling:js:footer-stylesheet-loader.js'));
479 // Output Javascript array to be filled with the styles!
480 $jsStyleSheetsList = json_encode($styles);
481 require cssJSToolbox::resolvePath('controllers:coupling:html:load-footer-style.html.php');
482 }
483 }
484
485 /**
486 * put your comment there...
487 *
488 */
489 public function linkTemplates() {
490 $currentFilter = current_filter();
491 // Derived template Type from Wordpress filter.
492 $filterFor = explode('_', $currentFilter); $filterFor = array_pop($filterFor);
493 $type = CJTCouplingModel::$templateTypes[$filterFor];
494 // Following vars are referenced based on the current type.
495 $templates = isset($this->templates[$type]) ? $this->templates[$type] : array();
496 // Filering!
497 $templates = $this->{"onlink{$filterFor}"}($templates);
498 /**
499 * @var WP_Dependencies
500 */
501 $queue = $this->model->getQueueObject($filterFor);
502 // Add templates to the queye.
503 foreach ($templates as $template) {
504 // Registery only if not yet registered.
505 $template = $this->{"onqueue{$type}"}($template);
506 if (!isset($queue->registered[$template->queueName])) {
507 $queue->add($template->queueName, "/{$template->file}", null, $template->version);
508 }
509 // Always make sure the template is queued.
510 $queue->enqueue($template->queueName);
511 }
512 }
513
514 /**
515 * put your comment there...
516 *
517 */
518 public function outputBlocks() {
519 // Derived location name from wordpress filter name.
520 $currentFilter = current_filter();
521 // Map "wp hook location" to "block hook location".
522 $locationsMap = array('head' => 'header', 'footer' => 'footer');
523 // This hook is used across both ends, front and back ends.
524 // Remove application prefix (wp_ or admin_).
525 // Remining is head or footer.
526 $location = str_replace(array('wp_', 'admin_'), '', $currentFilter);
527 // Map to block location.
528 $location = $locationsMap[$location];
529 echo $this->onoutput($this->blocks['code'][$location], $location);
530 }
531
532 /**
533 * put your comment there...
534 *
535 */
536 protected function setRequestFilters() {
537 // Get request blocks.
538 $filters = $this->ondefaultfilters((object) array(
539 'pinPoint' => 0x00000000,
540 'customPins' => array(),
541 'moreToOrder' => array(),
542 ));
543 if (is_admin()) {
544 // Include all backend blocks.
545 $filters->pinPoint |= CJTBlockModel::PINS_BACKEND;
546 }
547 else {
548 $filters->pinPoint |= CJTBlockModel::PINS_FRONTEND;
549 // Pages.
550 if (is_page()) {
551 // Blocks with ALL PAGES selected.
552 $filters->pinPoint |= CJTBlockModel::PINS_PAGES_ALL_PAGES;
553 // Blocks with PAGE-ID selected.
554 $filters->customPins[] = array(
555 'pin' => 'pages',
556 'pins' => array($GLOBALS['post']->ID),
557 'flag' => CJTBlockModel::PINS_PAGES_CUSTOM_PAGE,
558 );
559 // Blocks with FRONT-PAGE selected.
560 if (is_front_page()) {
561 $filters->pinPoint |= CJTBlockModel::PINS_PAGES_FRONT_PAGE;
562 }
563 /**
564 * In order for metabox block to get in the output we need
565 * to add metabox order for it.
566 * @see CJTBlocksCouplingController::getBlocks.
567 */
568 $metabox = CJTModel::create('metabox', array($GLOBALS['post']->ID));
569 $filters->moreToOrder[][1] = $metabox->getMetaboxId();
570 } // End is_page()
571 else if (is_attachment()) {
572 $filters->pinPoint |= CJTBlockModel::PINS_ATTACHMENT;
573 }
574 // Posts.
575 else if (is_single()) {
576 // Blocks with ALL POSTS & ALL CATEGORIES selected.
577 $filters->pinPoint |= CJTBlockModel::PINS_POSTS_ALL_POSTS | CJTBlockModel::PINS_CATEGORIES_ALL_CATEGORIES;
578 // Blocks with POST-ID selected.
579 $filters->customPins[] = array(
580 'pin' => 'posts',
581 'pins' => array($GLOBALS['post']->ID),
582 'flag' => CJTBlockModel::PINS_POSTS_CUSTOM_POST,
583 );
584 // Include POST PARENT CATRGORIES blocks.
585 $parentCategoriesIds = wp_get_post_categories($GLOBALS['post']->ID, array('fields' => 'ids'));
586 /**
587 * Custom-Posts just added "ON THE RUN/FLY"
588 * Need simple fix by confirming that the post is belong to
589 * specific category or not.
590 * Custom posts NOW unlike Posts, it doesn't inherit parent
591 * taxonomis Code Blocks!!
592 */
593 if (!empty($parentCategoriesIds)) {
594 $filters->customPins[] = array(
595 'pin' => 'categories',
596 'pins' => $parentCategoriesIds,
597 'flag' => CJTBlockModel::PINS_CATEGORIES_CUSTOM_CATEGORY,
598 );
599 }
600 /**
601 * In order for metabox block to get in the output we need
602 * to add metabox order for it.
603 * @see CJTBlocksCouplingController::getBlocks.
604 */
605 $metabox = CJTModel::create('metabox', array($GLOBALS['post']->ID));
606 $filters->moreToOrder[][1] = $metabox->getMetaboxId();
607 /**
608 * @TODO check for recent posts Based on user configuration.
609 * Recent posts should be detcted by comparing
610 * user condifguration with post date.
611 */
612 if (0) {
613
614 }
615 } // End is_single()
616 // Categories.
617 else if(is_category()) {
618 // Blocks with ALL CATEGORIES selected.
619 $filters->pinPoint |= CJTBlockModel::PINS_CATEGORIES_ALL_CATEGORIES;
620 // Blocks with CATEGORY-ID selected.
621 $filters->customPins[] = array(
622 'pin' => 'categories',
623 'pins' => array(get_queried_object()->term_id),
624 'flag' => CJTBlockModel::PINS_CATEGORIES_CUSTOM_CATEGORY,
625 );
626 } // End is_category()
627 // Blocks with BLOG-INDEX selected.
628 else if (is_home()) {
629 $filters->pinPoint |= CJTBlockModel::PINS_POSTS_BLOG_INDEX;
630 }
631 else if (is_search()) {
632 $filters->pinPoint |= CJTBlockModel::PINS_SEARCH;
633 }
634 else if (is_tag()) {
635 $filters->pinPoint |= CJTBlockModel::PINS_TAG;
636 }
637 else if (is_author()) {
638 $filters->pinPoint |= CJTBlockModel::PINS_AUTHOR;
639 }
640 else if (is_archive()) {
641 $filters->pinPoint |= CJTBlockModel::PINS_ARCHIVE;
642 }
643 else if (is_404()) {
644 $filters->pinPoint |= CJTBlockModel::PINS_404_ERROR;
645 }
646 }
647 $this->filters = $this->onsetfilters($filters);
648 }
649
650 /**
651 * Wordpress do shortcode callback for
652 * CJT Shortcodes ([cjtoolbox ....])!
653 *
654 * This method role is to load the shortcode routines
655 * in order to handle the request.
656 *
657 * It doesn't do anything except deferring the shortcode
658 * codes from loaded until shortcode is really used!
659 *
660 * @param mixed $attributes
661 */
662 public function shortcode($attributes, $content) {
663 // Instantiate Shortcode handler class.
664 cssJSToolbox::import('controllers:coupling:shortcode:shortcode.php');
665 $shortcode = new CJT_Controllers_Coupling_Shortcode($attributes, $content);
666 // Return Shortcode replacement!
667 return ((string) $shortcode);
668 }
669
670 /**
671 * put your comment there...
672 *
673 */
674 public static function & theInstance() {
675 return self::$instance;
676 }
677
678 } // End class.
679
680 // Hookable!
681 CJTBlocksCouplingController::define('CJTBlocksCouplingController', array('hookType' => CJTWordpressEvents::HOOK_FILTER));