Magento - entered data into wrong fields - mysql

We did something wrong when uploading our products to our database. SKU number ended up in description, and description ended up in SKU.
It is around 1.000 products, so manually doing this is not an option. Also, this is an old error that didnt get noticed until now, so many of the products have order history on them by now.
Is there a way to switch these fields?

Try to identify the product ids that have this problem.
If all of them are in this situation that it's easier.
The idea is to first get an all the products that need modifying
If you can get them manually do this:
$ids = array(1,3,5,6,7,8, ...);
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('description')->addAttributeToFilter('entity_id', $ids);
if all the products need modifying do this:
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('description');
After you have all the ids run this script:
foreach ($products as $product) {
Mage::getSingleton('catalog/product_action')->updateAttributes(
array($product->getId()), //id to update
array( //values to update
'sku' => $product->getDescription(),
'description' => $product->getSku()
),
0 //store id
);
}

Related

Add result of subquery to Eloquent query in Laravel 9

In Laravel 9 I am trying to add the result of a subquery to a query(for lack of better wording) and I am stuck. More concretely, I am trying to load all products and at the same time add information about whether the current user has bought that product.
Why do I want to do this?
I am currently loading all products, then loading all bought products, then comparing the 2 to determine if the user has bought a product, but that means extra queries which I would like to avoid. Pretend for the sake of this question that pagination doesn't exist(because when paginating the impact of those multiple queries is far diminished).
There is a many to many relationship between the 2 tables users and products, so these relationships are defined on the models:
public function products()
{
return $this->belongsToMany(Product::class);
}
and
public function users()
{
return $this->belongsToMany(User::class);
}
What I have tried so far:
I created a model for the join table and tried to use selectRaw to add the extra 'column' I want. This throws a SQL syntax error and I couldn't fix it.
$products = Product::query()
->select('id', 'name')
->selectRaw("ProductUser::where('user_id',$user->id)->where('product_id','products.id')->exists() as is_bought_by_auth_user")
->get();
I tried to use addSelect but that also didn't work.
$products = Product::query()
->select('id', 'name')
->addSelect(['is_bought_by_auth_user' => ProductUser::select('product_id')->where('user_id',$user?->id)->where('product_id','product.id')->first()])
->get();
I don't even need a select, I actually just need ProductUser::where('user_id',$user?->id)->where('product_id','product.id')->exists() but I don't know a method like addSelect for that.
The ProductUser table is defined fine btw, tried ProductUser::where('user_id',$user?->id)->where('product_id','product.id')->exists() with hardcoded product id and that worked as expected.
I tried to create a method on the product model hasBeenBoughtByAuthUser in which I wanted to check if Auth::user() bought the product but Auth wasn't recognized for some reason(and I thought it's not really nice to use Auth in the model anyway so didn't dig super deep with this approach).
$products = Product::query()
->select('id', 'name')
->addSelect(\DB::raw("(EXISTS (SELECT * FROM product_user WHERE product_users.product_id = product.id AND product_users.user_id = " . $user->id . ")) as is_bought_by_auth_user"))
->simplePaginate(40);
For all attempts $user=$request->user().
I don't know if I am missing something easy here but any hints in the right direction would be appreciated(would prefer not to use https://laravel.com/docs/9.x/eloquent-resources but if there is no other option I will try that as well).
Thanks for reading!
This should do,
$id = auth()->user()->id;
$products = Product::select(
'id',
'name',
DB::raw(
'(CASE WHEN EXISTS (
SELECT 1
FROM product_users
WHERE product_users.product_id = products.id
AND product_users.user_id = '.$id.'
) THEN "yes" ELSE "no" END) AS purchased'
)
);
return $products->paginate(10);
the collection will have purchased data which either have yes or no value
EDIT
If you want eloquent way you can try using withExists or withCount
i.e.
withExists the purchased field will have boolean value
$products = Product::select('id', 'name')->withExists(['users as purchased' => function($query) {
$query->where('user_id', auth()->user()->id);
}]);
withCount the purchased field will have count of found relationship rows
$products = Product::select('id', 'name')->withCount(['users as purchased' => function($query) {
$query->where('user_id', auth()->user()->id);
}]);

Woocommerce: How to update meta attribute value of all products programmatically

I have a meta attribute on my products that can be accessed like this:
get_post_meta( $product_id, '_disable_shipping', true );
I need to update _disable_shipping attribute of all products on MySQL or programmatically. Is there a simple way of doing it? I want to change all values to yes for all my products.
You can use the following MYSQL query , wp_postmeta depends on your wordpress database prefix
UPDATE `wp_postmeta` SET `meta_value` = 'yes' WHERE `meta_key` = '_disable_shipping'
You can create a plugin and put a function in it which runs through your products and updates every products meta value. If you don't know how you create a plugin, here is a tutorial for this: https://www.smashingmagazine.com/2011/09/how-to-create-a-wordpress-plugin/ It is done in minutes.
Please make sure you have a backup of your database before doing bulk actions to update your products.
The function could look something like this:
function disable_shipping_once(){
$products = get_posts(array('post_type' => 'product', 'numberposts' => -1) );
foreach($products as $product) :
$product_ID = $product->ID;
$meta_value = get_post_meta($product_ID, '_disable_shipping',true);
if($meta_value == "no") :
update_post_meta($product_ID, '_disable_shipping-include', 'yes' );
endif;
endforeach;
}
If you activate your plugin, this function will run. After that, you can deactivate it again.
This code should be pretty save, because it only updates post meta, if the value is "no", so there should not be any unintended updates of the posts.
Maybe there also is a plugin for bulk editing your products. This is the first I found which seems to be doing the job, haven't tested it yet: https://wordpress.org/plugins/custom-field-bulk-editor/

