PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/packages/themes/theme.class.php

https://bitbucket.org/navigatecms/navigatecms
PHP | 1591 lines | 1203 code | 285 blank | 103 comment | 212 complexity | 596505ec9e37f888384e05370d045472 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-2.1, BSD-3-Clause, AGPL-3.0, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. require_once(NAVIGATE_PATH.'/lib/packages/items/item.class.php');
  3. require_once(NAVIGATE_PATH.'/lib/packages/structure/structure.class.php');
  4. require_once(NAVIGATE_PATH.'/lib/packages/comments/comment.class.php');
  5. require_once(NAVIGATE_PATH.'/lib/packages/blocks/block_group.class.php');
  6. require_once(NAVIGATE_PATH.'/lib/packages/blocks/block.class.php');
  7. require_once(NAVIGATE_PATH.'/lib/packages/files/file.class.php');
  8. require_once(NAVIGATE_PATH.'/lib/packages/properties/property.class.php');
  9. require_once(NAVIGATE_PATH.'/lib/external/misc/zipfile.php');
  10. class theme
  11. {
  12. public $name;
  13. public $title;
  14. public $version;
  15. public $author;
  16. public $website;
  17. public $languages;
  18. public $styles;
  19. public $options;
  20. public $block_groups;
  21. public $blocks;
  22. public $templates;
  23. public $webusers;
  24. public $sections;
  25. public $dictionary;
  26. public $dictionaries;
  27. public function load($name)
  28. {
  29. $json = @file_get_contents(NAVIGATE_PATH.'/themes/'.$name.'/'.$name.'.theme');
  30. if(empty($json))
  31. return false;
  32. $theme = json_decode($json);
  33. if(empty($theme))
  34. return false;
  35. //var_dump(json_last_error());
  36. $this->name = $name;
  37. $this->title = $theme->title;
  38. $this->version = $theme->version;
  39. $this->author = $theme->author;
  40. $this->website = $theme->website;
  41. // remove "@" from styles section definition
  42. $this->styles = json_encode($theme->styles);
  43. $this->styles = str_replace("@", "", $this->styles);
  44. $this->styles = json_decode($this->styles);
  45. $this->languages = $theme->languages;
  46. $this->options = (array)$theme->options;
  47. $this->blocks = (array)$theme->blocks;
  48. $this->block_groups = (array)$theme->block_groups;
  49. $this->templates = (array)$theme->templates;
  50. $this->webusers = (array)$theme->webusers;
  51. $this->content_samples = (array)$theme->content_samples;
  52. $this->content_samples_parse(null);
  53. // in 2.0 templates->section "code" was replaced by "id"
  54. // added some code to keep compatibility with existing themes
  55. for($t=0; $t < count($this->templates); $t++)
  56. {
  57. if(isset($this->templates[$t]->sections))
  58. {
  59. for ($s = 0; $s < count($this->templates[$t]->sections); $s++)
  60. {
  61. if(!is_array($this->templates[$t]->sections))
  62. $this->templates[$t]->sections = (array) $this->templates[$t]->sections;
  63. if(!empty($this->templates[$t]->sections))
  64. {
  65. if (!isset($this->templates[$t]->sections[$s]->id))
  66. $this->templates[$t]->sections[$s]->id = $this->templates[$t]->sections[$s]->code;
  67. }
  68. }
  69. }
  70. // remove spaces in "uses" attribute value, if declared
  71. if(isset($this->templates[$t]->uses))
  72. $this->templates[$t]->uses = str_replace(" ", "", $this->templates[$t]->uses);
  73. }
  74. return true;
  75. }
  76. public function delete()
  77. {
  78. global $user;
  79. if($user->permission("themes.delete")=="false")
  80. throw new Exception(t(610, "Sorry, you are not allowed to execute this function."));
  81. $ok = false;
  82. if(file_exists(NAVIGATE_PATH.'/themes/'.$this->name))
  83. {
  84. core_remove_folder(NAVIGATE_PATH.'/themes/'.$this->name);
  85. $ok = !file_exists(NAVIGATE_PATH.'/themes/'.$this->name);
  86. }
  87. return $ok;
  88. }
  89. public function templates($type=NULL)
  90. {
  91. $data = array();
  92. if(!is_array($this->templates))
  93. $this->templates = array();
  94. foreach($this->templates as $template)
  95. {
  96. $template->id = $template->type;
  97. $template->title = $this->template_title($template->type);
  98. $data[] = $template;
  99. if($type == $template->id)
  100. return $template;
  101. }
  102. return $data;
  103. }
  104. public function template_title($type, $add_theme_name=true)
  105. {
  106. $out = $this->t($type);
  107. if($out==$type)
  108. {
  109. $types = theme::types();
  110. $out = (empty($types[$type])? $type : $types[$type]);
  111. }
  112. if($add_theme_name)
  113. $out = $this->title . ' | ' . $out;
  114. return $out;
  115. }
  116. public function t($code='')
  117. {
  118. global $DB;
  119. global $user;
  120. global $webuser;
  121. global $website;
  122. global $session;
  123. $out = "";
  124. if(empty($this->dictionary))
  125. {
  126. $theme_languages = (array)$this->languages;
  127. $file = '';
  128. if(!is_array($theme_languages))
  129. $theme_languages = array();
  130. // if we are in Navigate CMS, user has the default language
  131. // if we call this function from the website, the session has the default language
  132. $current_language = $session['lang'];
  133. if(empty($current_language) && !empty($webuser))
  134. $current_language = $webuser->language;
  135. if(empty($current_language) && !empty($user))
  136. $current_language = $user->language;
  137. foreach($theme_languages as $lcode => $lfile)
  138. {
  139. if( $lcode==$current_language || empty($file))
  140. $file = $lfile;
  141. }
  142. $json = @file_get_contents(NAVIGATE_PATH.'/themes/'.$this->name.'/'.$file);
  143. if(!empty($json))
  144. $this->dictionary = (array)json_decode($json);
  145. // maybe we have a custom translation added in navigate / webdictionary ?
  146. if(!empty($website->id))
  147. {
  148. $DB->query('
  149. SELECT subtype, lang, text
  150. FROM nv_webdictionary
  151. WHERE website = '.$website->id.'
  152. AND node_type = "theme"
  153. AND lang = '.protect($current_language).'
  154. AND theme = '.protect($this->name)
  155. );
  156. $rs = $DB->result();
  157. for($r=0; $r < count($rs); $r++)
  158. $this->dictionary[$rs[$r]->subtype] = $rs[$r]->text;
  159. }
  160. }
  161. if(is_string($code))
  162. {
  163. $out = $code;
  164. if(substr($out, 0, 1)=='@') // get translation from theme dictionary
  165. $out = substr($out, 1);
  166. if(!empty($this->dictionary[$out]))
  167. $out = $this->dictionary[$out];
  168. }
  169. return $out;
  170. }
  171. public function get_translations()
  172. {
  173. if(empty($this->dictionaries))
  174. {
  175. $dict = array();
  176. foreach($this->languages as $lcode => $lfile)
  177. {
  178. $jarray = NULL;
  179. $json = @file_get_contents(NAVIGATE_PATH.'/themes/'.$this->name.'/'.$lfile);
  180. if(!empty($json))
  181. $jarray = (array)json_decode($json);
  182. if(!empty($jarray))
  183. {
  184. foreach($jarray as $code => $text)
  185. {
  186. $id = count($dict) + 1;
  187. $id = -$id;
  188. $dict[] = array(
  189. 'id' => $id, //.' | '.$this->name . ' | '.$code,
  190. 'theme' => $this->name,
  191. 'source' => 'theme.'.$this->name.'.'.$code,
  192. 'node_id' => $code,
  193. 'lang' => $lcode,
  194. 'text' => $text
  195. );
  196. }
  197. }
  198. }
  199. $this->dictionaries = $dict;
  200. }
  201. return $this->dictionaries;
  202. }
  203. public static function types()
  204. {
  205. $template_types = array(
  206. 'home' => t(187, 'Home page'),
  207. 'content' => t(9, 'Content'),
  208. 'gallery' => t(210, 'Gallery'),
  209. 'blog' => t(375, 'Blog'),
  210. 'blog_entry' => t(376, 'Blog entry'),
  211. 'item' => t(180, 'Item'),
  212. 'list' => t(39, 'List'),
  213. 'contact' => t(377, 'Contact'),
  214. 'search' => t(41, 'Search'),
  215. 'newsletter' => t(249, 'Newsletter'),
  216. 'portfolio' => t(447, 'Portfolio'),
  217. 'portfolio_item'=> t(448, 'Portfolio item'),
  218. 'not_found' => t(13, 'Not found')
  219. );
  220. return $template_types;
  221. }
  222. public static function list_available()
  223. {
  224. $themes = glob(NAVIGATE_PATH.'/themes/*/*.theme');
  225. for($t=0; $t < count($themes); $t++)
  226. {
  227. $theme_json = @json_decode(@file_get_contents($themes[$t]));
  228. debug_json_error($themes[$t]); // if debug is enabled, show last json error
  229. $code = substr($themes[$t], strrpos($themes[$t], '/')+1);
  230. $code = substr($code, 0, strpos($code, '.theme'));
  231. $themes[$t] = '';
  232. if(!empty($theme_json))
  233. $themes[$t] = array(
  234. 'code' => $code,
  235. 'title' => $theme_json->title,
  236. 'version' => $theme_json->version
  237. );
  238. }
  239. $themes = array_filter($themes);
  240. sort($themes);
  241. return $themes;
  242. }
  243. public function block_group_blocks($block_group_id)
  244. {
  245. $out = array();
  246. foreach($this->block_groups as $bg)
  247. {
  248. if($bg->id == $block_group_id)
  249. {
  250. foreach($bg->blocks as $bgb)
  251. {
  252. if(empty($bgb->type))
  253. $bgb->type = $bgb->id;
  254. $out[$bgb->id] = $bgb;
  255. }
  256. }
  257. }
  258. return $out;
  259. }
  260. // add special samples if the theme is using foundation, bootstrap...
  261. public function content_samples_parse($ws=null)
  262. {
  263. global $website;
  264. if(empty($ws) && !empty($website))
  265. $ws = $website;
  266. else
  267. $ws = new website();
  268. $content_samples = array();
  269. $grid_samples = array(
  270. '6,6',
  271. '4,4,4',
  272. '3,3,3,3',
  273. '9,3', '3,9',
  274. '8,4', '4,8',
  275. '7,5', '5,7',
  276. '6,3,3', '3,6,3', '3,3,6'
  277. );
  278. $text = "Vis prodesset adolescens adipiscing te, usu mazim perfecto recteque at, assum putant erroribus mea in.\n";
  279. $text.= "Vel facete imperdiet id, cum an libris luptatum perfecto, vel fabellas inciderint ut.";
  280. if(!empty($this->content_samples))
  281. {
  282. foreach($this->content_samples as $cs)
  283. {
  284. switch($cs->file)
  285. {
  286. case 'foundation_grid':
  287. case 'bootstrap_grid':
  288. case 'grid':
  289. $stylesheets = $ws->content_stylesheets('array', "content", false, $this);
  290. $html_pre = '<html><head>';
  291. if(!empty($stylesheets) && is_array($stylesheets))
  292. {
  293. foreach($stylesheets as $ss)
  294. $html_pre.= '<link rel="stylesheet" type="text/css" href="'.$ss.'" />';
  295. }
  296. $html_pre.= '</head><body><div id="navigate-theme-content-sample" style=" width: 99%; ">';
  297. foreach($grid_samples as $gs)
  298. {
  299. $cols = explode(',', $gs);
  300. $name = "Grid &nbsp; [ ";
  301. $html = $html_pre.'<div class="row">';
  302. foreach($cols as $col)
  303. {
  304. $name .= $col.str_pad("", $col, "-");
  305. $scol = $col * 2;
  306. // set the small column to the closest step: 6 or 12
  307. if($scol >= 8) $scol = 12;
  308. if($scol <= 7) $scol = 6;
  309. $html .= '<div class="col-md-'.$col.' medium-'.$col.' col-xs-'.$scol.' small-'.$scol.' columns">'.$text.'</div>';
  310. }
  311. $name .= " ]";
  312. $html .= '</div>'; // close row
  313. $html .= '<div><p>+</p></div>'; // add extra space under the row
  314. $html .= '</div>'; // close copy enabled content
  315. $html .= '</body></html>';
  316. $content_samples[] = json_decode(json_encode(array('title' => $name, 'content' => $html)));
  317. }
  318. break;
  319. case 'skeleton_grid':
  320. $stylesheets = explode(",", $ws->content_stylesheets());
  321. $translate = array(
  322. 1 => "one",
  323. 2 => "two",
  324. 3 => "three",
  325. 4 => "four",
  326. 5 => "fix",
  327. 6 => "six",
  328. 7 => "seven",
  329. 8 => "eight",
  330. 9 => "nine",
  331. 10 => "ten",
  332. 11 => "eleven",
  333. 12 => "twelve"
  334. );
  335. $html_pre = '<html><head>';
  336. foreach($stylesheets as $ss)
  337. $html_pre.= '<link rel="stylesheet" type="text/css" href="'.$ss.'" />';
  338. $html_pre.= '</head><body><div id="navigate-theme-content-sample" style=" width: 99%; ">';
  339. foreach($grid_samples as $gs)
  340. {
  341. $cols = explode(',', $gs);
  342. $name = "Grid &nbsp; [ ";
  343. $html = $html_pre.'<div class="row">';
  344. foreach($cols as $col)
  345. {
  346. $name .= $col.str_pad("", $col, "-");
  347. $scol = $col * 2;
  348. // set the small column to the closest step: 6 or 12
  349. if($scol >= 8) $scol = 12;
  350. if($scol <= 7) $scol = 6;
  351. $html .= '<div class="'.$translate[$col].' columns">'.$text.'</div>';
  352. }
  353. $name .= " ]";
  354. $html .= '</div>'; // close row
  355. $html .= '<div><p>+</p></div>'; // add extra space under the row
  356. $html .= '</div>'; // close copy enabled content
  357. $html .= '</body></html>';
  358. $content_samples[] = json_decode(json_encode(array('title' => $name, 'content' => $html)));
  359. }
  360. break;
  361. default:
  362. $content_samples[] = $cs;
  363. }
  364. }
  365. $this->content_samples = $content_samples;
  366. }
  367. }
  368. public function import_sample($ws=null)
  369. {
  370. global $DB;
  371. global $website;
  372. global $theme;
  373. global $events;
  374. if(is_null($ws))
  375. $ws = $website;
  376. if(!file_exists(NAVIGATE_PATH.'/themes/'.$this->name.'/'.$this->name.'_sample.zip'))
  377. throw new Exception(t(56, 'Unexpected error'));
  378. $ptf = NAVIGATE_PRIVATE.'/tmp/'.$this->name.'_sample';
  379. core_remove_folder($ptf);
  380. // decompress the zip file
  381. $extracted = false;
  382. $zip = new ZipArchive;
  383. if($zip->open(NAVIGATE_PATH.'/themes/'.$this->name.'/'.$this->name.'_sample.zip') === TRUE)
  384. {
  385. @mkdir($ptf, 0777, true);
  386. $extracted = $zip->extractTo($ptf);
  387. if(!$extracted)
  388. throw new Exception(t(56, 'Unexpected error'));
  389. $zip->close();
  390. }
  391. // website languages (add website included languages)
  392. if(file_exists($ptf.'/languages.var_export'))
  393. eval('$wlangs = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/languages.var_export')).';');
  394. else
  395. $wlangs = unserialize(file_get_contents($ptf.'/languages.serialized'));
  396. if(!is_array($wlangs)) $wlangs = array();
  397. foreach($wlangs as $lcode => $loptions)
  398. {
  399. if(!is_array($ws->languages) || !in_array($lcode, array_keys($ws->languages)))
  400. $ws->languages[$lcode] = $loptions;
  401. }
  402. // theme options
  403. if(file_exists($ptf.'/theme_options.var_export'))
  404. eval('$toptions = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/theme_options.var_export')).';');
  405. else
  406. $toptions = unserialize(file_get_contents($ptf.'/theme_options.serialized'));
  407. $ws->theme_options = $toptions;
  408. $ws->save();
  409. // folders (if available)
  410. $theme_files_parent = file::create_folder($this->name, "folder/generic", 0, $ws->id);
  411. $folders = array();
  412. if(file_exists($ptf.'/folders.var_export')) // available since v2.1.2
  413. eval('$folders_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/folders.var_export')).';');
  414. if(!empty($folders_or))
  415. {
  416. // assume folders are defined in order (first the parents, then their children)
  417. foreach($folders_or as $f)
  418. {
  419. // error protection
  420. if(empty($f->id))
  421. continue;
  422. $folders[$f->id] = new file();
  423. $folders[$f->id]->load_from_resultset(array($f));
  424. $folders[$f->id]->id = 0;
  425. $folders[$f->id]->website = $ws->id;
  426. if(isset($folders[$f->parent]))
  427. $folders[$f->id]->parent = $folders[$f->parent]->id;
  428. else
  429. $folders[$f->id]->parent = $theme_files_parent;
  430. $folders[$f->id]->insert();
  431. }
  432. }
  433. // files
  434. $files = array();
  435. if(file_exists($ptf.'/files.var_export'))
  436. eval('$files_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/files.var_export')).';');
  437. else
  438. $files_or = unserialize(file_get_contents($ptf.'/files.serialized'));
  439. foreach($files_or as $f)
  440. {
  441. // error protection
  442. if(empty($f->id))
  443. continue;
  444. $files[$f->id] = new file();
  445. $files[$f->id]->load_from_resultset(array($f));
  446. $files[$f->id]->id = 0;
  447. $files[$f->id]->website = $ws->id;
  448. if(isset($folders[$f->parent]))
  449. $files[$f->id]->parent = $folders[$f->parent]->id;
  450. else
  451. $files[$f->id]->parent = $theme_files_parent;
  452. $files[$f->id]->insert();
  453. // finally copy the sample file
  454. @copy($ptf.'/files/'.$f->id, NAVIGATE_PRIVATE.'/'.$ws->id.'/files/'.$files[$f->id]->id);
  455. }
  456. // structure
  457. $structure = array();
  458. if(file_exists($ptf.'/structure.var_export'))
  459. eval('$structure_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/structure.var_export')).';');
  460. else
  461. $structure_or = unserialize(file_get_contents($ptf.'/structure.serialized'));
  462. // hide existing structure entries
  463. $DB->execute('
  464. UPDATE nv_structure
  465. SET permission = 2, visible = 0
  466. WHERE website = '.$ws->id
  467. );
  468. // we need to insert the old categories in order, in other words, the parents before its children
  469. // so to make things easy, we loop until we have no more categories to insert
  470. // this could lead to an infinite loop, so we have to add a simple protection
  471. $structure_categories_or = $structure_or;
  472. $changes = true;
  473. while(!empty($structure_categories_or) && $changes)
  474. {
  475. $changes = false;
  476. foreach($structure_categories_or as $si => $category)
  477. {
  478. if(empty($category))
  479. continue;
  480. $old_category_id = $category->id;
  481. $category->id = 0;
  482. $category->website = $ws->id;
  483. if($category->parent > 0 && !isset($structure[$category->parent]))
  484. {
  485. // this structure entry needs a parent category that's not yet inserted
  486. // ignore the current entry until the next loop
  487. continue;
  488. }
  489. // if this category has a parent != root, update the parent id with the new value given
  490. if($category->parent > 0)
  491. $category->parent = $structure[$category->parent]->id;
  492. $category->insert();
  493. $changes = true;
  494. $structure[$old_category_id] = $category;
  495. unset($structure_categories_or[$si]);
  496. }
  497. $structure_categories_or = array_filter($structure_categories_or);
  498. }
  499. // elements
  500. $items = array();
  501. if(file_exists($ptf.'/items.var_export'))
  502. eval('$items_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/items.var_export')).';');
  503. else
  504. $items_or = unserialize(file_get_contents($ptf.'/items.serialized'));
  505. foreach($items_or as $item)
  506. {
  507. // error protection
  508. if(empty($item->id))
  509. continue;
  510. $old_item_id = $item->id;
  511. $item->id = 0;
  512. $item->website = $ws->id;
  513. // if this category has a parent != root, update the parent id with the new value given
  514. if($item->category > 0)
  515. $item->category = $structure[$item->category]->id;
  516. $item->dictionary = theme::import_sample_parse_dictionary($item->dictionary, $files, $ws);
  517. // gallery images (correct FILE ids)
  518. if(!empty($item->galleries))
  519. {
  520. $ngallery = array();
  521. foreach($item->galleries as $gid => $gallery)
  522. {
  523. foreach($gallery as $fid => $caption)
  524. $ngallery[$files[$fid]->id] = $caption;
  525. $item->galleries[$gid] = $ngallery;
  526. }
  527. }
  528. $item->insert();
  529. $items[$old_item_id] = $item;
  530. }
  531. // blocks
  532. $blocks = array();
  533. if(file_exists($ptf.'/blocks.var_export'))
  534. eval('$blocks_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/blocks.var_export')).';');
  535. else
  536. $blocks_or = mb_unserialize(file_get_contents($ptf.'/blocks.serialized'));
  537. if(!is_array($blocks_or))
  538. $blocks_or = array();
  539. foreach($blocks_or as $block)
  540. {
  541. // error protection
  542. if(empty($block->id))
  543. continue;
  544. $old_block_id = $block->id;
  545. $block->id = 0;
  546. $block->website = $ws->id;
  547. // update structure entries (if used)
  548. if(!empty($block->categories))
  549. {
  550. for($bc=0; $bc < count($block->categories); $bc++)
  551. $block->categories[$bc] = $structure[$block->categories[$bc]]->id;
  552. }
  553. // update Actions (file/image)
  554. if(is_array($block->action['action-file']))
  555. foreach($block->action['action-file'] as $lang => $file)
  556. $block->action['action-file'][$lang] = $files[$file]->id;
  557. if(is_array($block->action['action-image']))
  558. foreach(@$block->action['action-image'] as $lang => $file)
  559. $block->action['action-image'][$lang] = $files[$file]->id;
  560. // update Triggers (image/rolloverimage/flash/content/html)
  561. if(is_array($block->trigger['trigger-image']))
  562. foreach(@$block->trigger['trigger-image'] as $lang => $file)
  563. $block->trigger['trigger-image'][$lang] = $files[$file]->id;
  564. if(is_array($block->trigger['trigger-rollover']))
  565. foreach(@$block->trigger['trigger-rollover'] as $lang => $file)
  566. $block->trigger['trigger-rollover'][$lang] = $files[$file]->id;
  567. if(is_array($block->trigger['trigger-rollover-active']))
  568. foreach(@$block->trigger['trigger-rollover-active'] as $lang => $file)
  569. $block->trigger['trigger-rollover'][$lang] = $files[$file]->id;
  570. if(is_array($block->trigger['trigger-flash']))
  571. foreach(@$block->trigger['trigger-flash'] as $lang => $file)
  572. $block->trigger['trigger-flash'][$lang] = $files[$file]->id;
  573. $block->trigger['trigger-content'] = theme::import_sample_parse_array($block->trigger['trigger-content'], $files, $ws);
  574. $block->trigger['trigger-html'] = theme::import_sample_parse_array($block->trigger['trigger-html'], $files, $ws);
  575. $block->dictionary = theme::import_sample_parse_dictionary($block->dictionary, $files, $ws);
  576. // translate nv:// urls, which may be in:
  577. // trigger->[trigger-links][lang][link][code] => link
  578. // trigger->[trigger-content][lang] (as html code)
  579. // trigger->[trigger-html][lang] (as html code)
  580. // action->[action-web][lang]
  581. if(!empty($block->trigger['trigger-links']))
  582. {
  583. foreach($block->trigger['trigger-links'] as $lang => $block_trigger_link)
  584. {
  585. foreach($block_trigger_link['link'] as $btl_code => $btl_link)
  586. {
  587. $btl_link = theme::import_sample_translate_nv_urls($btl_link, $structure, $items);
  588. $block->trigger['trigger-links'][$lang]['link'][$btl_code] = $btl_link;
  589. }
  590. }
  591. }
  592. if(!empty($block->trigger['trigger-content']))
  593. {
  594. foreach($block->trigger['trigger-content'] as $lang => $block_trigger_content)
  595. {
  596. $block_trigger_content = theme::import_sample_translate_nv_urls($block_trigger_content, $structure, $items);
  597. $block->trigger['trigger-content'][$lang] = $block_trigger_content;
  598. }
  599. }
  600. if(!empty($block->trigger['trigger-html']))
  601. {
  602. foreach($block->trigger['trigger-html'] as $lang => $block_trigger_content)
  603. {
  604. $block_trigger_content = theme::import_sample_translate_nv_urls($block_trigger_content, $structure, $items);
  605. $block->trigger['trigger-html'][$lang] = $block_trigger_content;
  606. }
  607. }
  608. if(!empty($block->action['action-web']))
  609. {
  610. foreach($block->action['action-web'] as $lang => $block_action_web)
  611. {
  612. $block_action_web = theme::import_sample_translate_nv_urls($block_action_web, $structure, $items);
  613. $block->action['action-web'][$lang] = $block_action_web;
  614. }
  615. }
  616. $block->insert();
  617. $blocks[$old_block_id] = $block;
  618. }
  619. // block_groups
  620. $block_groups = array();
  621. if(file_exists($ptf.'/block_groups.var_export'))
  622. eval('$block_groups_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/block_groups.var_export')).';');
  623. else
  624. $block_groups_or = unserialize(file_get_contents($ptf.'/block_groups.serialized'));
  625. foreach($block_groups_or as $block_group)
  626. {
  627. // error protection
  628. if(empty($block_group->id))
  629. continue;
  630. $old_block_group_id = $block_group->id;
  631. $block_group->id = 0;
  632. $block_group->website = $ws->id;
  633. // fix block IDs in group
  634. $new_selection = array();
  635. for($bi=0; $bi < count($block_group->blocks); $bi++)
  636. {
  637. if($block_group->blocks[$bi]['type'] == 'block')
  638. $block_group->blocks[$bi]['id'] = $blocks[ $block_group->blocks[$bi]['id'] ]->id;
  639. $new_selection[] = $block_group->blocks[$bi];
  640. }
  641. $block_group->blocks = $new_selection;
  642. $block_group->insert();
  643. $block_groups[$old_block_group_id] = $block_group;
  644. }
  645. // comments
  646. if(file_exists($ptf.'/comments.var_export'))
  647. eval('$comments_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/comments.var_export')).';');
  648. else
  649. $comments_or = unserialize(file_get_contents($ptf.'/comments.serialized'));
  650. foreach($comments_or as $comment)
  651. {
  652. if(empty($comment->object_id))
  653. continue;
  654. $comment->id = 0;
  655. $comment->website = $ws->id;
  656. $comment->object_id = $items[$comment->object_id]->id;
  657. $comment->ip = '';
  658. $comment->insert();
  659. }
  660. // now that categories and elements have been inserted
  661. // we need to fix:
  662. // structure jumps: [jump-branch, jump-item] to its new ID values
  663. // items' sections: embedded nv:// urls
  664. // note: properties will be "translated" later
  665. // update structure properties
  666. foreach($structure as $old_id => $entry)
  667. {
  668. foreach($entry->dictionary as $elang => $properties)
  669. {
  670. if(!empty($properties['action-jump-item']))
  671. $entry->dictionary[$elang]['action-jump-item'] = $items[$properties['action-jump-item']]->id;
  672. else if(!empty($properties['action-jump-branch']))
  673. $entry->dictionary[$elang]['action-jump-branch'] = $structure[$properties['action-jump-branch']]->id;
  674. $entry->save();
  675. }
  676. }
  677. // find & update items' sections nv:// urls
  678. foreach($items as $old => $element)
  679. {
  680. foreach($element->dictionary as $eld_lang => $eld_field)
  681. {
  682. foreach($eld_field as $eld_field_key => $eld_field_val)
  683. {
  684. $html = theme::import_sample_translate_nv_urls($eld_field_val, $structure, $items);
  685. $items[$old]->dictionary[$eld_lang][$eld_field_key] = $html;
  686. }
  687. }
  688. $items[$old]->save();
  689. }
  690. // translate website options; check for forced multilanguage options!
  691. $theme_options = array();
  692. for($toi=0; $toi < count($theme->options); $toi++)
  693. {
  694. $to = $theme->options[$toi];
  695. $to->value = $ws->theme_options->{$to->id};
  696. switch($to->type)
  697. {
  698. case 'file':
  699. case 'image':
  700. // is multi-language forced for this option?
  701. if(in_array($to->multilanguage, array('true', '1')))
  702. {
  703. foreach($to->value as $olang => $oval)
  704. {
  705. if(isset($files[$oval]->id))
  706. $to->value[$olang] = $files[$oval]->id;
  707. }
  708. }
  709. else
  710. {
  711. if(isset($files[$to->value]->id))
  712. $to->value = $files[$to->value]->id;
  713. }
  714. break;
  715. case 'category':
  716. // is multi-language forced for this option?
  717. if(in_array($to->multilanguage, array('true', '1')))
  718. {
  719. foreach($to->value as $olang => $oval)
  720. {
  721. if(isset($structure[$oval]->id))
  722. $to->value[$olang] = $structure[$oval]->id;
  723. }
  724. }
  725. else
  726. {
  727. if(isset($structure[$to->value]->id))
  728. $to->value = $structure[$to->value]->id;
  729. }
  730. break;
  731. case 'element':
  732. // is multi-language forced for this option?
  733. if(in_array($to->multilanguage, array('true', '1')))
  734. {
  735. foreach($to->value as $olang => $oval)
  736. {
  737. if(isset($items[$oval]->id))
  738. $to->value[$olang] = $items[$oval]->id;
  739. }
  740. }
  741. else
  742. {
  743. if(isset($items[$to->value]->id))
  744. $to->value = $items[$to->value]->id;
  745. }
  746. break;
  747. case 'categories':
  748. // is multi-language forced for this option?
  749. if(in_array($to->multilanguage, array('true', '1')))
  750. {
  751. foreach($to->value as $olang => $oval)
  752. {
  753. $property_categories_old = explode(',', $oval);
  754. $property_categories_new = array();
  755. foreach($property_categories_old as $oc)
  756. $property_categories_new[] = $structure[$oc]->id;
  757. $to->value[$olang] = implode(',', $property_categories_new);
  758. }
  759. }
  760. else
  761. {
  762. $property_categories_old = explode(',', $to->value);
  763. $property_categories_new = array();
  764. foreach($property_categories_old as $oc)
  765. $property_categories_new[] = $structure[$oc]->id;
  766. $to->value = implode(',', $property_categories_new);
  767. }
  768. break;
  769. default:
  770. // we don't need to change this type of value
  771. }
  772. // convert theme option definition to website option value
  773. $theme_options[$to->id] = $to->value;
  774. }
  775. $ws->theme_options = $theme_options;
  776. $ws->save();
  777. // properties
  778. // array ('structure' => ..., 'item' => ..., 'block' => ...)
  779. if(file_exists($ptf.'/properties.var_export'))
  780. eval('$properties = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/properties.var_export')).';');
  781. else
  782. $properties = unserialize(file_get_contents($ptf.'/properties.serialized'));
  783. $elements_with_properties = array('structure', 'item', 'block', 'block_group_block');
  784. foreach($elements_with_properties as $el)
  785. {
  786. if($el=='structure') $real = $structure;
  787. else if($el=='item') $real = $items;
  788. else if($el=='block') $real = $blocks;
  789. else if($el=='block_group_block') $real = $block_groups;
  790. else
  791. continue; // unrecognized element type, ignore
  792. if(!is_array($properties[$el]))
  793. continue;
  794. foreach($properties[$el] as $el_id => $el_properties)
  795. {
  796. if(empty($el_properties))
  797. continue;
  798. $item_uid = "";
  799. if($el=='block_group_block')
  800. {
  801. // find each assigned block UID reference in this block group block
  802. foreach($el_properties as $item_uid => $el_properties_bg)
  803. theme::import_sample_properties($ws, $el_properties_bg, $el, $files, $structure, $items, $real, $el_id, $item_uid);
  804. }
  805. else
  806. {
  807. theme::import_sample_properties($ws, $el_properties, $el, $files, $structure, $items, $real, $el_id, $item_uid);
  808. }
  809. }
  810. }
  811. // apply final settings from export
  812. if(file_exists($ptf.'/settings.var_export'))
  813. eval('$settings_or = '.str_replace("stdClass::__set_state", "(object)", file_get_contents($ptf.'/settings.var_export')).';');
  814. else
  815. {
  816. // get first structure ID
  817. $structure_id = array_keys($structure);
  818. $structure_id = $structure_id[0];
  819. $settings_or = array('homepage' => $structure_id);
  820. }
  821. if(!empty($settings_or['favicon']))
  822. $ws->favicon = $files[$settings_or['favicon']]->id;
  823. // what is the homepage?
  824. if(is_numeric($settings_or['homepage']))
  825. {
  826. // homepage as a category ID
  827. $ws->homepage = $structure[$settings_or['homepage']]->id;
  828. }
  829. else
  830. {
  831. // homepage as a path
  832. $ws->homepage = $settings_or['homepage'];
  833. }
  834. $ws->save();
  835. core_remove_folder($ptf);
  836. }
  837. public static function export_sample($a_categories, $a_items, $a_block_groups, $a_blocks, $a_comments, $folder)
  838. {
  839. global $website;
  840. global $theme;
  841. global $DB;
  842. @set_time_limit(0);
  843. $categories = array();
  844. $items = array();
  845. $blocks = array();
  846. $block_groups = array();
  847. $comments = array();
  848. $properties = array();
  849. $files = array();
  850. $settings = array();
  851. // structure
  852. for($c=0; $c < count($a_categories); $c++)
  853. {
  854. $tmp = new structure();
  855. $tmp->load($a_categories[$c]);
  856. //$properties['structure'][$tmp->id] = property::load_properties_associative('structure', $tmp->template, 'structure', $tmp->id);
  857. $properties['structure'][$tmp->id] = property::load_properties('structure', $tmp->template, 'structure', $tmp->id);
  858. $categories[$tmp->id] = $tmp;
  859. // add files referenced in properties
  860. if(is_array($properties['structure'][$tmp->id]))
  861. {
  862. foreach($properties['structure'][$tmp->id] as $property)
  863. if($property->type == 'image' || $property->type == 'file')
  864. $files[] = $property->value;
  865. }
  866. }
  867. // comments
  868. for($c=0; $c < count($a_comments); $c++)
  869. {
  870. $tmp = new comment();
  871. $tmp->load($a_comments[$c]);
  872. $comments[$tmp->id] = $tmp;
  873. }
  874. // items
  875. for($i=0; $i < count($a_items); $i++)
  876. {
  877. $tmp = new item();
  878. $tmp->load($a_items[$i]);
  879. $template_id = $tmp->template;
  880. if($tmp->association != "free" && $tmp->embedding == 1)
  881. {
  882. // we have to get the template set in the category of the item
  883. $template_id = $DB->query_single('template', 'nv_structure', ' id = '.protect($tmp->category).' AND website = '.$website->id);
  884. }
  885. $properties['item'][$tmp->id] = property::load_properties('item', $template_id, 'item', $tmp->id);
  886. list($tmp->dictionary, $files) = theme::export_sample_parse_dictionary($tmp->dictionary, $files);
  887. // add files referenced in properties
  888. if(is_array($properties['item'][$tmp->id]))
  889. {
  890. foreach($properties['item'][$tmp->id] as $property)
  891. if($property->type == 'image' || $property->type == 'file')
  892. $files[] = $property->value;
  893. }
  894. // add files referenced in gallery
  895. if(is_array($tmp->galleries[0]))
  896. {
  897. $gallery_images = array_keys($tmp->galleries[0]);
  898. $files = array_merge($files, $gallery_images);
  899. }
  900. $items[$tmp->id] = $tmp;
  901. }
  902. // block_groups
  903. for($i=0; $i < count($a_block_groups); $i++)
  904. {
  905. $tmp = new block_group();
  906. $tmp->load($a_block_groups[$i]);
  907. $block_groups[$tmp->id] = $tmp;
  908. if(is_array($tmp->blocks))
  909. {
  910. foreach($tmp->blocks as $bgb)
  911. {
  912. if($bgb['type'] == 'block_group_block')
  913. {
  914. $properties['block_group_block'][$a_block_groups[$i]][$bgb['uid']] = property::load_properties($bgb['id'], $tmp->code, 'block_group_block', $bgb['id'], $bgb['uid']);
  915. }
  916. else if($bgb['type'] == 'extension')
  917. {
  918. $properties['block_group_block'][$a_block_groups[$i]][$bgb['uid']] = property::load_properties(NULL, $bgb['id'], "extension_block", NULL, $bgb['uid']);
  919. }
  920. }
  921. }
  922. // note: maybe not all blocks in the group have been selected in the "blocks" tab
  923. // here we only export the block group definition, the block group blocks properties and the extension blocks properties, not adding anything else to export
  924. }
  925. // blocks
  926. for($i=0; $i < count($a_blocks); $i++)
  927. {
  928. $tmp = new block();
  929. $tmp->load($a_blocks[$i]);
  930. $properties['block'][$tmp->id] = property::load_properties('block', $tmp->type, 'block', $tmp->id);
  931. list($tmp->dictionary, $files) = theme::export_sample_parse_dictionary($tmp->dictionary, $files);
  932. list($tmp->trigger['trigger-content'], $files) = theme::export_sample_parse_array($tmp->trigger['trigger-content'], $files);
  933. list($tmp->trigger['trigger-html'], $files) = theme::export_sample_parse_array($tmp->trigger['trigger-html'], $files);
  934. if(!empty($tmp->trigger['trigger-image']))
  935. $files = array_merge($files, array_values($tmp->trigger['trigger-image']));
  936. if(!empty($tmp->trigger['trigger-rollover']))
  937. $files = array_merge($files, array_values($tmp->trigger['trigger-rollover']));
  938. if(!empty($tmp->trigger['trigger-rollover-active']))
  939. $files = array_merge($files, array_values($tmp->trigger['trigger-rollover-active']));
  940. if(!empty($tmp->trigger['trigger-flash']))
  941. $files = array_merge($files, array_values($tmp->trigger['trigger-flash']));
  942. if(!empty($tmp->action['action-image']))
  943. $files = array_merge($files, array_values($tmp->action['action-image']));
  944. if(!empty($tmp->action['action-file']))
  945. $files = array_merge($files, array_values($tmp->action['action-file']));
  946. // add files referenced in properties
  947. if(is_array($properties['block'][$tmp->id]))
  948. {
  949. foreach($properties['block'][$tmp->id] as $property)
  950. if($property->type == 'image' || $property->type == 'file')
  951. $files[] = $property->value;
  952. }
  953. $blocks[$tmp->id] = $tmp;
  954. }
  955. // folders
  956. // save references and get their files list
  957. $folders = array();
  958. $folders_to_check = array();
  959. if(!empty($folder))
  960. {
  961. array_push($folders_to_check, $folder);
  962. while(!empty($folders_to_check))
  963. {
  964. $f = array_shift($folders_to_check);
  965. $f = file::filesOnPath($f);
  966. foreach($f as $file)
  967. {
  968. if($file->type == 'folder')
  969. {
  970. array_push($folders_to_check, $file->id);
  971. array_push($folders, $file);
  972. }
  973. else
  974. $files[] = $file->id;
  975. }
  976. }
  977. }
  978. // add files selected as theme_options
  979. foreach($theme->options as $to)
  980. {
  981. if($to->type == 'image' || $to->type == 'file')
  982. {
  983. $to_value = $website->theme_options->{$to->id};
  984. if(is_array($to_value))
  985. $files = array_merge($files, $to_value);
  986. else
  987. $files[] = $to_value;
  988. }
  989. }
  990. // include favicon in file list
  991. if(!empty($website->favicon))
  992. $files[] = $website->favicon;
  993. // files
  994. $files = array_unique($files);
  995. for($f=0; $f < count($files); $f++)
  996. {
  997. $file = new file();
  998. $file->load($files[$f]);
  999. $files[$f] = $file;
  1000. }
  1001. // settings
  1002. $settings['homepage'] = $website->homepage;
  1003. $settings['favicon'] = $website->favicon;
  1004. $zip = new zipfile();
  1005. $zip->addFile(var_export($website->languages, true), 'languages.var_export');
  1006. $zip->addFile(var_export($website->theme_options, true), 'theme_options.var_export');
  1007. $zip->addFile(var_export($categories, true), 'structure.var_export');
  1008. $zip->addFile(var_export($items, true), 'items.var_export');
  1009. $zip->addFile(var_export($block_groups, true), 'block_groups.var_export');
  1010. $zip->addFile(var_export($blocks, true), 'blocks.var_export');
  1011. $zip->addFile(var_export($comments, true), 'comments.var_export');
  1012. $zip->addFile(var_export($files, true), 'files.var_export');
  1013. $zip->addFile(var_export($folders, true), 'folders.var_export');
  1014. $zip->addFile(var_export($properties, true), 'properties.var_export');
  1015. $zip->addFile(var_export($settings, true), 'settings.var_export');
  1016. foreach($files as $file)
  1017. $zip->addFile(file_get_contents($file->absolute_path()), 'files/'.$file->id);
  1018. $contents = $zip->file();
  1019. header('Content-Disposition: attachment; filename="'.$website->theme.'_sample.zip"');
  1020. header("Content-type: application/octet-stream");
  1021. header('Content-Length: '.strlen($contents));
  1022. echo $contents;
  1023. }
  1024. public static function export_sample_parse_dictionary($dictionary, $files=array())
  1025. {
  1026. if(is_array($dictionary))
  1027. {
  1028. foreach($dictionary as $language => $dictionary_data)
  1029. {
  1030. list($dictionary_data, $files) = theme::export_sample_parse_array($dictionary_data, $files);
  1031. $dictionary[$language] = $dictionary_data;
  1032. }
  1033. }
  1034. return array($dictionary, $files);
  1035. }
  1036. public static function export_sample_parse_array($dictionary, $files=array())
  1037. {
  1038. global $website;
  1039. if(is_array($dictionary))
  1040. {
  1041. foreach($dictionary as $entry => $content)
  1042. {
  1043. // identify all files used
  1044. preg_match_all('!'.NAVIGATE_DOWNLOAD.'!', $content, $matches_nd, PREG_OFFSET_CAPTURE);
  1045. $matches_nd = $matches_nd[0];
  1046. for($m=count($matches_nd); $m >= 0; $m--)
  1047. {
  1048. if(@empty($matches_nd[$m][1])) continue;
  1049. $offset = $matches_nd[$m][1] + strlen(NAVIGATE_DOWNLOAD);
  1050. $end = strpos($content, '"', $offset);
  1051. $file_query = substr($content, $offset + 1, $end - $offset - 1);
  1052. $file_query = str_replace('&amp;', '&', $file_query);
  1053. parse_str($file_query, $file_query);
  1054. $file_id = intval($file_query['id']);
  1055. $files[] = $file_id;
  1056. $file_query['id'] = '{{NAVIGATE_FILE}'.$file_id.'}';
  1057. if(!empty($file_query['wid']))
  1058. $file_query['wid'] = '{{NVWEB_WID}}';
  1059. $file_query = http_build_query($file_query);
  1060. $content = substr_replace($content, $file_query, $offset + 1, $end - $offset - 1);
  1061. }
  1062. preg_match_all('!'.NVWEB_OBJECT.'!', $content, $matches_no, PREG_OFFSET_CAPTURE);
  1063. $matches_no = $matches_no[0];
  1064. for($m=count($matches_no); $m >= 0; $m--)
  1065. {
  1066. if(@empty($matches_no[$m][1])) continue;
  1067. $offset = $matches_no[$m][1] + strlen(NVWEB_OBJECT);
  1068. $end = strpos($content, '"', $offset);
  1069. $file_query = substr($content, $offset + 1, $end - $offset - 1);
  1070. $file_query = str_replace('&amp;', '&', $file_query);
  1071. parse_str($file_query, $file_query);
  1072. $file_id = intval($file_query['id']);
  1073. $files[] = $file_id;
  1074. $file_query['id'] = '{{NAVIGATE_FILE}'.$file_id.'}';
  1075. $file_query = http_build_query($file_query);
  1076. $content = substr_replace($content, $file_query, $offset + 1, $end - $offset - 1);
  1077. }
  1078. // example route substitutions
  1079. // http://192.168.x.x/navigate/navigate_download.php --> NAVIGATE_DOWNLOAD
  1080. // http://192.168.x.x/ocean [ $website->absolute_path() ] --> WEBSITE_ABSOLUTE_PATH
  1081. // http://192.168.x.x/navigate/themes/ocean [ NAVIGATE_PARENT.NAVIGATE_FOLDER.'/themes/'.$website->theme ] --> THEME_ABSOLUTE_PATH
  1082. $content = str_replace(NAVIGATE_DOWNLOAD, 'url://{{NAVIGATE_DOWNLOAD}}', $content);
  1083. $content = str_replace($website->absolute_path(), 'url://{{WEBSITE_ABSOLUTE_PATH}}', $content);
  1084. $content = str_replace(NAVIGATE_PARENT.NAVIGATE_FOLDER.'/themes/'.$website->theme, 'url://{{THEME_ABSOLUTE_PATH}}', $content);
  1085. $dictionary[$entry] = $content;
  1086. }
  1087. }
  1088. return array($dictionary, $files);
  1089. }
  1090. public static function import_sample_parse_dictionary($dictionary, $files=array(), $ws=null)
  1091. {
  1092. if(is_array($dictionary))

Large files files are truncated, but you can click here to view the full file