Prestashop hiding category description because of pagination - pagination

I've noticed something weird about our prestashop store - the category description that's displayed on page 1 disappears when the customer switches to any other page.
https://vipkoszulka.pl/91-pielegniarka
https://vipkoszulka.pl/91-pielegniarka?page=2
(below the products, above the footer. the div contains category title as well)
Furthermore, if you go from page 1 to any other page and then back to page 1, the category description is gone as well. The div that's supposed to contain all the info (#js-product-list-bottom) is just empty.
Can someone point me out which controller is responsible for this? I found part of the script that's responsible for pagination in ProductListingFrontController.php:
ProductSearchQuery $query,
ProductSearchResult $result
) {
$pagination = new Pagination();
$pagination
->setPage($query->getPage())
->setPagesCount(
(int) ceil($result->getTotalProductsCount() / $query->getResultsPerPage())
)
;
$totalItems = $result->getTotalProductsCount();
$itemsShownFrom = ($query->getResultsPerPage() * ($query->getPage() - 1)) + 1;
$itemsShownTo = $query->getResultsPerPage() * $query->getPage();
$pages = array_map(function ($link) {
$link['url'] = $this->updateQueryString(array(
'page' => $link['page'] > 1 ? $link['page'] : null,
));
return $link;
}, $pagination->buildLinks());
//Filter next/previous link on first/last page
$pages = array_filter($pages, function ($page) use ($pagination) {
if ('previous' === $page['type'] && 1 === $pagination->getPage()) {
return false;
}
if ('next' === $page['type'] && $pagination->getPagesCount() === $pagination->getPage()) {
return false;
}
return true;
});
return array(
'total_items' => $totalItems,
'items_shown_from' => $itemsShownFrom,
'items_shown_to' => ($itemsShownTo <= $totalItems) ? $itemsShownTo : $totalItems,
'current_page' => $pagination->getPage(),
'pages_count' => $pagination->getPagesCount(),
'pages' => $pages,
// Compare to 3 because there are the next and previous links
'should_be_displayed' => (count($pagination->buildLinks()) > 3),
);
}
But it only deals with products, not the description itself.

This is not really an issue. As long as you don't have a description on the second page, it's ok from the SEO perspective. The most important is to have a description available on the first page when you visit the page directly.

Related

Detecting a category page in the isCategoryPage method

