This can be frustrating when you are new to wordpres and/or woocommerce. You just created your first product, and got 404 when trying to see it. Fortunately solution is quite simple. In backend panel go to “Settings”, then “Permalinks”. In “Common settings” section make sure “Post Name” is selected, if not, choose it – it will look like “http://newbl.blastar.biz/sample-post/”. Then look below, in “Product permalink base” section choose “Shop base” – it will look like “http://newbl.blastar.biz/shop/sample-product/”. Click “Save CHanges” and below you should see new box with .htaccess settings like:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

Just copy it and paste to your .htaccess. All links should work now!

If you just started playing with CloudKit, probably you will see that error trying to implement custom synchronization. Why need custom synchronization? Because receiving push message each time something changed in your cloud will be annoying. So probably you started with:

CKDatabase *database = [[CKContainer defaultContainer] privateCloudDatabase];
CKRecordZoneID *zoneID = [[CKRecordZoneID alloc] initWithZoneName:CKRecordZoneDefaultName ownerName:CKOwnerDefaultName];
CKFetchRecordChangesOperation *fetchRecordChangesOperation = [[CKFetchRecordChangesOperation alloc] initWithRecordZoneID:zoneID previousServerChangeToken:nil];
fetchRecordChangesOperation.fetchRecordChangesCompletionBlock = ^(CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData, NSError *error) {
    NSLog(@"fetchRecordChangesCompletionBlock %@", serverChangeToken);
    NSLog(@"fetchRecordChangesCompletionBlock %@", error);
};

and this is a place where you will see such error. Why this happens? Becouse you cannot fetch changed records for default zone. This applies both private and public cloud. So what to do? You need to create new zone before you will save anything to database:

CKDatabase *privateDatabase = [[CKContainer defaultContainer] privateCloudDatabase];
CKRecordZone *newZone = [[CKRecordZone alloc] initWithZoneName:@"ShareTestZone"];
    
[privateDatabase saveRecordZone:newZone completionHandler:^(CKRecordZone *zone, NSError *zoneError) {
    if (!zoneError) {
       NSLog(@"zone created");
    }
}];

After refreshing your cloud dashboard you will see your zone in “Private data” section. Now you can change zoneId to:

CKRecordZoneID *zoneID = [[CKRecordZoneID alloc] initWithZoneName:@"ShareTestZone" ownerName:CKOwnerDefaultName];

Of course you can use whatever name you want, this will also allow you to logically group records. Now in fetchRecordChangesCompletionBlock you should see:

fetchRecordChangesCompletionBlock <CKServerChangeToken: 0x7c17c770; data=AQAAAAAAAAADf/////////82R2EDHolICrHf6fPmTmm5>
fetchRecordChangesCompletionBlock (null)

And the second info means there is no error, and in first you have your CKServerChangeToken you need to save somewhere for next call.

Recently I had an NSDate object which had to be convered to unix timestamp and added to NSDictionary. But, what a surprise – I can’t add anything which is not object, and time_t is C element. So what to do? Solution as usual is very simple:

NSDate *date = your date here;
NSTimeInterval ts= [date timeIntervalSince1970]
myDictionary[@"myTimestamp"] = @(ts);

As result of this snipped, you will have NSNumber object in your dictionary instead of NSDate

Recently I noticed this may not be such obvious, but if you need to know when user pauses video or resumes playback, just use:

- (void)playerView:(YTPlayerView *)playerView didChangeToState:(YTPlayerState)state;

and since there are constants like kYTPlayerStatePlaying or kYTPlayerStatePaused  you can just do:

- (void)playerView:(YTPlayerView *)playerView didChangeToState:(YTPlayerState)state {
  switch (state) {
    case kYTPlayerStatePlaying:
      // do something here
      break;
    case kYTPlayerStatePaused:
      // do something else here
      break;
    default:
      break;
  }
}

but to make it work, do not forget to set proper delegate:

myPlayer.delegate = self;

and add YTPlayerViewDelegate in your header file for view controller:

@interface ViewController : UIViewController <YTPlayerViewDelegate>

There are also few other useful methods:

- (void)playerViewDidBecomeReady:(YTPlayerView *)playerView;
- (void)playerView:(YTPlayerView *)playerView didChangeToQuality:(YTPlaybackQuality)quality;
- (void)playerView:(YTPlayerView *)playerView receivedError:(YTPlayerError)error;

so there is pretty easy to handle most of player behavior.