PluginProbe
CSS & JavaScript Toolbox / 7.1
CSS & JavaScript Toolbox v7.1
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 7.1, at controllers/blocks-coupling.php

671 lines 19.2 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 $oncancelmatching = array('parameters' => array('matched'));
80
81 /**
82 * put your comment there...
83 *
84 * @var mixed
85 */
86 protected $ondefaultfilters = array('parameters' => array('filters'));
87
88 /**
89 * put your comment there...
90 *
91 * @var mixed
92 */
93 protected $ondo = array('parameters' => array('data', 'method', 'condition'));
94
95 /**
96 * put your comment there...
97 *
98 * @var mixed
99 */
100 protected $onblocksorder = array('parameters' => array('order'));
101
102 /**
103 * put your comment there...
104 *
105 * @var mixed
106 */
107 protected $ongetblocks = array('parameters' => array('blocks'));
108
109 /**
110 * put your comment there...
111 *
112 * @var mixed
113 */
114 protected $ongetcache = array('parameters' => array('cache'));
115
116 /**
117 * put your comment there...
118 *
119 * @var mixed
120 */
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'));
129
130 /**
131 * put your comment there...
132 *
133 * @var mixed
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 */
156 protected $onmatchingurls = array('parameters' => array('urls'));
157
158 /**
159 * put your comment there...
160 *
161 * @var mixed
162 */
163 protected $onnoblocks = array('hookType' => CJTWordpressEvents::HOOK_ACTION);
164
165 /**
166 * put your comment there...
167 *
168 * @var mixed
169 */
170 protected $onoutput = array('parameters' => array('code', 'location'));
171
172 /**
173 * put your comment there...
174 *
175 * @var mixed
176 */
177 protected $onprocess = array('hookType' => CJTWordpressEvents::HOOK_ACTION);
178
179 /**
180 * put your comment there...
181 *
182 * @var mixed
183 */
184 protected $onprocessblock = array('parameters' => array('block'));
185
186 /**
187 * put your comment there...
188 *
189 * @var mixed
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 */
205 protected $onsetfilters = array('parameters' => array('filters'));
206
207 /**
208 * put your comment there...
209 *
210 * @var mixed
211 */
212 protected $templates = array();
213
214 /**
215 * Initialize controller object.
216 *
217 * @see CJTController for more details
218 * @return void
219 */
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;
228 // Initialize controller.
229 parent::__construct(false);
230 // Import related libraries
231 CJTModel::import('block');
232 // Not default action needed.
233 $this->defaultAction = null;
234 // Initialize controller.
235 $initCouplingCallback = $this->onassigncouplingcallback(array(&$this, 'initCoupling'));
236 add_action('admin_init', $initCouplingCallback);
237 add_action($siteHook->tag, $initCouplingCallback, $siteHook->priority);
238 // Add Shortcode callbacks.
239 add_shortcode('cjtoolbox', array(&$this, 'shortcode'));
240 }
241
242 /**
243 * put your comment there...
244 *
245 * @param mixed $id
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 */
260 public function getBlocks() {
261 // Set request view filters used for querying database.
262 $this->setRequestFilters();
263 // Get blocks order. NOTE: This is all blocks order not only the queried/target blocks.
264 $blocksOrder = array();
265 $metaBoxesOrder = $this->onblocksorder($this->model->getOrder());
266 // Get ORDER-INDEX <TO> BLOCK-ID mapping.
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);
273 // Prepare request URL to match against Links & Expressions.
274 $linksRequestURL = self::getRequestURL();
275 $expressionsRequestURL = "{$linksRequestURL}?{$_SERVER['QUERY_STRING']}";
276 extract($this->onmatchingurls(compact('linksRequestURL', 'expressionsRequestURL')));
277 // Get all blocks including (Links & Expressions Blocks).
278 $blocks = $this->ongetblocks($this->model->getPinsBlocks(CJTBlockModel::PINS_LINK_EXPRESSION,
279 $this->getFilters()->pinPoint,
280 $this->getFilters()->customPins));
281 if (empty($blocks)) {
282 $this->onnoblocks();
283 return false;
284 }
285 // Import related libraries.
286 cssJSToolbox::import('framework:php:evaluator:evaluator.inc.php');
287 /**
288 * Iterator over all blocks by using they order.
289 * For each block get code and scripts.
290 */
291 $this->onprocess();
292 foreach ($blocksOrder as $blockOrder) {
293 $blockId = (int) $blockOrder[1];
294 // As mentioned above. Orders is for all blocks not just those queried from db.
295 if (isset($blocks[$blockId])) {
296 $block = $this->onprocessblock($blocks[$blockId]);
297 /**
298 * Process Links & Expressions blocks.
299 * For better performace check only those with links and expressions flags.
300 */
301 if ($block->blocksGroup & CJTBlockModel::PINS_LINK_EXPRESSION) {
302 /**
303 * Initiliaze $matchedLink and $matchedExpression inside IF statment.
304 * Those variables need to refresh state at each block.
305 * If there is no link or expression flags, they will be FALSE.
306 * Otherwise they'll get the correct value inside each statement.
307 */
308 /// Check if there is a matched link.
309 if ($matchedLink = ($block->blocksGroup & CJTBlockModel::PINS_LINKS)) {
310 $links = explode("\n", trim($block->links));
311 $matchedLink = in_array($linksRequestURL, $links);
312 }
313 /// Check if there is a matched expression.
314 if ($matchedExpression = ($block->blocksGroup & CJTBlockModel::PINS_EXPRESSIONS)) {
315 $expressions = explode("\n", $block->expressions);
316 foreach ($expressions as $expression) {
317 /// @TODO: Matches may be used later to evaulate variables inside code block.
318 if($matchedExpression = @preg_match("/{$expression}/", $expressionsRequestURL)) {
319 break;
320 }
321 }
322 }
323 /**
324 * Exclude Links & Expressions Blocks that doesn't has a match.
325 * If there is no matched link or expression then exclude block.
326 */
327 if ($this->oncancelmatching(!($matchedExpression || $matchedLink))) {
328 continue;
329 }
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);
335 // For every location store blocks code into single string
336 $evaluatedCode = CJTPHPCodeEvaluator::getInstance($block)->exec()->getOutput();
337 /** @todo Include Debuging info only if we're in debuging mode! */
338 if (1) {
339 $evaluatedCode = "\n<!-- Block ({$blockId}) START-->\n{$evaluatedCode}\n<!-- Block ({$blockId}) END -->\n";
340 }
341 $this->blocks['code'][$block->location] .= $this->onappendcode($evaluatedCode);
342 // Store all used Ids in the CORRECT ORDER.
343 $this->addOnActionIds($blockId);
344 }
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 }
353 // Return true if there is at least 1 block return within the set.
354 return true;
355 }
356
357 /**
358 * put your comment there...
359 *
360 */
361 public function getCached() {
362 // Cache is not implemented yet might be supported by extenal Extensions!
363 return $this->ongetcache(false);
364 }
365
366 /**
367 * put your comment there...
368 *
369 */
370 public function getFilters() {
371 return $this->ongetfilters($this->filters);
372 }
373
374 /**
375 * put your comment there...
376 *
377 */
378 public function getOnActionIds() {
379 return $this->onActionIds;
380 }
381
382 /**
383 * put your comment there...
384 *
385 */
386 public static function getRequestURL() {
387 // URL Protocol.
388 $protocol = 'http' . ((isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) ? 's' : '') . '://';
389 // Host name & port.
390 $host = $_SERVER['HTTP_HOST'];
391 $port = ($_SERVER["SERVER_PORT"] != "80") ? ":{$_SERVER["SERVER_PORT"]}" : '';
392 // Request URI.
393 $requestURI = $_SERVER['REQUEST_URI'];
394 // Final URL.
395 $url = "{$protocol}{$host}{$port}{$requestURI}";
396 return $url;
397 }
398
399 /**
400 * put your comment there...
401 *
402 */
403 public function hasOnActionIds() {
404 return !empty($this->onActionIds);
405 }
406
407 /**
408 * put your comment there...
409 *
410 */
411 public function initCoupling() {
412 // For some reasons wp action is fired twice.
413 // The wrong call won't has $wp_query object set,
414 // but this is only valid at Front end.
415 if (!is_admin() && !$GLOBALS['wp_query']) {
416 return;
417 }
418 // Get current application hook prefix.
419 $actionsPrefix = is_admin() ? 'admin' : 'wp';
420 // Get cache or get blocks if not cached.
421 // If there is no cache or no blocks for output
422 // do nothing.
423 if ($this->getCached() || $this->getBlocks()) {
424 // Output blocks on various locations!
425 add_action("{$actionsPrefix}_head", array(&$this, 'outputBlocks'), 30);
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);
430 }
431 // Link style sheet in footer required custom implementation.
432 add_action("{$actionsPrefix}_print_footer_scripts", array(&$this, 'linkFooterStyleSheets'), 9);
433 // Make sure this is executed only once.
434 // Sometimes wp hook run on backend and sometimes its not.
435 // This method handle both front and backend requests.
436 // Simply remove all hooks to ensure its run only one time.
437 remove_action('wp', array(&$this, 'initCoupling'));
438 remove_action('admin_init', array(&$this, 'initCoupling'));
439 }
440
441 /**
442 * put your comment there...
443 *
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 */
508 public function outputBlocks() {
509 // Derived location name from wordpress filter name.
510 $currentFilter = current_filter();
511 // Map "wp hook location" to "block hook location".
512 $locationsMap = array('head' => 'header', 'footer' => 'footer');
513 // This hook is used across both ends, front and back ends.
514 // Remove application prefix (wp_ or admin_).
515 // Remining is head or footer.
516 $location = str_replace(array('wp_', 'admin_'), '', $currentFilter);
517 // Map to block location.
518 $location = $locationsMap[$location];
519 echo $this->onoutput($this->blocks['code'][$location], $location);
520 }
521
522 /**
523 * put your comment there...
524 *
525 */
526 protected function setRequestFilters() {
527 // Get request blocks.
528 $filters = $this->ondefaultfilters((object) array(
529 'pinPoint' => 0x00000000,
530 'customPins' => array(),
531 'moreToOrder' => array(),
532 ));
533 if (is_admin()) {
534 // Include all backend blocks.
535 $filters->pinPoint |= CJTBlockModel::PINS_BACKEND;
536 }
537 else {
538 $filters->pinPoint |= CJTBlockModel::PINS_FRONTEND;
539 // Pages.
540 if (is_page()) {
541 // Blocks with ALL PAGES selected.
542 $filters->pinPoint |= CJTBlockModel::PINS_PAGES_ALL_PAGES;
543 // Blocks with PAGE-ID selected.
544 $filters->customPins[] = array(
545 'pin' => 'pages',
546 'pins' => array($GLOBALS['post']->ID),
547 'flag' => CJTBlockModel::PINS_PAGES_CUSTOM_PAGE,
548 );
549 // Blocks with FRONT-PAGE selected.
550 if (is_front_page()) {
551 $filters->pinPoint |= CJTBlockModel::PINS_PAGES_FRONT_PAGE;
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();
560 } // End is_page()
561 else if (is_attachment()) {
562 $filters->pinPoint |= CJTBlockModel::PINS_ATTACHMENT;
563 }
564 // Posts.
565 else if (is_single()) {
566 // Blocks with ALL POSTS & ALL CATEGORIES selected.
567 $filters->pinPoint |= CJTBlockModel::PINS_POSTS_ALL_POSTS | CJTBlockModel::PINS_CATEGORIES_ALL_CATEGORIES;
568 // Blocks with POST-ID selected.
569 $filters->customPins[] = array(
570 'pin' => 'posts',
571 'pins' => array($GLOBALS['post']->ID),
572 'flag' => CJTBlockModel::PINS_POSTS_CUSTOM_POST,
573 );
574 // Include POST PARENT CATRGORIES blocks.
575 $parentCategoriesIds = wp_get_post_categories($GLOBALS['post']->ID, array('fields' => 'ids'));
576 /**
577 * Custom-Posts just added "ON THE RUN/FLY"
578 * Need simple fix by confirming that the post is belong to
579 * specific category or not.
580 * Custom posts NOW unlike Posts, it doesn't inherit parent
581 * taxonomis Code Blocks!!
582 */
583 if (!empty($parentCategoriesIds)) {
584 $filters->customPins[] = array(
585 'pin' => 'categories',
586 'pins' => $parentCategoriesIds,
587 'flag' => CJTBlockModel::PINS_CATEGORIES_CUSTOM_CATEGORY,
588 );
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();
597 /**
598 * @TODO check for recent posts Based on user configuration.
599 * Recent posts should be detcted by comparing
600 * user condifguration with post date.
601 */
602 if (0) {
603
604 }
605 } // End is_single()
606 // Categories.
607 else if(is_category()) {
608 // Blocks with ALL CATEGORIES selected.
609 $filters->pinPoint |= CJTBlockModel::PINS_CATEGORIES_ALL_CATEGORIES;
610 // Blocks with CATEGORY-ID selected.
611 $filters->customPins[] = array(
612 'pin' => 'categories',
613 'pins' => array(get_queried_object()->term_id),
614 'flag' => CJTBlockModel::PINS_CATEGORIES_CUSTOM_CATEGORY,
615 );
616 } // End is_category()
617 // Blocks with BLOG-INDEX selected.
618 else if (is_home()) {
619 $filters->pinPoint |= CJTBlockModel::PINS_POSTS_BLOG_INDEX;
620 }
621 else if (is_search()) {
622 $filters->pinPoint |= CJTBlockModel::PINS_SEARCH;
623 }
624 else if (is_tag()) {
625 $filters->pinPoint |= CJTBlockModel::PINS_TAG;
626 }
627 else if (is_author()) {
628 $filters->pinPoint |= CJTBlockModel::PINS_AUTHOR;
629 }
630 else if (is_archive()) {
631 $filters->pinPoint |= CJTBlockModel::PINS_ARCHIVE;
632 }
633 else if (is_404()) {
634 $filters->pinPoint |= CJTBlockModel::PINS_404_ERROR;
635 }
636 }
637 $this->filters = $this->onsetfilters($filters);
638 }
639
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 /**
661 * put your comment there...
662 *
663 */
664 public static function & theInstance() {
665 return self::$instance;
666 }
667
668 } // End class.
669
670 // Hookable!
671 CJTBlocksCouplingController::define('CJTBlocksCouplingController', array('hookType' => CJTWordpressEvents::HOOK_FILTER));