I have custom Joomla(v1.5) component and currently working with component's router. The problem is I can't remove id numbers from SEF url. I get:
http://myaddress.com/componentalias/17-city-alias/130-item-alias
What I want to get:
http://myaddress.com/componentalias/city-alias/item-alias
Take a look at router.php methods below:
function ComponentnameBuildRoute(&$query) {
$segments = array();
if(isset($query['city_id'])){
$segments[] = $query['city_id'];
unset($query['city_id']);
}
if(isset($query['item_id'])){
$segments[] = $query['item_id'];
unset($query['item_id']);
}
if(isset($query['task'])){
switch($query['task']){
case 'pay':
$segments[] = JText::_('payment');
unset($query['task']);
break;
}
}
unset($query['view']);
return $segments;
}
/*
* Function to convert a SEF URL back to a system URL
*/
function ComponentnameParseRoute($segments) {
$var = array();
if(isset($segments[0])){
$cityData = explode(':',$segments[0]);
if(isset($cityData[0])){
$vars['city_id'] = $cityData[0];
}
}
if(isset($segments[1])){
$itemData = explode(':',$segments[1]);
if(isset($itemData[0])){
$vars['item_id'] = $itemData[0];
}
}
if(isset($segments[2])){
switch($segments[2]){
case JText::_('payment'):
$vars['task'] = 'pay';
break;
}
}
return $vars;
}
Any ideas? Your help would be appreciated.
The best place to start with your router.php file is reading this article (it's a bit dated but still good) and then reviewing the com_content's router.php file (components/com_content/router.php). You will notice that articles do achieve what you want so best to look at working code and got from there.
Longer answer:
You can only get rid of the item ID variables in a path to a content element if a menu item exists that points directly to the item, otherwise there is no way to find the item.
SEF URLs in Joomla! 1.5 etc are made from the alias' of the individual elements
eg. If I have this menu structure:
Recipes (The menu)
-- Seafood (<-- Category blog where category alias is `seafood` )
-- Grilled Snapper (<-- Recipe Item where item alias is `grilled-snapper` )
-- 'Other category' (<-- Another Category blog )
Full ID Removal
In the case where you're building the SEF URL for a recipe you can build the route by looking for the menu item it might appear in by getting the site menu $menu = &JSite::getMenu(); and comparing the query id in the current menu item against id value in the $query array passed in.
If you have a match you can build the segments up using the alias from the menu path and the recipe alias. (And reverse the process in your ParseRoute($segments) method).
So, from this example above you could build a SEF URL to the Grilled Snapper recipe that looks something like: recipes/seafood/grilled-snapper.
Partial ID Removal
Now say you also have another recipe (e.g. 'Garlic Prawns' alias garlic-prawns) that isn't directly linked to a menu but will appear in the 'Seafood' category blog page. In this situation you would end up with recipes/seafood/2:garlic-prawns
If you don't have a match (like the Garlic Prawns), you can build up partial match if your component has list views like category blogs or in our example Recipe category pages... Essentially in this case you look at the current menu item and determine if it's a list/category view that would contain the content item.
If it is then the path to the category/list view form you initial segments, but as there is no menu item for the article you will still have to use the ID of the item in the last element of the URL.
No Menu Item for content item or a list/category view
When the content item is being linked to directly (e.g. from an article, module or search result) and there are no menu items that point to it or could contain it then you can still create a URL without id's in it but you will be providing the path in the form of direct component access URL.
eg. /component/recipes/recipe/ice-cream-sundae where recipes is the name of the component, recipe is the view and ice-cream-sundae is the alias of the article.
Related
I am using contao 4.4 instance.I have a problem in google sitemap generation.
I have a newsletter page (page type = regular ) . In that page I have some newsletter articles (with teaser) . When I generate the sitemap, the url of these articles generated twice. When I checked the core I found a class which creates the page array for generating sitemap
vendor/contao/core-bundle/src/Resources/contao/classes/Backend.php
line no 662 - 680 .
Which append 'articles/' to the articles with teaser. So the sitemap generates url
with articles/
List item
without articles/
The first one is the correct url.Second Url generate 404. How I fix the issue ?
My siteconfiguration is as follows
->created a regular page with hidden in navigation and created articles with configuration show teaser
->created another page and created elements as 'teaser articles' and select articles from the above page
So your site structure is like this?
Page 1 with multiple articles
Page 2 with one article containing an „article teaser“ element, this page should be excluded from the sitemap
Is that correct? If yes this might be the solution:
In your „site structur“ you can EDIT Page 2: Scroll down to „Expert settings“, there is an option „Show in sitemap“ and you can select „Never show“.
I resolved the issue.
The url's were regenerated from the newsletter-bundle. In core bundle, the url of the article with teaser is generated. The newsletter-bundle is also contain hook for creating searchable page array. The hook regenerates the url. I wrote a function in vendor/contao/newsletter-bundle/src/Resources/contao/classes/Newsletter.php to check whether the array contain any duplicate url.
Modified function getSearchablePages() ( line 889-897
)
if($this->checkValidUrl($arrPages, $objItem, $strUrl)){
$arrPages[] = sprintf($strUrl, ($objItem->alias ?: $objItem->id));
}
Defining new function for finding duplicate
public function checkValidUrl($arrPages, $objItem, $strUrl)
{
$alias = $objItem->alias ?: $objItem->id;
$urlExplode = explode('%s', $strUrl);
$articleUrl = $urlExplode[0] . 'articles';
foreach ($arrPages as $arrPage) {
$validarticleUrl = $articleUrl . '/' . $alias;
if (strcasecmp($arrPage,$validarticleUrl) == 0) {
return false;
}
}
return true;
}
On an anchor category page I'm trying to only show the products directly contained within the category. I don't want to show the products of child categories, it's not appropriate in this case. I really do need to filter the products in my current category, so I need layered navigation, which necessitates an anchor category.
Initially I thought to filter the products in the view.phtml template, but that only filters the products in the view and is not a sensible answer. When I do this I end up with big gaps on my page where child products are present, but simply not displayed. And the product counts (eg. "1-12 of 117 products") are "incorrect".
From what I've read, this is going to require a core rewrite. Probably of an index process. I don't really know where to start with this rewrite, and I'm sure it's going to be rather involved.
Are any of my assumptions wrong? Have you already solved this problem?
Goto app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php
copy to app/code/local/Mage/Catalog/Model/Resource/Product/Collection.php
find function addCategoryFilter( and here you you find code
public function addCategoryFilter(Mage_Catalog_Model_Category $category)
{
$this->_productLimitationFilters['category_id'] = $category->getId();
/* start to comment here
if ($category->getIsAnchor()) {
unset($this->_productLimitationFilters['category_is_anchor']);
} else {
$this->_productLimitationFilters['category_is_anchor'] = 1;
}*/
/* new line */
$this->_productLimitationFilters['category_is_anchor'] = 1;
if ($this->getStoreId() == Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID) {
$this->_applyZeroStoreProductLimitations();
} else {
$this->_applyProductLimitations();
}
return $this;
}
You don't need a single line of code if I have understood your condition correct. Magento provides the freedom to enter products in any category regardless of their hierarchy.
So consider the following scenario:
Category A->Category a
Then a product can be assigned to only category a and not to category A. This will work in harmony with the entire magento system including layered navigation and no of prouducts shown on page.
I have requirement in which i am getting product ID from external Application with product super_attribute options like color,size. I am getting all those and i can do the add to cart option.
But here my actual requirement is to select the requested options by customer and redirect them to product detail page in magento so that here they can still enter optional text to print. So i need to set the requested options in detail page and redirect them to product detail page instead of adding it to cart. They will enter more details and then they will do addtocart manually.
How can i set the selected options while loading itself.
Please help me.
Thankfully this is already built in to most themes. You need to know the ID of both attributes and values from the Simple product that is included in the Configurable product. I've only seen it work with Configurable types so that might be a limitation.
For each attribute make a key=value pair
Combine the attributes as a query string, eg. "123=345&678=890"
Append the string as a hash fragment (not as a query).
This is an example from the official demo, note that the first option needs to be selected for the second to work so it has two key/value pairs.
http://demo.magentocommerce.com/zolof-the-rock-and-roll-destroyer-lol-cat-t-shirt-126.html#525=99&272=22
Rough Magento2 example add the below for pre-selecting the custom options by name=value in:
/www/mysite/app/design/frontend/mycompany/mytheme/Magento_Catalog/templates/product/view/options.phtml
The below code looks at the label of the option and the text value of the select. And depends on your theme structure. Example below for Luma.
It expects the following format in the url
product.html?SelectLabel=OptionValue&SelectLabel=OptionValue
This does not account for multi language etc.. you could easily adapt it to instead look for the select id and option id which would be more accurate replacing
$(label).parents().eq(1).find('select option:contains('+arr[k]+')').attr('selected', true);
with (untested)
$("#"+k+" option[id='"+arr[k]+"']").attr("selected", "selected");
<script>
require(['jquery'],function($){
$(document).ready(function(){
function getJsonFromUrl() {
var query = location.search.substr(1);
var result = {};
query.split("&").forEach(function(part) {
var item = part.split("=");
result[item[0]] = decodeURIComponent(item[1]);
});
return result;
}
var arr = getJsonFromUrl();
for (var k in arr){
if (arr.hasOwnProperty(k)) {
//alert("Key is " + k + ", value is" + arr[k]);
var label = $('.product-options-wrapper').find("span:contains('"+k+"')");
$(label).parents().eq(1).find('select option:contains('+arr[k]+')').attr('selected', true);
}
}
});
});
</script>
I have my website working on social engine, I have a Main page named as articles.tpl, and in that I have a sub-page named as article.tpl, article.tpl is used to show the entire article, and articles.tpl is used to show topics of articles not the content,
My concern is with articles.tpl(pretty confusing articles and article)
In articles.tpl, 3 articles title, author of article and date is displayed, but I also want to display the category of that article,
For that I tried the following code,
$article_category = "";
$parent_category = "";
$article_category_query = $database->database_query("SELECT articlecat_id, articlecat_title, ".
"articlecat_dependency FROM se_articlecats WHERE articlecat_id='".
$rc_article->article_info[article_articlecat_id]."' LIMIT 1");
if($database->database_num_rows($article_category_query) == 1) {
$article_category_info = $database->database_fetch_assoc($article_category_query);
$article_category = $article_category_info[articlecat_title];
if($article_category_info[articlecat_dependency] != 0) {
$parent_category = $database->database_fetch_assoc(
$database->database_query("SELECT articlecat_id, articlecat_title".
" FROM se_articlecats WHERE articlecat_id='".
$article_category_info[articlecat_dependency]."' LIMIT 1"));
}
}
$smarty->assign('article_category', $article_category);
and in articles.tpl file I called it in this way
<span class="tahoma11_blue">| {$article_category}</span>
But when I check I get nothing, that space is blank, I am just able to see
|
How can I display the category?
i think you have to change
$smarty->assign('categories', $categories);
to
$smarty->assign('article_category', $article_category);
(in your example, you assign the (apparently empty) php variable $categories to the smarty variable categories. then, in the template, you use a smarty variable article_category - which never got assigned)
ok, so i'm very new to codeigniter and from what i have learned by now i can't figure out how can i create a dynamic category -> subcategory -> subsubcategory system. Can you give me some guidelines please...some references, anything to guide me on what should i learn to accomplish that? thanks
i should get my URL like this www.site.com/category/subcategory/subsubcategory/etc... , you know what i mean.
I have done this for the page manager in PyroCMS but it is no easy task.
Each page has its own slug and parent_id, then to read the correct page it loops through each of the page slugs and joins the child. It knows how many children there are so if there are 5 children it selects the 5th self-joined table.
Here is an example of the code:
public function get_by_path($segments = array())
{
// If the URI has been passed as a string, explode to create an array of segments
if(is_string($segments))
{
$segments = explode('/', $segments);
}
// Work out how many segments there are
$total_segments = count($segments);
// Which is the target alias (the final page in the tree)
$target_alias = 'p'.$total_segments;
// Start Query, Select (*) from Target Alias, from Pages
$this->db->select($target_alias.'.*');
$this->db->from('pages p1');
// Loop thorugh each Slug
$level = 1;
foreach( $segments as $segment )
{
// Current is the current page, child is the next page to join on.
$current_alias = 'p'.$level;
$child_alias = 'p'.($level - 1);
// We dont want to join the first page again
if($level != 1)
{
$this->db->join('pages '.$current_alias, $current_alias.'.parent_id = '.$child_alias.'.id');
}
// Add slug to where clause to keep us on the right tree
$this->db->where($current_alias . '.slug', $segment);
// Increment
++$level;
}
// Can only be one result
$this->db->limit(1);
return $this->db->get()->row();
}
It's a bit nuts but it works perfectly. This can be really slow so PyroCMS also maintains a look-up table which has id and the page URI to match quickly.
You can see the whole model here:
http://github.com/philsturgeon/pyrocms/blob/master/application/modules/core/pages/models/pages_m.php
you could:
create controller category, reroute some URIs to it and use it's internal logic to parse it's arguments to pick whatever article client requested:
About URLs:
http://codeigniter.com/user_guide/general/urls.html
About URI routing:
http://codeigniter.com/user_guide/general/routing.html
I agree with Phil's idea and I was also envisioning that you can create a separate module (if you use modular extensions for example) to handle the categories in a generic way. Then you can reuse that module in any other projects. Basically the new module may be able to handle categories and sub-categories (the hierarchy).