Problems Saving Large Number of Attribute Option Labels in Magento - magento

I'm running into a problem in a Magento system where saving a large number of attributes either doesn't work at all, or only partially works. It appears to be a javascript related issue, and I was hoping someone on Stack Overflow had some "known science" for dealing with this situation, or could point me in the right direction.
The basic problem is, the Magento system in question has over 250 color attribute option labels. If an admin user attempts to manage these by doing the following
Navigating to Catalog -> Attributes -> Manage Attributes
Selecting the color attributes
Clicking on the Manage Label/Options tab
Editing the last Label Option
Clicking "Save and Continue Edit"
One of two things happens.
In Google Chrome on OS X, the button sticks in the "depressed" state, and after a period of time Google Chrome's "This page is not responsive" kill dialog comes up.
In a mozilla based browser on OS X, clicking the button makes the browser "think" for a bit, but it eventually submits the form. However, only a partial list of attribute labels is posted to the admin controller. This means the user can only edit the first 75 - 100 labels, since the other labels are never submitted.
I have reports from windows users describing the second behavior as well (browsers are non-specific)
The obvious answers are to either investigate the poorly performing javascript, or (Grouch Marx style) "don't do that". Before I spend the time profiling/excavating the javascript on that page, I was hoping there was some known fix for this, or specific knowledge as to what was causing the problem.
Magento CE 1.7.x, if it maters.
Update: The Javascript performance issues are a red herring. They're caused by the massive number of input fields being iterated through in
js/prototype/validation.js
Specifically in this try catch block
try {
if(this.options.stopOnFirst) {
result = Form.getElements(this.form).all(function(elm) {
if (elm.hasClassName('local-validation') && !this.isElementInForm(elm, this.form)) {
return true;
}
return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback});
}, this);
} else {
result = Form.getElements(this.form).collect(function(elm) {
if (elm.hasClassName('local-validation') && !this.isElementInForm(elm, this.form)) {
return true;
}
return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback});
}, this).all();
}
} catch (e) {
}
However, even if I short circuit this and have the function return true, the behavior of not saving all the labels persists.