Cakephp Querybuilder : update rows with an identical field as selected one

My app's goal is to schedule posts through a franchise to its franchised.
The HQ schedules a post for a certain date and time, with text and potential image.
It creates the post with all necessary information in the database for each franchised(id, franchise_id, user_id, text, image, network, post_id)
post_id contains an id that is the same for each row that are completely identical besides the franchise_id.
When I add a post, it works well. But when editing, since it gets the ID of the post, it'll only edit the post that matches the id.
And that is fine when it is a franchised, it will then change the post_id to a custom value, and will be independent to the others.
But when it's the HQ(superadmin)logged in, I want him to edit all that matches the selected one by post_id.
Query builder is not something I'm used to and sometimes I thought about dropping it for standard SQL, but if it's there it's for a reason, so I would like your help in solving this with Cakephp's query builder.
public function edit($id = null){
$event = $this->Events->get($id);
if ($this->request->is(['post', 'put'])) {
$event = $this->Events->patchEntity($event, $this->request->data,['associated' => ['Networks'], ]);
if($isuper == 'true'){//if logged in user is superadmin
}else{
$event->user_id = $this->Auth->user('id');
}
if ($this->Events->save($event)) {
$this->Flash->success(__('your post has been updated'));
return $this->redirect(
[
'action' => 'index',
date('Y', $event->date->getTimestamp()),
date('m', $event->date->getTimestamp()),
$event->company_id
]
);
}
$this->Flash->error(__('unable to update your post'));
}
$this->set('event', $event);
$this->layout = 'ajax';
}
You could try making bulk updates using updateAll
Something like:
$this->Events->updateAll(
['field' => true], // whatever fields you are updating
['post_id' => 'some_id'] // the selected post_id
);

How get sum of field in the related table in one query in Yii2

Everyone,
I have 2 tables, that related via third:
Structure looks like below:
Playlist: id, channel_id, name, date
Files: id, name, duration
Playlist-rel-Files: list_id, file_id
I'm using ActiveRecord in my app. When I use such query to get last playlist:
$pl = Playlist::find()
->where(['channel_id' => $model->channel_id])
->orderBy(['date' => SORT_DESC])
->limit(1)
->one();
Then I use such code to get all files, that related with last playlist:
$f = $pl->files;
All is OK, and I get Array of files, but I don't need the list of them, I need only SUM of files duration, to get this SUM, I will need to run through array in foreach, my question is:
how can I modify my first query to get Playlist data AND sum of duration of this playlist's files in one query ? is it possible ?
What you are looking for is a statistical query. You can define a new relation for your count e.g
public function getFileCount() {
return $this->hasMany(Files::className(), ['id' => 'file_id'])
->viaTable('playlist-rel-files', ['playlist_id' => 'id'])
->sum('duration');
}
This is then accessible using the magic property $fileCount and can be added to the query via with for eager loading i.e:
$pl = Playlist::find()
->with('fileCount')
->where(['channel_id' => $model->channel_id])
->orderBy(['date' => SORT_DESC])
->one();

Minimising Database Queries in Wordpress when using Advanced Custom Fields

I'm working on a page which lists staff members for a large company and trying to minimise the number of times I'm forced to query the database as it gets quite complex and slow.
'person' is a custom post type (there are about 300 people)
'date_accredited' is a date field added via Advanced Custom Fields plugin.
Only accredited staff will have a 'date_accredited'.
I need to list every 'person' BUT, with ALL accredited staff listed first (so about 20 accredited staff come at the top).
At the moment, I am doing a call to WP_Query like:
$args = array(
'posts_per_page' => -1,
'post_type' => 'people',
'no_found_rows' => true,
'meta_key' => 'date_accredited'
);
$people = new WP_Query($args);
After that I'm doing:
while($people->have_posts()): $people->the_post();
$my_post_meta = get_post_meta($post->ID, 'date_accredited', true);
if (!empty($my_post_meta)) {
array_push($accredited, $post);
} else {
array_push($notAccredited, $post);
}
endwhile;
Leaving us with two arrays of 'person' objects. My thinking here was that I would be able to do something like the following to get the list I want:
foreach($accredited as $person):
personTile($person);
endforeach;
foreach($notAccredited as $person):
personTile($person);
endforeach;
I'm trying to avoid re-querying the database.
The personTile(); function was supposed to output various info and HTML (the_post_thumbnail() and various Advanced Custom Fields fields), but what I'm realising now is that none of this is included in the post objects I get from WP_Query(), so I'm forced to use things like:
get_the_post_thumbnail($person->ID)
get_permalink($person->ID)
get_field('date_accredited', $person->ID)
All of these cost another DB Query (each!), and worse still since they are in a loop each one happens around 300 times.
Is there any way to get the permalink, thumbnail and ACF fields to be included in the original DB Query? Would I need to resort to a custom MySQL Query???
Any other suggestions welcome!