I'm trying to write a product filter extension for opencart.
I assign size, color etc. options to the url like this:
index.php?route=product/category&path=59_63&size=57&color=black
The problem is when I click another color on the page the link goes like this:
index.php?route=product/category&path=59_63&size=57&color=black&color=brown
As you can see there are duplicated color arguments and it messes up the category listing.
How can I remove same arguments if there is?
The original opencart's link builder function:
public function link($route, $args = '', $connection = 'NONSSL') {
if ($connection == 'NONSSL') {
$url = $this->url;
} else {
$url = $this->ssl;
}
$url .= 'index.php?route=' . $route;
if ($args) {
$url .= str_replace('&', '&', '&' . ltrim($args, '&'));
}
return $this->rewrite($url);
}
There is not enough information to provide a correct answer, but I'll take a guess.
The problem seems to be with $args. It seems that you are taking $args from the URL and append to it your new color parameter.
If URL is index.php?route=product/category&path=59_63&size=57&color=black, then $args is path=59_63&size=57&color=black
You append to it color=brown and $args becomes path=59_63&size=57&color=black&color=brown.
If this is the case, you can do something like this:
parse_str($args,$url_params);
$url_params['color'] = 'brown'; //-- overwrites color=black with color=brown
$args = http_build_query($url_params);
Then pass $args to your link() function.
you don't have to remove duplicate parameters.
uou have not to add it.
use http_build_query() to create a query string
This is really nothing to do with opencart's link builder, it's done outside of that so as not to make any core changes. You need to set the value when you use $this->url->link in your controller code for your category. When you are getting all of the colors that you will use for filters, be sure to unset the color attribute passed into the second parameter of the link
Related
I want to access and use a variable passed in the URL within a WordPress page (not a template file, but the page itself).
Here's what I'm trying to accomplish. I want to create a single page that will display different WP content by using text passed in the URL in shortcodes and elsewhere on the page. So, if the URL was specified as:
www.greenneedham.org/blog/topicpage/?topic=solar
I will be able to use the passed text ('solar') in shortcodes and other places in the page, like this:
[documents category_name="solar" numberposts="-1" orderby="title" order="ASC"]
Ideally, I'd like to be able to create a variable or field that I can simply use within the page text. I just don't know how to accomplish that.
Here's what I've considered/tried:
1) There are plugins that access the passed variables (e.g. URL params), but that would seem to require nested shortcodes:
[documents category_name="[urlparam param="topic" default="home-energy-savings"/]" numberposts="-1" orderby="title" order="ASC"]
That doesn't work, and I'm not aware of any way to accomplish that.
Added: The Shortcode API documentation at http://codex.wordpress.org/Shortcode_API#Square_Brackets explains that the shortcode parser cannot handle square brackets within an attribute. Unfortunately, that's exactly what I'm trying to do.
If that won't work, The question is now - Is there some way within the page content of presenting a shortcode string that has been modified based on a query variable?
EndAdded
2) Using a filter to add the variable allows me to access the variable within a page template (e.g. page.php), but I want to use the value within the page itself.
3) Plugins to allow PHP snippets within a page or post. This seems to be generally discouraged. It's also complex, and the page itself (which may be used by non-coders) would get hard to use.
Any help or guidance would be much appreciated. Thanks!
add_shortcode('cat', 'get_name');
function get_name() {
return '[category_name='.$_GET['topic'].' numberposts="-1" orderby="title" order="ASC"]';
}
or echo do_shortcode('[category_name='.$_GET['topic'].' numberposts="-1" orderby="title" order="ASC"]'); // instead of return.
Should work as snippet function. then use it as [cat] shortcode
In addition, remember to sanitize your $_GET variable. Here's an example in the context of a simple shortcode to display a query variable within the page text, with reference to where I took the sanitizing code from:
//[query_string label="" class="" var=""] shortcode
function query_string_shortcode( $atts, $content = null ) {
//Create an array of default values for attributes. These don't have to be blank. If specified as attributes in the shortcode, those values will be used instead.
$a = shortcode_atts( array(
'label' => '',
'class' => '',
'var' => '',
), $atts );
//Create variables from atts/defaults
$label = $a['label'];
$class = $a['class'];
/*
* 1. Check if the variable is set
* 2. If so, sanitize the input for security (https://wordpress.stackexchange.com/questions/351292/sanitize-get-query-var-url-parameters)
* 3. Set the variable
*/
$var = ( isset( $_GET[$a['var']] ) ) ? sanitize_text_field( $_GET[$a['var']] ) : '';
if(!empty($label)) {
$label = "<b>$label</b>";
}
if(!empty($var)) {
$html = '<span class="pt-query ' . $class . '">' . $label . $var . '</span>';
return $html;
}
return;
}
add_shortcode( 'query_string', 'query_string_shortcode' );
Is there a way to get a list of products with their current canonical url on command line?
class Mage_Shell_UrlTest extends Mage_Shell_Abstract
{
public function run()
{
$productCollection = Mage::getResourceModel('catalog/product_collection')
->addStoreFilter()
->addUrlRewrite()
->addAttributeToSelect('*')
->setPageSize(10) // just for testing
->addFieldToFilter('visibility',Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
->addAttributeToFilter('status', array(
'eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED
));
Mage::getSingleton('cataloginventory/stock')
->addInStockFilterToCollection($productCollection);
foreach ($productCollection as $product) {
$url = $product->getUrlModel()->getUrl($product, array('_ignore_category' => true));
echo PHP_EOL . $url . PHP_EOL; // debug output
}
}
}
$shell = new Mage_Shell_UrlTest();
$shell->run();
I run it with php -f magento/shell/urlTest.php and this gives me something like this:
http://www.domain.com/urlTest.php/catalog/product/view/_ignore_category/1/id/307/s/any_valid_product_url_key
By default magento uses the same code to get the canonical url in Mage_Catalog_Block_Product_View::_prepareLayout() so the code should be fine. The only difference is for which store the code is executed.
It doesn't work in shell scripts because they are executed for the admin store (see Mage_Shell_Abstract::__construct() where Mage::app() is initialized). You could use Mage::app()->setCurrentStore('default'); where you need to replace default by your store and the right urls should be printed.
I maybe do not understand properly what you mean by "canonical url" but if you mean the url of the product with its ID and the key at the end that is normally the "canonical url" for magento as it is supposed to be unique at a moment, you should just take away the params of the getUrl. If you do not want the key, you can still use :
$url = substr($url, 0, strrpos('/s/'));
I hope it helps, if not, please precise the result you want.
I have been spending quiet some time figuring out how this works - so thought lets ask the question here.
I do understand how to customize URL's in Joomla with the help of router.php - at least I thought so. It is simple to create something like this
domain.com/country/id
example:
domain.com/germany/12
However, you wouldn't know that the id stands for a city. So in this example lets assume the city with id 12 is Berlin.
So for my custom component (named: countries) I would like that the following is displayed:
for view=countries (1st level)
domain.com/country
i.e.:
domain.com/germany
for view=city (2nd level)
domain.com/country/city-id
i.e.:
domain.com/country/berlin-12
(or perhaps just: domain.com/country/berlin - but I think the ID is required for the custom component to work - and any related modules on the page that read the ID to know what to do)
What do I have so far:
function CountriesBuildRoute(&$query)
{
$segments = array();
//if(isset($query['view'])) {
// $segments[] = $query['view'];
// unset( $query['view'] );
//}
if (isset($query['task'])) {
$segments[] = implode('/',explode('.',$query['task']));
unset($query['task']);
}
if (isset($query['id'])) {
$segments[] = $query['id'];
unset($query['id']);
}
if (isset($query['name'])) {
$segments[] = $query['name'];
unset($query['name']);
}
unset( $query['view'] );
return $segments;
}
function CountriesParseRoute( $segments )
{
$vars = array();
$app =& JFactory::getApplication();
$menu =& $app->getMenu();
$item =& $menu->getActive();
// Count segments
$count = count( $segments );
//Handle View and Identifier
switch( $item->query['view'] )
{
case 'countries':
if($count == 1) {
$vars['view'] = 'city';
}
break;
case 'city':
$id = explode( ':', $segments[$count-2] );
$name = explode( ':', $segments[$count-1] );
$vars['id'] = $id[0].'-'.$name;
break;
}
return $vars;
}
The way I am calling city pages from view countries is the following:
<a href="<?php echo JRoute::_('index.php?option=com_countries&view=city&id=' . (int)$item->id) .'&name='. $item->city_name; ?>">
Would be amazing if someone can help ! Cheers
If you want to get ride of IDs from urls you will have to add every country menu item or create rooter that will search for item id within database (bad idea with big websites). This will also require setting your homepage to one of your component views. Its easiest way.
When you build router you need two functions. First that will return SEF url CountriesBuildRoute and second that will translate SEF url back to query CountriesParseRoute. It is harder then you actually think to write SEF at this level. I will not write you whole router but only point you to right direction.
In Joomla 1.5 it was easier to make smth you want. If you have time look in rooter from some Joomla 1.5 component like (com_weblinks). CountriesBuildRoute returns array that will build your URL. For example when you return $query array looking like this: array('country','berlin') url will look like you want: domain.com/country/berlin. But reversing that process (something you will do in CountriesParseRoute) gonna be harder. You will have to check if first segment is a country (if it is second should be city).
So in function CountriesBuildRoute check what view is passed and build $segments array directly like you want for your url or selected view to be. Remember that single element from that array will be single segment from URL.
In function CountriesParseRoute check if first array element is a country (db checking, cached countries list, there are many ways to do it) then you will have to do the same with second element from array(if it exists).
I always created BuildRoute first as I wanted. Then spend hours on making parse route as precise and effective as only could be. You can spend hours or even few days if you want to make good router.
I'm trying to create a function that does a text replacement on the post content when its saved (the_content).
The stub function is below, but how do I obtain a reference to the post content, then return the filtered content back to the "publish_post" routine?
However, my replacement is either not working and/or not passing the updated post_content to the publish function. The values never get replaced.
function my_function() {
global $post;
$the_content = $post->post_content;
$text = " test ";
$post->post_content = str_ireplace($text, '<b>'.$text.'</b>', $the_content );
return $post->post_content;
}
add_action('publish_post', 'my_function');
When you mention the_content, are you referencing the template tag or the filter hook?
the_content as a filter hook only works on post content during database reads, not writes. The filter to use when modifying post content right before it is save to the db is content_save_pre.
Code Example
In your plugin or theme's functions.php, add your function, using $content as the argument. Modify the content any way you wish, and be sure to return $content.
Then use add_filter('filter_name', 'function_name') to run the function when the filter hook is encountered in WordPress.
function add_myself($content){
return $content." myself";
}
add_filter('content_save_pre','add_myself');
If I write a post that includes:
"To the end of posts, I like to add"
when saved to the database and displayed on the site, it will read:
"To the end of posts, I like to add myself".
Your example filter might be revised to look like this:
function my_function($content) {
$text = " test ";
return str_ireplace($text, '<b>'.$text.'</b>', $content );
}
add_filter('content_save_pre','my_function');
Probably easier to do something like this:
function my_function($post) {
$content = str_ireplace(" test ", '<b>'.$text.'</b>', $post->content);
return $content;
}
Less focus was on the interior of the function, but the idea is that you pass the object to the function in the () then call the directly rather than globalizing the value. It should be more direct that way.
the passed variable here is $id. This should work:
function my_function($id) {
$the_post = get_post($id);
$content = str_ireplace(" test ", '<b>'.$text.'</b>', $the_post->post_content);
return $content;
}
add_action('publish_post', 'my_function');
I need to make a simple site search with pagination in it; could anyone tell me how to do it without affecting the URL structure? Currently I'm using the default CodeIgniter URL structure and I have removed index.php from it. Any suggestions?
You could just use a url like /search/search_term/page_number.
Set your route like this:
$route['search/:any'] = "search/index";
And your controller like this:
function index()
{
$search_term = $this->uri->rsegment(3);
$page = ( ! $this->uri->rsegment(4)) ? 1 : $this->uri->rsegment(4);
// some VALIDATION and then do your search
}
Just to update this question. It is probably best to use the following function:
$uri = $this->uri->uri_to_assoc()
and the result will then put everything into an associative array like so:
[array]
(
'name' => 'joe'
'location' => 'UK'
'gender' => 'male'
)
Read more about the URI Class at CodeIgniter.com
Don't quite understand what you mean by "affecting the url structure". Do you mean you'd want pagination to occur without the URL changing at all?
The standard pagination class in CI would allow you to setup pagination so that the only change in the URL would be a number on the end
e.g if you had 5 results to a page your urls might be
http://www.example.com/searchresults
and then page 2 would be
http://www.example.com/searchresults/5
and page 3 would be
http://www.example.com/searchresults/10
and so on.
If you wanted to do it without any change to the URL then use ajax I guess.
Code Igniter disables GET queries by default, but you can build an alternative if you want the url to show the search string.
Your url can be in the notation
www.yoursite.com/index.php/class/function/request1:value1/request2:value2
$request = getRequests();
echo $request['request1'];
echo $request['request2'];
function getRequests()
{
//get the default object
$CI =& get_instance();
//declare an array of request and add add basic page info
$requestArray = array();
$requests = $CI->uri->segment_array();
foreach ($requests as $request)
{
$pos = strrpos($request, ':');
if($pos >0)
{
list($key,$value)=explode(':', $request);
if(!empty($value) || $value='') $requestArray[$key]=$value;
}
}
return $requestArray ;
}
source: http://codeigniter.com/wiki/alternative_to_GET/