You can try the variable max_input_vars (introduced in PHP 5.3.9), by default it's 1000 so that should be enough, but maybe your configuration uses a lower amount. But I imagine the form just doesn't get through due to the major performance issues you're experiencing.
About the option labels: do they by any change have an uploader for an attribute-image? We had the exact same problem when we installed the GoMage Advanced Navigation extension on a shop with over 300 manufacturer options (the extension uses Magento's built-in Flash-uploader).
We didn't have the extension for that feature so I disabled the uploader, but the extreme performance decrease was definitely in the 300 Flash-movies being loaded. Maybe you can try lazyloading the uploader on a per-option basis by inserting a button or link instead of the movie.
Hope this points you in the right (or exact) direction.

[Working SOLUTION]
Hello as Alan Storm mentioned, this ussue is related with the JS logic, that handles the validation of the option label inputs. I had this problem on a project of one of my clents and I wrote simple extension, that solves it.
You can dowload the exntesion for here: https://github.com/Jarlssen/Jarlssen_FasterAttributeOptionEdit
Basically the extension replaces the original option template with mine template. In my template I rewrote most of the JS in the bottom of the template and replaced the form inputs with div elements ( pseudo inputs ), so when the administrator click on the pseudo input, then its replaced with the real input. In this way we avoid validating all the inputs and we validate only edited and the new added entries. The extension works well if you add options on chunks, for example 500 entries per attribute save.
Hope, that helps.
Additional information: http://www.jarlssen.de/blog/2014/05/07/magento-timeout-saving-attribute-options-type-multiple-select-and-dropdown
Quick look at the pseudo generation code:
<tr class="option-row">
<?php foreach ($this->getStores() as $_store): ?>
<td>
<div class="replace-content pseudo-input input-text <?php if($_store->getId()==0): ?> required-option<?php endif; ?>" id="option[value][<?php echo $_value->getId() ?>][<?php echo $_store->getId() ?>]"><?php echo $_value->getData('store' . $_store->getId()) ?></div>
</td>
<?php endforeach; ?>
<td>
<div class="replace-content pseudo-input" id="option[order][<?php echo $_value->getId() ?>]"><?php echo $_value->getSortOrder() ?></div>
</td>
<td class="a-center default-checkbox">
<div id="option_<?php echo $_value->getId() ?>" class="checkbox-radio-container replace-content">
<?php if($_value->getChecked()) : ?>
<input class="input-radio" type="<?php echo $defaultChooserInputType; ?>" name="default[]" value="<?php echo $_value->getId() ?>" checked <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif;?>/>
<?php else : ?>
<?php if('radio' == $defaultChooserInputType) : ?>
<span class="fake-radio"></span>
<?php else : ?>
<span class="fake-checkbox"></span>
<?php endif; ?>
<?php endif; ?>
</div>
</td>
<td class="a-left actions-column" id="delete_button_container_<?php echo $_value->getId() ?>">
<div id="option[delete][<?php echo $_value->getId() ?>]" title="<?php echo $this->__('Delete') ?>" class="scalable left pseudo-delete-option">
<span class="pseudo-delete-button" option_id="<?php echo $_value->getId(); ?>">
<span>
<span><?php echo $this->__('Delete') ?></span>
</span>
</span>
</div>
</td>
</tr>

I had exactly this problem (POST truncated) and it comes from a suhosin patch that has a too little POST limit. (or the standard PHP post_max_size)
In your php.ini check these values and increase their values if needed (and restart apache) :
post_max_size
suhosin.post.max_vars
suhosin.request.max_vars
For your second probleme (JS performance issue), I can't help you

Sorry!!
I went through this same problem , solution follows below.
Explanation of the problem
problem
A customer has a very large base of tires that also have many cars added to the same , thereby to migrate moorings between tires and vehicles only 255 characters of the attributes of ids were inserted into the table with it causing error in the migration.
The magento inserts a string with ids separated by ,
The problem occurred in the table "catalog_product_entity_varchar" in the value field which by default is 255 characters if I put text and resolved .
Note : I know you modify the DB is not nice but unfortunately had to perform this operation.
Example product
Tire 175 / 65R14
-> Make ( + - 200 options)
-> Model (+ - 4mil options)
-> Series (+ - 15mil options)
-> Year
-> ...
att,

Same problem here. I solved with BELVG module "Attribute Pagination" : http://blog.belvg.com/attribute-admin-page-pagination-in-magento.html
It works properly.
Hope that helps.

Open your server's php.ini, search for max_input_vars and set its value to greater than 2500 will solve your problem
; How many GET/POST/COOKIE input variables may be accepted
max_input_vars = 5000

Related

Svelte {# if } block length is not possible. How to get the length of the if block

I have a page with products/items. Some with options that the user needs to choose and some with no options at all.
In my shopping cart page, I display this ordered items/products with the options user chose if needed. This is how I iterate over products/item and the options
{#each eachitem as item }
<li>
Here it is : {item.item.id} -- {item.price} -- {item.qty}
{#if item.item.checkedoptions.checkoptions === 0 }
<p> Display NO OPTIONS</p>
{:else}
{#each item.item.checkedoptions.checkoptions[1] as opti}
<li style="list-style-type : none">
Options : {opti.optionname} - {opti.optionvalue}
</li>
{/each}
{/if}
</li>
{/each}
The issue is when there are no options, I get the error in my dev tools that reads "Cannot read property 'length' of undefined", of course because item.item.checkedoptions.checkoptions[1] is empty. I tried to use length but couldn't figure out how to attach it to item.item.checkedoptions.checkoptions do I put it inside () or [] or what?
How do you write if statement that if item.... length === 0 {do something}?
If I can't get the length, how do I solve this problem, do I do something in the script before I iterate?
How do you solve this issue?
In your if statement you are not actually checking the length of checkoptions you are comparing it directly with 0
You should change this to #if item.item.checkedoptons.checkoptions.length === 0

Inserting an item into a thymeleaf iteration

I have a list of items that I iterate over as cards w/ thymeleaf:
<div th:each="show,iter : ${shows}" class="col-sm-6 col-xl-4 mb-5">
<div class="card">
...
</div
</div>
I want after every nth card to show an ad instead of the regular card but NOT skip the item in the list. I can't find a way to add the ad code as its own card without it skipping one of the items OR just messing up the UI.
My best thought is to add "dummy" items to the list itself, but that feels wrong.
Any ideas?
The main answer to this is that you want to do the manipulation on the server-side, NOT on the view. Then you can unit-test, cache, and simply display the results without a UI designer caring about any complicated code. All you're really doing is inserting the ad at every nth position and then displaying the full list, one-by-one.
If that is somehow not an option, you can do something like the following. Let's say you have:
List<String> shows = new ArrayList<>(Arrays.asList("Game of Thrones",
"Daniel Tiger's Neighborhood",
"The Mandalorian",
"Breaking Bad",
"RugRats",
"Big Bang Theory",
"Knight Rider",
"Quantum Leap",
"Friends",
"Gilligan's Island"));
model.addAttribute("shows", shows);
model.addAttribute("ad", "StackOverflow");
model.addAttribute("cardsToDisplay", new ArrayList<>()); //ignore a capacity for simplicity for now
Then you can do:
<th:block th:with="cardsToDisplay = ${cardsToDisplay}">
<th:block th:each="show : ${shows}">
<!-- add the first show and every 3 thereafter, add the ad -->
<th:block th:if="${showStat.index % 2 == 0 && showStat.index != 0}">
<th:block th:text="${cardsToDisplay.add(ad)}" th:remove="all"></th:block><!-- or however you are getting your ad -->
</th:block>
<th:block th:text="${cardsToDisplay.add(show)}" th:remove="all"></th:block>
</th:block>
<!-- display the manipulated list -->
<div th:each="theCard : ${cardsToDisplay}" class="col-sm-6 col-xl-4 mb-5">
<div th:text="${theCard}" class="card"></div>
</div>
</th:block>
Then your output would be:
Game of Thrones
Daniel Tiger's Neighborhood
StackOverflow
The Mandalorian
Breaking Bad
StackOverflow
RugRats
Big Bang Theory
StackOverflow
Knight Rider
Quantum Leap
StackOverflow
Friends
Gilligan's Island
Thymeleaf implicitly gives you this construct of showStat because we declare a variable called show. You need th:remove="all" to hide the output of the add operation.
Change the number 2 as needed to represent n.
You can alternatively do this work in Javascript, but doing so introduces another skill that someone on your team would maintain.

Get value from dropdown after submit in codeigniter

I have dropdown list with some universities and in case the user is in a university that isn't in the list he can add it with an input box. My issue is that after the user clicks the submit button I can't get the value from the dropdown.
My code in the view is:
echo "University:";
?>
<div id="university2" style="display:block;">
<?php
echo form_dropdown('university2',$this->session->userdata('user'));
echo "&nbsp";
echo "<a href= javascript:ShowContentuni('university')>Other</a>";
?>
</div>
<div id="university" style="display:none;">
<?php
echo form_input('university',$this->input->post('university'));?>
</div>
And my code in the controller is:
if(isset($_POST['university']))$university= $this->input->post['university'];
else if(isset($_POST['university2']))$university=$this->input->post('university2');
Any ideas what I'm doing wrong??
It looks like there are two problems:
always overriding the value of $university with the post value of 'university2', even if it is empty
the form has two inputs called university, only the second one is being referred to
A quick fix would be to first delete the second 'university' form element, i.e. delete this:
echo form_input('university',$this->input->post('university'));
Then check that the user if the user has manually entered a university name, and use that if so. If the user did not enter a university name, use whatever the dropdown value is. The code would look like this:
$universityFromDropdown = $this->input->post('university');
$universityFromManualInput = $this->input->post('university2');
$university = is_string($universityFromManualInput)
&& strlen($universityFromManualInput) > 1
? $universityFromManualInput : $universityFromDropdown;

How to get mian image url form the resized one in wordpress?

I need a help. I need to get the main url of an image uploaded in wprdpress from the url of the re sized one's url. If possible the link of the attachment. Experts please help. Thanks in advanced.
Example-
re sized url-
1. http://www.example.com/wp-content/uploads/2013/05/image-1-90x120.jpg
2. http://www.example.com/wp-content/uploads/sites/9/2013/01/image-1-1040x320.png
3. http://www.example.com/wp-content/uploads/custom_upload_folder/image-1-430x210.jpg
what i'm looking for-
1. http://www.example.com/wp-content/uploads/2013/05/image-1.jpg or http://www.example.com/?attactment_id=12
2. http://www.example.com/wp-content/uploads/sites/9/2013/01/image-1.png or http://www.example.com/?attactment_id=12
3. http://www.example.com/wp-content/uploads/custom_upload_folder/image-1.jpg or ttp://www.example.com/?attactment_id=12
I can't use regex as i'm novice at this. again i can't use substr as image sizes of the resized ones are different.
attactment_id is the attachment id if the image is uploaded through the wordpress media uploader.
Thanks a lot.
You may not do it with substr, but some other string operations may help. This will work but I wouldn't recommend using it as it's not very efficient (too many var assignments) and should just give you an idea. However you may still use it if you're not going to parse these urls with some heavy production code.
$url = 'http://www.example.com/wp-content/uploads/2013/05/image-1-90x120.jpg';
list($first, $second, $third, $forth) = explode("-", $url);
echo $first.'-'.$second.'-'.$third.'.jpg';
There are plenty of examples of how to work with strings, especially with explode and implode functions, in order to make it efficient and more elegant.
On the other hand, I don't believe that Wordpress can anyhow retrieve back the original url out from the ones you have provided.
Using this code get main upload image url:
<?php
while ( have_posts() ) : the_post();
$image_id = get_post_thumbnail_id();
$image_url = wp_get_attachment_image_src($image_id,'full');
?>
<?php if ( has_post_thumbnail() ) { ?>
<img class="img_slide" src="<?php echo $image_url[0]; ?>" alt="<?php the_title(); ?>" />
<?php
endwhile;
wp_reset_query();
?>

Magento - Limit title length for seo

I'd really like to limit the title length on products in Magento.
What I've tried is adding 'maxlength' => 65 somewhere in \app\code\core\Mage\Adminhtml\Block\, without success.
Does someone know how to add this feature? In HTML it will just be adding length="65" maxlength="65".
Thanks for all affords. :)
I don't have the platform available to give you a proper walkthrough on setting this up, but I should be able to get you in the right place. First of all, do not make changes in the app/code/core files. Any changes you would absolutely need to make to those files you should do by making a copy of lets say app/code/core/Mage/Sales/something.php to app/code/local/Mage/Sales/something.php. Magento knows to automatically use the code in local to override the code in core.
If you take a look at the source code for that page you'll see where the name form is:
<input id="name" name="product[name]" value="" class=" required-entry input-text required-entry" type="text"/> </td>
<td class="scope-label"><span class="nobr">[STORE VIEW]</span></td>
</tr>
What's going on here is you'll notice under class we have "required-entry input-text and, well, required-entry again. These are the validation tags defined in js/prototype/validation.js. You will need to add some custom validation to it, and add it to your template file (not in core, it can break when you upgrade).
You'll notice in validation.js a section
Validation.add('IsEmpty', '', function(v) {
In this section you can add your custom validation. Lets say:
//make sure these are unique, I'm not checking
['validate-length', 'Your input needs to be less than x characters.', function(v) {
if (v.length > x) return false;
}],
If you need help finding the template location, take a look at: Finding Correct Templates and Blocks in Magento. You'll simply add validate-length class such as: class="required-entry validate-length..."
After almost 10 hours of searching I gave the up the "best" way, and choose for the roundabout.
Simply add
document.getElementById("name").setAttribute("maxlength", "65");
document.getElementById("name").setAttribute("length", "65");
to app/design/adminhtml/default/default/template/catalog/wysiwyg/js.phtml
You can add javascript validator to the product's name attribute. To achieve this, you need to update attribute with special value for frontend class. Just create sql upgrade:
$this->updateAttribute(
Mage_Catalog_Model_Product::ENTITY,
'name',
array(
'frontend_class' => 'validate-length maximum-length-65',
'note' => 'Max length is 65 characters'
)
);

Resources