I currently have an SCA website that has sub categories that need to display as a category page, and not a Product listing page. (i.e. display the categories, not the products).
Currently, I have modified the isCategoryPage to override the Facets.Views.isCategoryPage such that it does this correctly. However, when doing a search on the site - it breaks that page with a blank page.
I am currently stuck at figuring out how to detect if I am on a search page rather than a category page.
The code is thus:
...
// #Overrides Facets.Views.isCategoryPage
isCategoryPage: function isCategoryPage(translator) {
var currentFacets = translator.getAllFacets();
var categories = translator.getCategoryPath();
if (<--IsSearchPage() === true --->) {
return (_.keys(categories[categories.length-1].categories).length !== 0);
} else {
return (currentFacets.length === 1 &&
currentFacets[0].id === 'category' &&
categories &&
CategoryHelper.showCategoryPage(categories)
);
}
},
...
As you can see the if statement is where I need a bit of help.
if (<--IsSearchPage() === true --->) {
What method, function, code would detect if the page is a search page. Or if the page url has /search in the url. (either would work).
Thank you.
The proper update, after much trial and error:
isCategoryPage: function isCategoryPage(translator) {
var currentFacets = translator.getAllFacets();
var categories = translator.getCategoryPath();
if (categories) {
return (_.keys(categories[categories.length-1].categories).length !== 0);
} else {
return (currentFacets.length === 1 &&
currentFacets[0].id === 'category' &&
categories &&
CategoryHelper.showCategoryPage(categories)
);
}
},

react-virtualized - how do I use this as a true infinite scroller

I can't find any code example or docs that answers this:
Achieve almost complete infinite scroll -> unknown # of items, but there is a finite amount that may be infeasible to compute beforehand - e.g. at some point the list needs to stop scrolling
Can I trigger first load of data from within InfiniteScroller/List - it seems you need to pass in a data source that is populated with initial page
I am using this example:
https://github.com/bvaughn/react-virtualized/blob/master/docs/creatingAnInfiniteLoadingList.md
and:
https://github.com/bvaughn/react-virtualized/blob/master/source/InfiniteLoader/InfiniteLoader.example.js
along with CellMeasurer for dynamic height:
https://github.com/bvaughn/react-virtualized/blob/master/source/CellMeasurer/CellMeasurer.DynamicHeightList.example.js
The docs for InfiniteLoader.rowCount say:
"Number of rows in list; can be arbitrary high number if actual number is unknown."
So how do you indicate there are no more rows.
If anyone can post an example using setTimeout() to simulate dynamic loaded data, thanks. I can likely get CellMeasurer working from there.
Edit
This doesn't work the way react-virtualized creator says it should or the infinite loading example implies.
Calls:
render(): rowCount = 1
_rowRenderer(index = 0)
_isRowLoaded(index = 0)
_loadMoreRows(startIndex = 0, stopIndex = 0)
_rowRenderer(index = 0)
end
Do I need to specify a batch size or some other props?
class HistoryBrowser extends React.Component
{
constructor(props,context,updater)
{
super(props,context,updater);
this.eventEmitter = new EventEmitter();
this.eventEmitter.extend(this);
this.state = {
history: []
};
this._cache = new Infinite.CellMeasurerCache({
fixedWidth: true,
minHeight: 50
});
this._timeoutIdMap = {};
_.bindAll(this,'_isRowLoaded','_loadMoreRows','_rowRenderer');
}
render()
{
let rowCount = this.state.history.length ? (this.state.history.length + 1) : 1;
return <Infinite.InfiniteLoader
isRowLoaded={this._isRowLoaded}
loadMoreRows={this._loadMoreRows}
rowCount={rowCount}
>
{({ onRowsRendered, registerChild }) =>
<Infinite.AutoSizer disableHeight>
{({ width }) =>
<Infinite.List
ref={registerChild}
deferredMeasurementCache={this._cache}
height={200}
onRowsRendered={onRowsRendered}
rowCount={rowCount}
rowHeight={this._cache.rowHeight}
rowRenderer={this._rowRenderer}
width={width}
/>}
</Infinite.AutoSizer>}
</Infinite.InfiniteLoader>
}
_isRowLoaded({ index }) {
if (index == 0 && !this.state.history.length)
// No data yet, force load
return false;
}
_loadMoreRows({ startIndex, stopIndex }) {
let self = this;
for (let i = startIndex; i <= stopIndex; i++) {
this.state.history[startIndex] = {loading: true};
}
const timeoutId = setTimeout(() => {
delete this._timeoutIdMap[timeoutId];
for (let i = startIndex; i <= stopIndex; i++) {
self.state.history[i] = {loading: false, text: 'Hi ' + i };
}
promiseResolver();
}, 10000);
this._timeoutIdMap[timeoutId] = true;
let promiseResolver;
return new Promise(resolve => {
promiseResolver = resolve;
});
}
_rowRenderer({ index, key, style }) {
let content;
if (index >= this.state.history.length)
return <div>Placeholder</div>
else if (this.state.history[index].loading) {
content = <div>Loading</div>;
} else {
content = (
<div>Loaded</div>
);
}
return (
<Infinite.CellMeasurer
cache={this._cache}
columnIndex={0}
key={key}
rowIndex={index}
>
<div key={key} style={style}>{content}</div>
</Infinite.CellMeasurer>
);
}
}
The recipe you linked to should be a good starting place. The main thing its missing is an implementation of loadNextPage but that varies from app to app based on how your state/data management code works.
Can I trigger first load of data from within InfiniteScroller/List - it seems you need to pass in a data source that is populated with initial page
This is up to you. IMO it generally makes sense to just fetch the first "page" of records without waiting for InfiniteLoader to ask for them- because you know you'll need them. That being said, if you give InfiniteLoader a rowCount of 1 and then return false from isRowLoaded it should request the first page of records. There are tests confirming this behavior in the react-virtualized GitHub.
The docs for InfiniteLoader.rowCount say: "Number of rows in list; can be arbitrary high number if actual number is unknown."
So how do you indicate there are no more rows.
You stop adding +1 to the rowCount, like the markdown file you linked to mentions:
// If there are more items to be loaded then add an extra row to hold a
loading indicator.
const rowCount = hasNextPage
? list.size + 1
: list.size

Cakephp 3 - Remove empty post from pagination

I'm working on multi language website.
In the English version of the website all works properly, because I entered translations.
$blogPosts = $this->BlogPosts->find('all')->where(['BlogPosts.active' => 1]);
$this->set('blogPosts',$this->paginate($blogPosts));
If I changed the language of website I would like to remove all the posts whose translation of the title is not entered.
I tried this, but it does not work:
$blogPosts = $this->BlogPosts->find('all')->where(['BlogPosts.active' => 1,'BlogPosts.title IS NOT' => null]);
$this->set('blogPosts',$this->paginate($blogPosts));
Still printed posts without titles.
How to solve this problem?
Try this conditions:
public function index()
{
$this->paginate['conditions'] = ['BlogPosts.active' => true , 'BlogPosts.title IS NOT' => null, 'BlogPosts.title !=' => ' '];
$this->paginate['order'] = ['BlogPosts.id' => 'desc'];
$this->paginate['limit'] = 4;
$blogPosts = $this->paginate($this->BlogPosts);
$this->set(compact('blogPosts'));
$this->set('_serialize', ['blogPosts']);
}
Query:
SELECT *
FROM blogPosts BlogPosts
WHERE (
BlogPosts.active = 1
AND BlogPosts.title IS NOT NULL
AND BlogPosts.title != ''
)
ORDER BY BlogPosts.id desc
LIMIT 4 OFFSET 0
I think faced with simmilar issue before. The pagination didn't worked as I excepted when I set order, limit together with custom where condition.
Try this:
$this->paginate['order'] = ['BlogPosts.id' => 'desc'];
$this->paginate['limit'] = 4;
$query = $this->BlogPost->find()
->select(['id', 'title', 'active'])
->where(['BlogPost.active' => true, 'BlogPost.title IS NOT' => null, 'BlogPost.id !=' => ''])
$data = $this->paginate($query);
$this->set('BlogPost', $data);

How to insert text on post link Wordpress?

only post link current: http://mydomain/post-name
I want change only post link : http://mydomain/blog/post-name
In the permalink page (Settings > Permalinks), select the last option to enter a custom permalink structure and enter this :
/blog/%postname%/
It will prepend all your post urls with /blog/.
UPDATE
To prefix posts only, use the following function in your functions.php :
function add_rewrite_rules( $wp_rewrite )
{
$new_rules = array(
'blog/(.+?)/?$' => 'index.php?post_type=post&name='. $wp_rewrite->preg_index(1),
);
$wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
}
add_action('generate_rewrite_rules', 'add_rewrite_rules');
function change_blog_links($post_link, $id=0)
{
$post = get_post($id);
if( is_object($post) && $post->post_type == 'post'){
return home_url('/blog/'. $post->post_name.'/');
}
return $post_link;
}
add_filter('post_link', 'change_blog_links', 1, 3);

Drupal: Create custom search

I'm trying to create a custom search but getting stuck.
What I want is to have a dropdownbox so the user can choose where to search in.
These options can mean 1 or more content types.
So if he chooses options A, then the search will look in node-type P,Q,R.
But he may not give those results, but only the uid's which will be then themed to gather specific data for that user.
To make it a little bit clearer, Suppose I want to llok for people. The what I'm searching in is 2 content profile types. But ofcourse you dont want to display those as a result, but a nice picture of the user and some data.
I started with creating a form with a textfield and the dropdown box.
Then, in the submit handler, i created the keys and redirected to another pages with those keys as a tail. This page has been defined in the menu hook, just like how search does it.
After that I want to call hook_view to do the actual search by calling node_search, and give back the results.
Unfortunately, it goes wrong. When i click the Search button, it gives me a 404.
But am I on the right track? Is this the way to create a custom search?
Thx for your help.
Here's the code for some clarity:
<?php
// $Id$
/*
* #file
* Searches on Project, Person, Portfolio or Group.
*/
/**
* returns an array of menu items
* #return array of menu items
*/
function vm_search_menu() {
$subjects = _vm_search_get_subjects();
foreach ($subjects as $name => $description) {
$items['zoek/'. $name .'/%menu_tail'] = array(
'page callback' => 'vm_search_view',
'page arguments' => array($name),
'type' => MENU_LOCAL_TASK,
);
}
return $items;
}
/**
* create a block to put the form into.
* #param $op
* #param $delta
* #param $edit
* #return mixed
*/
function vm_search_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Algemene zoek');
return $blocks;
case 'view':
if (0 == $delta) {
$block['subject'] = t('');
$block['content'] = drupal_get_form('vm_search_general_form');
}
return $block;
}
}
/**
* Define the form.
*/
function vm_search_general_form() {
$subjects = _vm_search_get_subjects();
foreach ($subjects as $key => $subject) {
$options[$key] = $subject['desc'];
}
$form['subjects'] = array(
'#type' => 'select',
'#options' => $options,
'#required' => TRUE,
);
$form['keys'] = array(
'#type' => 'textfield',
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Zoek'),
);
return $form;
}
function vm_search_general_form_submit($form, &$form_state) {
$subjects = _vm_search_get_subjects();
$keys = $form_state['values']['keys']; //the search keys
//the content types to search in
$keys .= ' type:' . implode(',', $subjects[$form_state['values']['subjects']]['types']);
//redirect to the page, where vm_search_view will handle the actual search
$form_state['redirect'] = 'zoek/'. $form_state['values']['subjects'] .'/'. $keys;
}
/**
* Menu callback; presents the search results.
*/
function vm_search_view($type = 'node') {
// Search form submits with POST but redirects to GET. This way we can keep
// the search query URL clean as a whistle:
// search/type/keyword+keyword
if (!isset($_POST['form_id'])) {
if ($type == '') {
// Note: search/node can not be a default tab because it would take on the
// path of its parent (search). It would prevent remembering keywords when
// switching tabs. This is why we drupal_goto to it from the parent instead.
drupal_goto($front_page);
}
$keys = search_get_keys();
// Only perform search if there is non-whitespace search term:
$results = '';
if (trim($keys)) {
// Log the search keys:
watchdog('vm_search', '%keys (#type).', array('%keys' => $keys, '#type' => $type));
// Collect the search results:
$results = node_search('search', $type);
if ($results) {
$results = theme('box', t('Zoek resultaten'), $results);
}
else {
$results = theme('box', t('Je zoek heeft geen resultaten opgeleverd.'));
}
}
}
return $results;
}
/**
* returns array where to look for
* #return array
*/
function _vm_search_get_subjects() {
$subjects['opdracht'] =
array('desc' => t('Opdracht'),
'types' => array('project')
);
$subjects['persoon'] =
array('desc' => t('Persoon'),
'types' => array('types_specialisatie', 'smaak_en_interesses')
);
$subjects['groep'] =
array('desc' => t('Groep'),
'types' => array('Villamedia_groep')
);
$subjects['portfolio'] =
array('desc' => t('Portfolio'),
'types' => array('artikel')
);
return $subjects;
}
To be honest, I haven't seen many people implement hook_search. Most just use Views, or, for advanced things, something like Faceted Search.
Did you consider using either for your current project? Why didn't it work?
you could also use a combination of hook_menu for your results, and db_queries with your custom (and optimized so faster) queries.
For example:
search/%/%
where the arguments could be whatever you need, for example the first one for minimum price, the second price to the maximum price, third for minimal bedrooms... Your url would look always like that:
search/200/400/null/3/ ...
I have used a null, but it could be anything that you prefer to consider this field as empty.
Then, from your select form you have just to redirect following the structure of this url and adding the parameters in its correct place.
It is probalby not the most beautiful way of building a url, but using this technique and hook_theme will allow you to have an unlimited flexibility. I can show you a project where we are using this technique and, I think it looks pretty good :-).
Any comment regarding this would be much aprreciated :-).

Resources