PageRenderTime 425ms CodeModel.GetById 115ms app.highlight 219ms RepoModel.GetById 49ms app.codeStats 1ms

/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

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

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

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