Exemple #1
0
function nvweb_search($vars = array())
{
    global $website;
    global $webuser;
    global $DB;
    global $current;
    global $cache;
    global $structure;
    global $theme;
    $out = array();
    $search_what = $_REQUEST[$vars['request']];
    $search_archive = array();
    if (!empty($_REQUEST['archive'])) {
        $search_archive = explode("-", $_REQUEST['archive']);
    }
    // YEAR, MONTH, CATEGORIES (separated by commas)
    if (isset($_REQUEST[$vars['request']]) || !empty($search_archive[0]) && !empty($search_archive[1])) {
        // LOG search request
        $wu_id = 0;
        if (!empty($webuser->id)) {
            $wu_id = $webuser->id;
        }
        $DB->execute('
            INSERT INTO nv_search_log
              (id, website, date, webuser, origin, text)
            VALUES
              (0, :website, :date, :webuser, :origin, :text)
        ', array('website' => $website->id, 'date' => time(), 'webuser' => $wu_id, 'origin' => empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'], 'text' => $search_what));
        // prepare and execute the search
        $search_what = explode(' ', $search_what);
        $search_what = array_filter($search_what);
        if (empty($search_what)) {
            $search_what = array();
        }
        $likes = array();
        $likes[] = ' 1=1 ';
        foreach ($search_what as $what) {
            if (substr($what, 0, 1) == '-') {
                $likes[] = 'd.text NOT LIKE ' . protect('%' . substr($what, 1) . '%') . '    AND i.id IN( 
                                            SELECT p.node_id
                                             FROM   nv_properties_items p 
                                             WHERE  p.element = "item" AND 
                                                    p.website = ' . protect($website->id) . ' AND
                                                    p.value NOT LIKE ' . protect('%' . substr($what, 1) . '%') . '
                                        )';
            } else {
                $likes[] = 'd.text LIKE ' . protect('%' . $what . '%') . '    OR i.id IN( 
			                        SELECT  p.node_id
			                         FROM   nv_properties_items p 
			                         WHERE  p.element = "item" AND 
			                                p.website = ' . protect($website->id) . ' AND
			                                p.value LIKE ' . protect('%' . $what . '%') . '
                                )';
            }
        }
        if (!empty($search_archive)) {
            $start_date = gmmktime(0, 0, 0, $search_archive[1], 1, $search_archive[0]);
            $end_date = gmmktime(0, 0, 0, $search_archive[1] + 1, 1, $search_archive[0]);
            $likes[] = ' (i.date_to_display >= ' . $start_date . ')';
            $likes[] = ' (i.date_to_display <= ' . $end_date . ')';
        }
        if (!empty($search_archive[2])) {
            $vars['categories'] = $search_archive[2];
        }
        $categories = NULL;
        if (isset($vars['categories'])) {
            if ($vars['categories'] == 'all') {
                $categories = array(0);
                $vars['children'] = 'true';
            } else {
                if ($vars['categories'] == 'parent') {
                    $categories = array($current['object']->id);
                    $parent = $DB->query_single('parent', 'nv_structure', 'id = ' . intval($categories[0]));
                    $categories = array($parent);
                } else {
                    if ($vars['categories'] == 'nvlist_parent') {
                        if ($vars['nvlist_parent_type'] === 'structure') {
                            $categories = array($vars['nvlist_parent_item']->id);
                        }
                    } else {
                        if (!is_numeric($vars['categories'])) {
                            // if "categories" attribute has a comma, then we suppose it is a list of comma separated values
                            // if not, then maybe we want to get the categories from a specific property of the current page
                            if (strpos($vars['categories'], ',') === false) {
                                $categories = nvweb_properties(array('property' => $vars['categories']));
                            }
                            if (empty($categories) && @$vars['nvlist_parent_vars']['source'] == 'block_group') {
                                $categories = nvweb_properties(array('mode' => 'block_group_block', 'property' => $vars['categories']));
                            }
                            if (empty($categories)) {
                                $categories = $vars['categories'];
                            }
                            if (!is_array($categories)) {
                                $categories = explode(',', $categories);
                                $categories = array_filter($categories);
                                // remove empty elements
                            }
                        } else {
                            $categories = explode(',', $vars['categories']);
                            $categories = array_filter($categories);
                            // remove empty elements
                        }
                    }
                }
            }
        }
        if ($vars['children'] == 'true') {
            $categories = nvweb_menu_get_children($categories);
        }
        // if we have categories="x" children="true" [to get the children of a category, but not itself]
        if ($vars['children'] == 'only') {
            $children = nvweb_menu_get_children($categories);
            for ($c = 0; $c < count($categories); $c++) {
                array_shift($children);
            }
            $categories = $children;
        }
        if (!empty($vars['children']) && intval($vars['children']) > 0) {
            $children = nvweb_menu_get_children($categories, intval($vars['children']));
            for ($c = 0; $c < count($categories); $c++) {
                array_shift($children);
            }
            $categories = $children;
        }
        // apply a filter on categories, if given
        // example: request_categories="c" ... in the url &q=text&c=23,35
        if (!empty($vars['request_categories'])) {
            $categories_filter = explode(",", $_REQUEST[$vars['request_categories']]);
            if (empty($categories)) {
                // note: categories may be empty by the rules applies on categories + children;
                // in this case we give preference to the request_categories filter
                $categories = array_values($categories_filter);
            } else {
                for ($cf = 0; $cf < count($categories_filter); $cf++) {
                    if (!in_array($categories_filter[$cf], $categories)) {
                        unset($categories_filter[$cf]);
                    }
                    $categories_filter = array_filter($categories_filter);
                }
                $categories = $categories_filter;
            }
        }
        // retrieve entries
        $permission = !empty($_SESSION['APP_USER#' . APP_UNIQUE]) ? 1 : 0;
        $access = !empty($current['webuser']) ? 1 : 2;
        if (empty($_GET['page'])) {
            $_GET['page'] = 1;
        }
        $offset = intval($_GET['page'] - 1) * $vars['items'];
        // get order type: PARAMETER > NV TAG PROPERTY > DEFAULT (priority given in CMS)
        $order = @$_REQUEST['order'];
        if (empty($order)) {
            $order = @$vars['order'];
        }
        if (empty($order)) {
            // default order: latest
            $order = 'latest';
        }
        $orderby = nvweb_list_get_orderby($order);
        if (empty($vars['items']) || $vars['items'] == '0') {
            $vars['items'] = 500;
            //2147483647; // maximum integer
            // NOTE: having >500 items on a page without a paginator is probably a bad idea... disagree? Contact Navigate CMS team!
        } else {
            if (!is_numeric($vars['items'])) {
                $max_items = "";
                // the number of items is defined by a property
                $max_items = nvweb_properties(array('property' => $vars['items']));
                if (empty($max_items) && @$vars['nvlist_parent_vars']['source'] == 'block_group') {
                    $max_items = nvweb_properties(array('mode' => 'block_group_block', 'property' => $vars['items'], 'id' => $vars['nvlist_parent_item']->id, 'uid' => $vars['nvlist_parent_item']->uid));
                }
                if (!empty($max_items)) {
                    $vars['items'] = $max_items;
                } else {
                    $vars['items'] = 500;
                }
                // default maximum
            }
        }
        // TODO: try to optimize search to use less memory and increase the maximum number of items
        $DB->query('
            SELECT SQL_CALC_FOUND_ROWS rs.id
            FROM (
                SELECT  i.id as id, i.permission, i.date_published, i.date_unpublish,
                        i.date_to_display, COALESCE(NULLIF(i.date_to_display, 0), i.date_created) as pdate,
                        i.position as position, wd.text as title
                  FROM nv_items i, nv_webdictionary d
                  LEFT JOIN nv_webdictionary wd
                    ON wd.node_id = d.node_id
                   AND wd.lang =  ' . protect($current['lang']) . '
                   AND wd.node_type = "item"
                   AND wd.website = ' . protect($website->id) . '			  
                 WHERE i.website = ' . $website->id . '
                   AND i.permission <= ' . $permission . '
                   AND (i.date_published = 0 OR i.date_published < ' . core_time() . ')
                   AND (i.date_unpublish = 0 OR i.date_unpublish > ' . core_time() . ')
                   AND (i.access = 0 OR i.access = ' . $access . ')
                   AND d.website = ' . protect($website->id) . '
                   AND d.node_id = i.id
                   AND d.lang =  ' . protect($current['lang']) . '
                   AND (d.node_type = "item" OR d.node_type = "tags")
                   AND (
                    ' . implode(' AND ', $likes) . '
                   )
                   ' . (empty($categories) ? '' : 'AND category IN(' . implode(",", $categories) . ')') . '
                 ' . $orderby . '
             ) rs
             GROUP BY rs.id
			 LIMIT ' . $vars['items'] . '
			OFFSET ' . $offset);
        $rs = $DB->result();
        $total = $DB->foundRows();
        for ($i = 0; $i < count($rs); $i++) {
            if (empty($rs[$i]->id)) {
                break;
            }
            $item = new item();
            $item->load($rs[$i]->id);
            // get the nv list template
            $item_html = $vars['template'];
            // now, parse the nvlist_conditional tags (with html source code inside (and other nvlist tags))
            unset($nested_condition_fragments);
            list($item_html, $nested_conditional_fragments) = nvweb_list_isolate_conditionals($item_html);
            $conditional_placeholder_tags = nvweb_tags_extract($item_html, 'nvlist_conditional_placeholder', true, true, 'UTF-8');
            // selfclosing = true
            while (!empty($conditional_placeholder_tags)) {
                $tag = $conditional_placeholder_tags[0];
                $conditional = $nested_conditional_fragments[$tag["attributes"]["id"]];
                $conditional_html_output = nvweb_list_parse_conditional($conditional, $item, $conditional['nvlist_conditional_template'], $i, count($rs));
                $item_html = str_replace($tag["full_tag"], $conditional_html_output, $item_html);
                $conditional_placeholder_tags = nvweb_tags_extract($item_html, 'nvlist_conditional_placeholder', true, true, 'UTF-8');
                // selfclosing = true
            }
            // now parse the (remaining) common nvlist tags
            $template_tags = nvweb_tags_extract($item_html, 'nvlist', true, true, 'UTF-8');
            // selfclosing = true
            if (empty($item_html)) {
                $item_html = array();
                $item_html[] = '<div class="search-result-item">';
                $item_html[] = '	<div class="search-result-title"><a href="' . $website->absolute_path() . $item->paths[$current['lang']] . '">' . $item->dictionary[$current['lang']]['title'] . '</a></div>';
                $item_html[] = '	<div class="search-result-summary">' . core_string_cut($item->dictionary[$current['lang']]['section-main'], 300, '&hellip;') . '</div>';
                $item_html[] = '</div>';
                $item_html = implode("\n", $item_html);
                $out[] = $item_html;
            } else {
                // parse special template tags
                foreach ($template_tags as $tag) {
                    $content = nvweb_list_parse_tag($tag, $item, $vars['source'], $i, $i + $offset, $total);
                    $item_html = str_replace($tag['full_tag'], $content, $item_html);
                }
                $out[] = $item_html;
            }
        }
        if ($total == 0) {
            $search_results_empty_text = $theme->t("no_results_found");
            if (isset($vars['no_results_found'])) {
                $search_results_empty_text = $theme->t($vars["no_results_found"]);
            }
            if (empty($search_results_empty_text) || $search_results_empty_text == 'no_results_found') {
                $search_results_empty_text = t(645, "No results found");
            }
            // display the error message only if
            //  1) it's not empty
            //  2) the template is preventing the display of any error message in the search ( no_results_found="" )
            if (!empty($search_results_empty_text) && (!isset($vars['no_results_found']) || isset($vars['no_results_found']) && !empty($vars['no_results_found']))) {
                $out[] = '<div class="search-results-empty">';
                $out[] = $search_results_empty_text;
                $out[] = '</div>';
            }
        }
        $archive = $_REQUEST['archive'];
        if (!empty($archive)) {
            $archive = 'archive=' . $archive . '&';
        }
        if (isset($vars['paginator']) && $vars['paginator'] != 'false') {
            $search_url = '?' . $archive . $vars['request'] . '=' . $_REQUEST[$vars['request']] . '&page=';
            $out[] = nvweb_list_paginator($vars['paginator'], $_GET['page'], $total, $vars['items'], $vars, $search_url);
        }
    }
    return implode("\n", $out);
}
Exemple #2
0
function nvweb_list($vars = array())
{
    global $website;
    global $DB;
    global $current;
    global $cache;
    global $structure;
    global $webgets;
    global $theme;
    global $webuser;
    $out = array();
    $webget = 'list';
    $categories = array();
    $exclude = '';
    if ($current['type'] == 'item') {
        $categories = array($current['object']->category);
    } else {
        $categories = array($current['object']->id);
    }
    if (isset($vars['categories'])) {
        if ($vars['categories'] == 'all') {
            $categories = array(0);
            $vars['children'] = 'true';
        } else {
            if ($vars['categories'] == 'parent') {
                $parent = $DB->query_single('parent', 'nv_structure', 'id = ' . intval($categories[0]));
                $categories = array($parent);
            } else {
                if ($vars['categories'] == 'nvlist_parent') {
                    if ($vars['nvlist_parent_type'] === 'structure') {
                        $categories = array($vars['nvlist_parent_item']->id);
                    }
                } else {
                    if (!is_numeric($vars['categories'])) {
                        // if "categories" attribute has a comma, then we suppose it is a list of comma separated values
                        // if not, then maybe we want to get the categories from a specific property of the current page
                        if (strpos($vars['categories'], ',') === false) {
                            $categories = nvweb_properties(array('property' => $vars['categories']));
                        }
                        if (empty($categories) && @$vars['nvlist_parent_vars']['source'] == 'block_group') {
                            $categories = nvweb_properties(array('mode' => 'block_group_block', 'property' => $vars['categories'], 'id' => $vars['nvlist_parent_item']->id, 'uid' => $vars['nvlist_parent_item']->uid));
                        }
                        if (!is_array($categories)) {
                            $categories = explode(',', $categories);
                            $categories = array_filter($categories);
                            // remove empty elements
                        }
                    } else {
                        $categories = explode(',', $vars['categories']);
                        $categories = array_filter($categories);
                        // remove empty elements
                    }
                }
            }
        }
    }
    if ($vars['children'] == 'true') {
        $categories = nvweb_menu_get_children($categories);
    }
    // if we have categories="x" children="true" [to get the children of a category, but not itself]
    if ($vars['children'] == 'only') {
        $children = nvweb_menu_get_children($categories);
        for ($c = 0; $c < count($categories); $c++) {
            array_shift($children);
        }
        $categories = $children;
    }
    if (!empty($vars['children']) && intval($vars['children']) > 0) {
        $children = nvweb_menu_get_children($categories, intval($vars['children']));
        for ($c = 0; $c < count($categories); $c++) {
            array_shift($children);
        }
        $categories = $children;
    }
    if (empty($vars['items']) || $vars['items'] == '0') {
        $vars['items'] = 5000;
        //2147483647; // maximum integer
        // NOTE: having >5000 items on a page without a paginator is probably a bad idea... disagree? Contact Navigate CMS team!
    } else {
        if (!is_numeric($vars['items'])) {
            $max_items = "";
            // the number of items is defined by a property
            $max_items = nvweb_properties(array('property' => $vars['items']));
            if (empty($max_items) && @$vars['nvlist_parent_vars']['source'] == 'block_group') {
                $max_items = nvweb_properties(array('mode' => 'block_group_block', 'property' => $vars['items'], 'id' => $vars['nvlist_parent_item']->id, 'uid' => $vars['nvlist_parent_item']->uid));
            }
            if (!empty($max_items)) {
                $vars['items'] = $max_items;
            } else {
                $vars['items'] = 500;
            }
            // default maximum
        }
    }
    if (!empty($vars['exclude'])) {
        $exclude = str_replace('current', $current['object']->id, $vars['exclude']);
        $exclude = explode(',', $exclude);
        $exclude = array_filter($exclude);
        if (!empty($exclude)) {
            if ($vars['source'] == 'structure' || $vars['source'] == 'category') {
                $exclude = 'AND s.id NOT IN(' . implode(',', $exclude) . ')';
            } else {
                // item
                $exclude = 'AND i.id NOT IN(' . implode(',', $exclude) . ')';
            }
        } else {
            $exclude = '';
        }
    }
    // retrieve entries
    // calculate the offset of the first element to retrieve
    // Warning: the paginator applies on all paginated lists on a page (so right now there can only be one in a page)
    if (empty($_GET['page'])) {
        $_GET['page'] = 1;
    }
    $offset = intval($_GET['page'] - 1) * $vars['items'];
    // this list does not use paginator, so offset must be always zero
    if (!isset($vars['paginator']) || $vars['paginator'] == 'false') {
        $offset = 0;
    }
    $permission = !empty($_SESSION['APP_USER#' . APP_UNIQUE]) ? 1 : 0;
    // public access / webuser based / webuser groups based
    $access = 2;
    $access_extra = '';
    if (!empty($current['webuser'])) {
        $access = 1;
        if (!empty($webuser->groups)) {
            $access_groups = array();
            foreach ($webuser->groups as $wg) {
                if (empty($wg)) {
                    continue;
                }
                $access_groups[] = 's.groups LIKE "%g' . $wg . '%"';
            }
            if (!empty($access_groups)) {
                $access_extra = ' OR (s.access = 3 AND (' . implode(' OR ', $access_groups) . '))';
            }
        }
    }
    // get order type: PARAMETER > NV TAG PROPERTY > DEFAULT (priority given in CMS)
    $order = @$_REQUEST['order'];
    if (empty($order)) {
        $order = @$vars['order'];
    }
    if (empty($order)) {
        // default order: latest
        $order = 'latest';
    }
    $orderby = nvweb_list_get_orderby($order);
    $rs = NULL;
    // TODO: try to optimize nvlist generation to use less memory and increase the maximum number of items
    if (($vars['source'] == 'structure' || $vars['source'] == 'category') && !empty($categories)) {
        $orderby = str_replace('i.', 's.', $orderby);
        $visible = '';
        if ($vars['filter'] == 'menu') {
            $visible = ' AND s.visible = 1 ';
        }
        $templates = "";
        if (!empty($vars['templates'])) {
            $templates = explode(",", $vars['templates']);
            $templates = array_filter($templates);
            $templates = ' AND s.template IN ("' . implode('","', $templates) . '")';
        }
        $DB->query('
			SELECT SQL_CALC_FOUND_ROWS s.id, s.permission,
			            s.date_published, s.date_unpublish, s.date_published as pdate,
			            d.text as title, s.position as position
			  FROM nv_structure s, nv_webdictionary d
			 WHERE s.id IN(' . implode(",", $categories) . ')
			   AND s.website = ' . $website->id . '
			   AND s.permission <= ' . $permission . '
			   AND (s.date_published = 0 OR s.date_published < ' . core_time() . ')
			   AND (s.date_unpublish = 0 OR s.date_unpublish > ' . core_time() . ')
			   AND (s.access = 0 OR s.access = ' . $access . $access_extra . ')
			   AND d.website = s.website
			   AND d.node_type = "structure"
			   AND d.subtype = "title"
			   AND d.node_id = s.id
			   AND d.lang = ' . protect($current['lang']) . '
		     ' . $templates . '
			 ' . $visible . '
			 ' . $exclude . '
			 ' . $orderby . '
			 LIMIT ' . $vars['items'] . '
			OFFSET ' . $offset);
        $rs = $DB->result();
        $total = $DB->foundRows();
    } else {
        if ($vars['source'] == 'block') {
            list($rs, $total) = nvweb_blocks(array('type' => $vars['type'], 'number' => $vars['items'], 'mode' => $order == 'random' ? 'random' : 'ordered', 'zone' => 'object'));
        } else {
            if ($vars['source'] == 'block_link') {
                // only useful if this nvlist is inside another nv list of source="block"
                $block_links = $vars['nvlist_parent_item']->trigger['trigger-links'][$current['lang']];
                $rs = array();
                if (!is_array($block_links)) {
                    $block_links = array();
                }
                foreach ($block_links as $b_key => $b_data) {
                    if (!is_array($b_data)) {
                        $b_data = array();
                    }
                    $b_i = 0;
                    foreach ($b_data as $b_ref => $b_value) {
                        if (!isset($rs[$b_i])) {
                            $rs[$b_i] = new stdClass();
                        }
                        if (!isset($rs[$b_i]->id)) {
                            $rs[$b_i]->id = $b_ref;
                        }
                        $rs[$b_i]->{$b_key} = $b_value;
                        $b_i++;
                    }
                }
                $total = count($rs);
            } else {
                if ($vars['source'] == 'block_group') {
                    $bg = new block_group();
                    if (!empty($vars['type'])) {
                        $bg->load_by_code($vars['type']);
                    }
                    if (!empty($bg) && !empty($bg->blocks)) {
                        $rs = array();
                        foreach ($bg->blocks as $bgb) {
                            unset($bgbo);
                            switch ($bgb['type']) {
                                case 'block':
                                    $bgbo = new block();
                                    $bgbo->load($bgb['id']);
                                    if (empty($bgbo) || empty($bgbo->type)) {
                                        continue;
                                    }
                                    // check if we can display this block
                                    if (nvweb_object_enabled($bgbo)) {
                                        // check categories / exclusions
                                        if (!empty($bgbo->categories)) {
                                            $bgbo_cat_found = false;
                                            foreach ($categories as $list_cat) {
                                                if (in_array($list_cat, $bgbo->categories)) {
                                                    $bgbo_cat_found = true;
                                                }
                                            }
                                            if (!$bgbo_cat_found) {
                                                // block categories don't match the current list categories, skip this block
                                                continue;
                                            }
                                        }
                                        if (!empty($bgbo->exclusions)) {
                                            foreach ($categories as $list_cat) {
                                                if (in_array($list_cat, $bgbo->exclusions)) {
                                                    continue;
                                                }
                                                // skip this block
                                            }
                                        }
                                        $rs[] = $bgbo;
                                    }
                                    break;
                                case 'block_group_block':
                                    $bgba = $theme->block_group_blocks($vars['type']);
                                    if (!empty($bgba[$bgb['id']])) {
                                        $bgbo = $bgba[$bgb['id']];
                                        $bgbo->uid = $bgb['uid'];
                                        $rs[] = clone $bgbo;
                                    }
                                    break;
                                case 'block_type':
                                    // a collection of blocks of the same type
                                    list($bgbos, $foo) = nvweb_blocks(array('type' => $bgb['id'], 'mode' => $order == 'random' ? 'random' : 'ordered', 'zone' => 'object'));
                                    // add the block type definition, with its title
                                    if (count($bgbos) > 0 && isset($bgb['title']) && !empty($bgb['title'])) {
                                        $bgb['_object_type'] = 'block_group_block_type';
                                        $rs[] = (object) $bgb;
                                    }
                                    for ($i = 0; $i < count($bgbos); $i++) {
                                        $rs[] = $bgbos[$i];
                                    }
                                    break;
                                case 'extension':
                                    $rs[] = (object) $bgb;
                                    break;
                            }
                        }
                        $total = count($rs);
                    }
                } else {
                    if ($vars['source'] == 'gallery') {
                        if (!isset($vars['nvlist_parent_type'])) {
                            // get gallery of the current item
                            if ($current['type'] == 'item') {
                                $galleries = $current['object']->galleries;
                                if (!is_array($galleries)) {
                                    $galleries = mb_unserialize($galleries);
                                }
                                $rs = $galleries[0];
                                $total = count($rs);
                            } else {
                                if ($current['type'] == 'structure') {
                                    // we need the first item assigned to the structure
                                    $access_extra_items = str_replace('s.', 'i.', $access_extra);
                                    $templates = "";
                                    if (!empty($vars['templates'])) {
                                        $templates = explode(",", $vars['templates']);
                                        $templates = array_filter($templates);
                                        $templates = ' AND i.template IN ("' . implode('","', $templates) . '")';
                                    }
                                    // default source for retrieving items (embedded or not)
                                    $DB->query('
                    SELECT SQL_CALC_FOUND_ROWS i.id
                      FROM nv_items i, nv_structure s, nv_webdictionary d
                     WHERE i.category IN(' . implode(",", $categories) . ')
                       AND i.website = ' . $website->id . '
                       AND i.permission <= ' . $permission . '
                       AND (i.date_published = 0 OR i.date_published < ' . core_time() . ')
                       AND (i.date_unpublish = 0 OR i.date_unpublish > ' . core_time() . ')
                       AND s.id = i.category
                       AND (s.date_published = 0 OR s.date_published < ' . core_time() . ')
                       AND (s.date_unpublish = 0 OR s.date_unpublish > ' . core_time() . ')
                       AND s.permission <= ' . $permission . '
                       AND (s.access = 0 OR s.access = ' . $access . $access_extra . ')
                       AND (i.access = 0 OR i.access = ' . $access . $access_extra_items . ')
                       AND d.website = i.website
                       AND d.node_type = "item"
                       AND d.subtype = "title"
                       AND d.node_id = i.id
                       AND d.lang = ' . protect($current['lang']) . '                       
                     ' . $templates . '
                     ' . $exclude . '
                     ORDER BY i.position ASC
                     LIMIT 1
                ');
                                    $rs = $DB->result();
                                    $tmp = new item();
                                    $tmp->load($rs[0]->id);
                                    $rs = $tmp->galleries[0];
                                    $total = count($rs);
                                }
                            }
                        } else {
                            if ($vars['nvlist_parent_type'] == 'item') {
                                $pitem = $vars['nvlist_parent_item'];
                                $rs = $pitem->galleries[0];
                                $total = count($rs);
                            }
                        }
                        if ($total > 0) {
                            $order = 'priority';
                            // display images using the assigned priority
                            if (!empty($vars['order'])) {
                                $order = $vars['order'];
                            }
                            $rs = nvweb_gallery_reorder($rs, $order);
                            // prepare format to be parsed by nv list iterator
                            $rs = array_map(function ($k, $v) {
                                $v['file'] = $k;
                                return $v;
                            }, array_keys($rs), array_values($rs));
                        }
                    } else {
                        if ($vars['source'] == 'rss') {
                            // url may be a property
                            $rss_url = $vars['url'];
                            if (strpos($vars['url'], "http") !== 0) {
                                $rss_url = nvweb_properties(array('property' => $vars['url']));
                            }
                            list($rs, $total) = nvweb_list_get_from_rss($rss_url, @$vars['cache'], $offset, $vars['items'], $permission, $order);
                        } else {
                            if ($vars['source'] == 'twitter') {
                                list($rs, $total) = nvweb_list_get_from_twitter($vars['username'], @$vars['cache'], $offset, $vars['items'], $permission, $order);
                            } else {
                                if (!empty($vars['source'])) {
                                    // CUSTOM data source
                                    if ($vars['source'] == 'comment') {
                                        $vars['source'] = 'comments';
                                    }
                                    $fname = 'nvweb_' . $vars['source'] . '_list';
                                    if ($vars['source'] == 'website_comments') {
                                        $vars['source'] = 'comments';
                                    }
                                    nvweb_webget_load($vars['source']);
                                    if (function_exists($fname)) {
                                        list($rs, $total) = $fname($offset, $vars['items'], $permission, $order, $vars);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    $categories = array_filter($categories);
    // DATA SOURCE not given or ERROR ===> items
    if ((empty($vars['source']) || !is_numeric($total)) && !empty($categories)) {
        /*
                 * TO DO: design decision ... lists should show items from published categories which has unpublished parent?
                 *
                 * Navigate CMS 1.6.7: NO
                 *
        // we have to check all website UNPUBLISHED categories to keep the list query efficient
                // there are some cases:
                //  a) Permission is beyond user's level [0=>public, 1=>private, 2=>hidden]
                //  b) Date published is set and the value is before the current time (not yet published)
                //  c) Date unpublish is set and the value is before the current time (no more published)
                //  d) User account level not allowed [0=>everyone, 1=>signed in users, 2=>users NOT signed in]
                $DB->query('
                    SELECT id
                      FROM nv_structure
                     WHERE website = '.protect($website->id).'
                       AND (    permission > '.$permission.'
                             OR (date_published > 0 AND '.$website->current_time().' > date_published)
                             OR (date_unpublish > 0 AND '.$website->current_time().' > date_unpublish)
                             OR (access <> 0 AND access <> '.$access.')
                       )
                ');
        $hidden_categories = $DB->result('id');
        // now we would have to mark the children categories also as unpublished
        */
        $filters = '';
        if (!empty($vars['filter'])) {
            $filters = nvweb_list_parse_filters($vars['filter'], 'items');
        }
        // reuse structure.access permission
        $access_extra_items = str_replace('s.', 'i.', $access_extra);
        $embedded = $vars['embedded'] == 'true' ? '1' : '0';
        $templates = "";
        if (!empty($vars['templates'])) {
            $templates = explode(",", $vars['templates']);
            $templates = array_filter($templates);
            if ($embedded == '1') {
                $templates = ' AND s.template IN ("' . implode('","', $templates) . '")';
            } else {
                $templates = ' AND i.template IN ("' . implode('","', $templates) . '")';
            }
        }
        $columns_extra = '';
        if ($vars['order'] == 'comments') {
            // we need to retrieve the number of comments to apply the order by clause
            $columns_extra = ', (SELECT COUNT(c.id) FROM nv_comments c WHERE i.id = c.item AND c.website = i.website AND c.status = 0) AS comments_published';
        }
        // default source for retrieving items
        $query = '
			SELECT SQL_CALC_FOUND_ROWS i.id, i.permission, i.date_published, i.date_unpublish,
                    i.date_to_display, COALESCE(NULLIF(i.date_to_display, 0), i.date_created) as pdate,
                    d.text as title, i.position as position, s.position ' . $columns_extra . '
			  FROM nv_items i, nv_structure s, nv_webdictionary d			          
			 WHERE i.category IN(' . implode(",", $categories) . ')
			   AND i.website = ' . $website->id . '
			   AND i.permission <= ' . $permission . '
			   AND i.embedding = ' . $embedded . '
			   AND (i.date_published = 0 OR i.date_published < ' . core_time() . ')
			   AND (i.date_unpublish = 0 OR i.date_unpublish > ' . core_time() . ')
			   AND s.id = i.category
			   AND (s.date_published = 0 OR s.date_published < ' . core_time() . ')
			   AND (s.date_unpublish = 0 OR s.date_unpublish > ' . core_time() . ')
			   AND s.permission <= ' . $permission . '
			   AND (s.access = 0 OR s.access = ' . $access . $access_extra . ')
			   AND (i.access = 0 OR i.access = ' . $access . $access_extra_items . ')
               AND d.website = i.website
			   AND d.node_type = "item"
			   AND d.subtype = "title"
			   AND d.node_id = i.id
			   AND d.lang = ' . protect($current['lang']) . '
             ' . $filters . '
		     ' . $templates . '
			 ' . $exclude . '
			 ' . $orderby . '
			 LIMIT ' . $vars['items'] . '
			OFFSET ' . $offset;
        $DB->query($query);
        $rs = $DB->result();
        $total = $DB->foundRows();
    }
    // now we have all elements that will be shown in the list
    // let's apply the nvlist template to each one
    for ($i = 0; $i < count($rs); $i++) {
        // ignore empty objects
        if ($vars['source'] != 'gallery' && empty($rs[$i]->id) || $vars['source'] == 'gallery' && empty($rs[$i]['file'])) {
            continue;
        }
        // prepare a standard  $item  with the current element
        if ($vars['source'] == 'comments' || $vars['source'] == 'comment') {
            $item = $rs[$i];
        } else {
            if ($vars['source'] == 'structure' || $vars['source'] == 'category') {
                $item = new structure();
                $item->load($rs[$i]->id);
                $item->date_to_display = $rs[$i]->pdate;
            } else {
                if ($vars['source'] == 'rss' || $vars['source'] == 'twitter' || $vars['source'] == 'block_link') {
                    // item is virtually created
                    $item = $rs[$i];
                } else {
                    if ($vars['source'] == 'block' || $vars['source'] == 'block_group') {
                        if (get_class($rs[$i]) == 'block') {
                            // standard block
                            $item = $rs[$i];
                        } else {
                            if (isset($rs[$i]->_object_type) && $rs[$i]->_object_type == "block_group_block_type") {
                                // block type definition (mainly used to add a title before a list of blocks of the same type)
                                $item = $rs[$i];
                            } else {
                                if (isset($rs[$i]->extension)) {
                                    // extension block
                                    $item = block::extension_block($rs[$i]->extension, $rs[$i]->id);
                                    $item->type = "extension";
                                    $item->extension = $rs[$i]->extension;
                                    $item->uid = $rs[$i]->uid;
                                } else {
                                    // block from block group
                                    $item = new block();
                                    $item->load_from_block_group($vars['type'], $rs[$i]->id, $rs[$i]->uid);
                                }
                            }
                        }
                    } else {
                        if ($vars['source'] == 'gallery') {
                            $item = $rs[$i];
                        } else {
                            $item = new item();
                            $item->load($rs[$i]->id);
                            // if the item comes from a custom source, save the original query result
                            // this allows getting a special field without extra work ;)
                            $item->_query = $rs[$i];
                        }
                    }
                }
            }
        }
        // get the nv list template
        $item_html = $vars['template'];
        // first we need to isolate the nested nv lists/searches
        unset($nested_lists_fragments);
        list($item_html, $nested_lists_fragments) = nvweb_list_isolate_lists($item_html);
        // now, parse the nvlist_conditional tags (with html source code inside (and other nvlist tags))
        unset($nested_condition_fragments);
        list($item_html, $nested_conditional_fragments) = nvweb_list_isolate_conditionals($item_html);
        $conditional_placeholder_tags = nvweb_tags_extract($item_html, 'nvlist_conditional_placeholder', true, true, 'UTF-8');
        // selfclosing = true
        while (!empty($conditional_placeholder_tags)) {
            $tag = $conditional_placeholder_tags[0];
            $conditional = $nested_conditional_fragments[$tag["attributes"]["id"]];
            $conditional_html_output = nvweb_list_parse_conditional($conditional, $item, $conditional['nvlist_conditional_template'], $i, count($rs));
            $item_html = str_replace($tag["full_tag"], $conditional_html_output, $item_html);
            $conditional_placeholder_tags = nvweb_tags_extract($item_html, 'nvlist_conditional_placeholder', true, true, 'UTF-8');
            // selfclosing = true
        }
        // now, parse the (remaining) common nvlist tags (selfclosing tags)
        $template_tags_processed = 0;
        $template_tags = nvweb_tags_extract($item_html, 'nvlist', true, true, 'UTF-8');
        // selfclosing = true
        while (!empty($template_tags)) {
            $tag = $template_tags[0];
            // protect the "while" loop, maximum 500 nvlist tags parsed!
            $template_tags_processed++;
            if ($template_tags_processed > 500) {
                break;
            }
            $content = nvweb_list_parse_tag($tag, $item, $vars['source'], $i, $i + $offset, $total);
            $item_html = str_replace($tag['full_tag'], $content, $item_html);
            // html template has changed, the nvlist tags may have changed its positions
            $template_tags = nvweb_tags_extract($item_html, 'nvlist', true, true, 'UTF-8');
        }
        // restore & process nested lists (if any)
        foreach ($nested_lists_fragments as $nested_list_uid => $nested_list_vars) {
            $nested_list_vars['nvlist_parent_vars'] = $vars;
            $nested_list_vars['nvlist_parent_type'] = $vars['source'];
            $nested_list_vars['nvlist_parent_item'] = $item;
            $content = nvweb_list($nested_list_vars);
            $item_html = str_replace('<!--#' . $nested_list_uid . '#-->', $content, $item_html);
        }
        $out[] = $item_html;
    }
    if (count($rs) == 0) {
        // special case, no results found
        // get the nv list template and parse only the conditional: <nvlist_conditional by="count" value="empty"> (or value=0)
        $item_html = $vars['template'];
        // now, parse the nvlist_conditional tags (with html source code inside (and other nvlist tags))
        unset($nested_condition_fragments);
        list($item_html, $nested_conditional_fragments) = nvweb_list_isolate_conditionals($item_html);
        // remove all tags except (selfclosing) nvlist_conditional_placeholder
        $item_html = strip_tags($item_html, '<nvlist_conditional_placeholder>');
        $conditional_placeholder_tags = nvweb_tags_extract($item_html, 'nvlist_conditional_placeholder', true, true, 'UTF-8');
        // selfclosing=true
        while (!empty($conditional_placeholder_tags)) {
            $tag = $conditional_placeholder_tags[0];
            $conditional = $nested_conditional_fragments[$tag["attributes"]["id"]];
            $conditional_html_output = nvweb_list_parse_conditional($conditional, NULL, $conditional['nvlist_conditional_template'], $i, count($rs));
            $item_html = str_replace($tag["full_tag"], $conditional_html_output, $item_html);
            $conditional_placeholder_tags = nvweb_tags_extract($item_html, 'nvlist_conditional_placeholder', true, true, 'UTF-8');
            // selfclosing = true
        }
        $out[] = $item_html;
    }
    if (isset($vars['paginator']) && $vars['paginator'] != 'false') {
        $out[] = nvweb_list_paginator($vars['paginator'], $_GET['page'], $total, $vars['items'], $vars);
    }
    return implode("\n", $out);
}