I need to add redirect for 30 urls in 3 stores. For that I have created a script, using that I can add the urls, but the issue with the script is if the request path already exists I have to delete the entry and insert the new one. I have used the below code for that, it doesn't deletes the already existing entry(is_system=>1 for this entry). Can anyone help me solve this.
$rewrite_collection = Mage::getModel('core/url_rewrite')->getCollection();
$rewrite_collection->addFieldToFilter('request_path', array('eq' =>
$request_path));
$rewrite_collection->addFieldToFilter('store_id', array('eq' => 1));
$rewrite_collection_count = $rewrite_collection->count();
if($rewrite_collection_count < 0){
foreach ($rewrite_collection->getItems() as $rewrite){
$rewrite->delete();
}
}
Mage::getModel('core/url_rewrite')
->setStoreId(1)
->setIsSystem(0)
->setOptions('RP')
->setIdPath($id_path)
->setRequestPath($request_path)
->setTargetPath($target_path)
->save();
if($rewrite_collection_count < 0){
The above code, only check the count is less than zero.
Please change the code as
if($rewrite_collection_count > 0){
foreach ($rewrite_collection->getItems() as $rewrite){
$rewrite->delete();
}
}
Allow me to bring some ineteresting elements to the accepted answer, that you'll be able to use for all your future delete/save operations :
$transaction = Mage::getResourceModel('core/transaction');
foreach ($rewrite_collection->getItems() as $rewrite){
$transaction->addObject($rewrite);
}
$transaction->delete(); //or $transaction->save() when you need
This allows you to delete/save all the objects you give to the transaction object to be saved/deleted in only one SQL transaction, and roll it back if an error occurs (automatically done if an exception is raised during the save of one of the models).
Also, try to make a habit of calling your collections this way :
$rewrite_collection = Mage::getResourceModel('core/url_rewrite_collection');
instead of :
$rewrite_collection = Mage::getModel('core/url_rewrite')->getCollection();
Fewer steps.
Related
I'm creating a dashboard for myself that helps me keep track of the Facebook ads I'm running.
What I've not been able to figure out is:
How can I retrieve an array of ad IDs for all ads that are active or could soon be active after no further action on my part?
In other words, I want all ads that I've set to Active and that exist within Adsets and Campaigns that are active (and therefore these ads are live right now)... plus all the ads that from my perspective are Active but that Facebook has set to another status such as Pending Review (and will soon set back to Active).
I have some code below, but the problem is that it also accidentally includes Pending ads that--once reviewed and approved by Facebook--will be inactive rather than active (because I've set them that way). And I do NOT want this type of ad to be included in my report.
My report should only show me ones where I'm actively spending money or have the potential to spend money as soon as FB approves them.
I think I understand the difference between configured_status and effective_status in AbstractArchivableCrudObjectFields, but I don't know that it's enough to help me because I have lots of ads set to Active that are within Adsets that are Inactive, and I don't want to see those listed in my report.
Any recommendations?
public function getActiveAdIds() {
$key = 'activeAdIds';
$adIdsJson = Cache::get($key);
if ($adIdsJson) {
$adIds = json_decode($adIdsJson);
} else {
$adsResponse = $this->getAdsByStatus([ArchivableCrudObjectEffectiveStatuses::ACTIVE, ArchivableCrudObjectEffectiveStatuses::PENDING_REVIEW]);
$ads = $adsResponse->data;
$adIds = [];
foreach ($ads as $ad) {
$adIds[] = $ad->id;
}
$adIdsJson = json_encode($adIds);
Cache::put($key, $adIdsJson, 1);
}
return $adIds;
}
public function getAdsByStatus($statuses) {
$params = [\FacebookAds\Object\Fields\AbstractArchivableCrudObjectFields::EFFECTIVE_STATUS => $statuses];
$adAccount = new AdAccount(self::ACT_PREPEND . $this->fbConfig['account_id']);
$cursor = $adAccount->getAds([], $params);
$response = $cursor->getResponse();
$jsonString = $response->getBody();
return json_decode($jsonString);
}
I get stats based on assets for my active campaigns. I have 119 ad accounts. This is php code which I used it for this purpose (any suggestion to improve it will be appreciated):
$fields = array(AdsInsightsFields::ACCOUNT_NAME,AdsInsightsFields::CAMPAIGN_ID,
AdsInsightsFields::CAMPAIGN_NAME, AdsInsightsFields::ADSET_ID,
AdsInsightsFields::ADSET_NAME,AdsInsightsFields::DATE_START,
AdsInsightsFields::DATE_STOP,AdsInsightsFields::REACH,
AdsInsightsFields::SPEND, AdsInsightsFields::IMPRESSIONS,
AdsInsightsFields::CLICKS, AdsInsightsFields::WEBSITE_CLICKS,
AdsInsightsFields::CALL_TO_ACTION_CLICKS,AdsInsightsFields::ACTIONS,
AdsInsightsFields::TOTAL_ACTIONS,AdsInsightsFields::CPC,
AdsInsightsFields::CPM,AdsInsightsFields::CPP,
AdsInsightsFields::CTR,AdsInsightsFields::OBJECTIVE,);
$params_c['date_preset'] = AdDatePresetValues::YESTERDAY;
$params_c['time_increment'] = 1;
$params_c['action_attribution_windows'] = array('1d_view', '28d_click');
$params_c['effective_status'] = AdStatusValues::ACTIVE;
$params_c['level'] = AdsInsightsLevelValues::ADSET;
$params_c['filtering'] = [array("field"=>"campaign.delivery_info",
"operator"=>"IN",
"value"=>array("active"))];
$params_c['fields']= $fields;
try{
// Initialize a new Session and instanciate an Api object
Api::init(self::api_key, self::secret_token, self::extended_token)->getHttpClient()->setCaBundlePath( $this->path_cert);
// The Api object is now available trough singleton
$api = Api::instance();
$user = new \FacebookAds\Object\Business($business_id);
$user->read(array(BusinessFields::ID));
//get all ad_account from Business
$accounts = $user->getAssignedAdAccounts(
array(
AdAccountFields::ID,
),
array('limit'=>1000,)
);
} catch (FacebookAds\Exception\Exception $ex) {
return $ex->getMessage();
}
if(isset($accounts) && ($accounts->count() > 0)):
do{
$ad_account = $accounts->current();
$adset_insights = $ad_account->getInsights($fields,$params_c);
do {
$adset_insights->fetchAfter();
} while ($adset_insights->getNext());
$adsets = $adset_insights->getArrayCopy(true);
}
while ($accounts->current());
endif;
If you include the adset{end_time} field in the query for the ad, you can assume that ad is not actually running if the end_time was in the past. This is how we get a base list of ads to query on.
The next step we take (which probably won't help you, unfortunately, but may help others) is building a batch of simple requests (one per ad) to see if there are any insights data for that day. If the response is an empty 'data' array, we can remove that ID from the ad list.
After we've reduced the size of the ad list with those two steps we can then make requests to run all of our breakdown reports. This method almost cut our API requests in half.
I have yet to find a way to do a "give me all ads that are for sure running this day" query in one step.
Edit:
I just found a better way to do this.... :
curl -G \
-d 'access_token=<ACCESS_TOKEN>' \
-d 'level=campaign' \
-d 'filtering=[{field:"ad.impressions",operator:"GREATER_THAN",value:0}]' \
'https://graph.facebook.com/v2.7/act_<ACCOUNT_ID>/insights'
In WordPress, when registering an admin page or a Custom Post Type, we can specify the menu_position. However, if two pages share the same menu_position then only one of them will be displayed.
How to avoid such conflicts in a multi-plugins/multi-devs environment such as WordPress? How can one check that a menu_position is not already taken?
Any value from 5 to 100 or even null can result in a conflict.
Probably not the best solution but to minimise the risk try using decimals for positioning :) instead of "3" try using "3.1", "3.2", "3.3" etc...another way might be to use a function similar to:
function get_free_menu_position($start, $increment = 0.3)
{
foreach ($GLOBALS['menu'] as $key => $menu) {
$menus_positions[] = $key;
}
if (!in_array($start, $menus_positions)) return $start;
/* the position is already reserved find the closet one */
while (in_array($start, $menus_positions)) {
$start += $increment;
}
return $start;
}
to give you the closest free position to the one you want....You can read more about it here
I edited the 'comment' table in my Drupal MySQL database to add two rows. This is because I have a page that takes in a URL parameter, so while there is one page, I need to distinguish between the values of that parameter for comments. I'm having trouble editing my comment.module to edit the MySQL query. I can't find any kind of 'INSERT into...' query anywhere, not just in that file. I've looked through everything in the comment module folder.
What appears to be what affects the database insertion is the comment_publish_action() function in comment.module but I'm still running into some problems regarding the added columns, as they don't have default values.
Here's that function, 'typenode' and 'idofnode' are the added columns with test values:
function comment_publish_action($comment, $context = array()) {
if (isset($comment->subject)) {
$subject = $comment->subject;
$comment->status = COMMENT_PUBLISHED;
}
else {
$cid = $context['cid'];
$subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid' => $cid))->fetchField();
db_update('comment')
->fields(array(
'status' => COMMENT_PUBLISHED,
'typenode' => 'player',
'idofnode' => 1239
))
->condition('cid', $cid)
->execute();
}
watchdog('action', 'Published comment %subject.', array('%subject' => $subject));
}
Edit comment.module is not good idea. During next core updates all changes will be lost. Better to create a custom module and implement some hooks there.
There is function comment_save($comment) which perform steps to insert / update new comment. In this function you can find a line drupal_write_record('comment', $comment); which do insert or update of db table 'comment' (dependence on logic). But before this line there is hook module_invoke_all('comment_presave', $comment); which allows you to modify $comment object before it will be store in database. This is good way to go - implement this hook in custom module and do modifications there.
function custom_module_comment_presave($comment) {
//add rows info here
}
I am having an issue with creating and adding sales/quote_address objects to the multishipping checkout process. Currently, whenever I create a new address object, it is just reusing the exact same object over and over; Thus, when I add items to one address, it will add them to all addresses. As a check, I put a for loop after my main loop to echo out all of the ID's of the created addresses - it always echos out the number 3. When i try to dynamically change the ID of the newly created addresses(commented out section) they won't even show up at all in the final for loop. My code is as follows:
//dynamically create the addresses and add them to the shipping information screen
$idCounter = 1;
foreach($dropshippersCombineWProducts as $dropshippersWCProducts) {
$newAddress = null;
$newAddress = Mage::getSingleton('sales/quote_address')->importCustomerAddress($customAddress);
//$idCounter++;
//$newAddress->setId($idCounter);
foreach ($newAddress->getItemsCollection() as $item) {
$item->isDeleted(true);
}
foreach ($dropshippersWCProducts[1] as $_item) {
$newAddress->addItem($_item);
}
$quote->setShippingAddress($newAddress);
$newAddress->collectShippingRates();
}
$addresses = $quote->getAllShippingAddresses();
foreach ($addresses as $address) {
echo $address->getId();
}
Any help would be much appreciated.
The getSingleton method always returns the same object instance. Try changing that call to getModel and see if it doesn't fix the problem for you.
Ok, its possible to add a new attribute set in magento using something like the following:
$entitySetup = new Mage_Eav_Model_Entity_Setup;
$entitySetup->addAttributeSet('catalog_product', $setName);
But how can i base the set on an existing set like the default. This option is available in the admin section so its possible.
I did this 6 months ago, I do not have the code anymore, but I know you have to use the initFromSkeleton() method on your attribute set. You can search Magento's code for calls to this function, there are very few calls (just one perhaps). It will show you its usage.
EDIT: I remember I had the very same problem you are talking about, and I mailed about it. Here is the usage I was advised:
$attrSet = Mage::getModel('eav/entity_attribute_set');
$attrSet->setAttributeSetName('MyAttributeSet');
$attrSet->setEntityTypeId(4);//You can look into the db what '4' corresponds to, I think it is for products.
$attrSet->initFromSkeleton($attrSetId);
$attrSet->save();
The initialization is done before the save.
// create attribute set
$entityTypeId = Mage::getModel('eav/entity')
->setType('catalog_product')
->getTypeId(); // 4 - Default
$newSet = Mage::getModel('eav/entity_attribute_set');
$newSet->setEntityTypeId($entityTypeId);
$newSet->setAttributeSetName(self::ATTRIBUTE_SET_NAME);
$newSet->save();
$newSet->initFromSkeleton($entityTypeId);
$newSet->save();
This is what worked for me.
$i_duplicate_attribut_set_id = 10; // ID of Attribut-Set you want to duplicate
$object = new Mage_Catalog_Model_Product_Attribute_Set_Api();
$object->create('YOUR_ATTRIBUT_SET_NAME', $i_duplicate_attribut_set_id);
Alex
Here you can find useful information about working with attribute sets.
Here:
$entityTypeId = Mage::getModel('eav/entity')
->setType('catalog_product') // This can be any eav_entity_type code
->getTypeId();
$attrSet = Mage::getModel('eav/entity_attribute_set');
$attrSetCollection = $attrSet->getCollection();
$attrSetCollection
->addFieldToFilter('entity_type_id', array('eq' => $entityTypeId))
->addFieldToFilter('attribute_set_name', array('eq' => 'Default')); // This can be any attribute set you might want to clone
$defaultAttrSet = $attrSetCollection->getFirstItem();
$defaultAttrSetId = $defaultAttrSet->getAttributeSetId();
$attrSet->setAttributeSetName('Assinaturas'); // This is the new attribute set name
$attrSet->setEntityTypeId($entityTypeId);
$attrSet->initFromSkeleton($defaultAttrSetId);
$attrSet->save();