Plugin Directory

Changeset 2744975


Ignore:
Timestamp:
06/20/2022 05:37:35 AM (4 years ago)
Author:
crowdaa
Message:

Added 1.2.0 release.

Location:
crowdaa-sync
Files:
6 added
17 edited
24 copied

Legend:

Unmodified
Added
Removed
  • crowdaa-sync/tags/1.2.0/CHANGELOG

    r2722017 r2744975  
    66
    77## [Unreleased]
     8
     9## [1.2.0] - 2022-06-14
     10
     11### Added
     12- Permissions/badges synchronization
     13- Synchronization database reset
     14
     15### Changed
     16- Separated categories synchronization from post synchronization
    817
    918## [1.1.0] - 2022-05-11
  • crowdaa-sync/tags/1.2.0/README.txt

    r2722534 r2744975  
    66Requires PHP: 7.3
    77Tested up to: 5.9
    8 Stable tag: 1.1.1
     8Stable tag: 1.2.0
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
  • crowdaa-sync/tags/1.2.0/admin/class-crowdaa-sync-add-info-api.php

    r2722017 r2744975  
    100100   */
    101101  public function get_opqueue_ajax() {
     102    $categories_opqueue = $this->get_categories_opqueue();
     103    $badges_opqueue = $this->get_badges_opqueue();
    102104    $articles_opqueue = $this->get_articles_opqueue();
    103105
    104106    wp_send_json([
    105107      'articles' => $articles_opqueue,
     108      'badges' => $badges_opqueue,
     109      'categories' => $categories_opqueue,
    106110    ]);
     111  }
     112
     113  public static function hash_badge(&$badge) {
     114    $data = [
     115      'name' => $badge->name,
     116      'description' => $badge->description,
     117      'access' => $badge->access,
     118      'management' => $badge->management,
     119      'createdAt' => $badge->createdAt,
     120    ];
     121
     122    if (isset($badge->updatedAt)) {
     123      $data['updatedAt'] = $badge->updatedAt;
     124    }
     125
     126    return (hash('sha256', serialize($data)));
     127  }
     128
     129  public static function hash_pmpro_membership(&$membership) {
     130    $data = [
     131      'name'          => ''.   $membership->name,
     132      'description'   => ''.   $membership->description,
     133      'allow_signups' => (int) $membership->allow_signups,
     134    ];
     135
     136    return (hash('sha256', serialize($data)));
     137  }
     138
     139  public static function hash_term(&$term) {
     140    $data = [
     141      'id'          => $term->term_id,
     142      'name'        => $term->name,
     143      'slug'        => $term->slug,
     144      'parent'      => $term->parent,
     145    ];
     146
     147    if (isset($term->rootParentId)) {
     148      $data['rootParentId'] = $term->rootParentId;
     149    }
     150
     151    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     152      global $wpdb;
     153      $memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_categories, [
     154        'category_id' => $term->term_id,
     155      ], ['membership_id']);
     156
     157      $data['memberships'] = $memberships;
     158    }
     159
     160    return (hash('sha256', serialize($data)));
     161  }
     162
     163  public static function hash_category(&$category) {
     164    $data = [
     165      'id'       => $category->_id,
     166      'name'     => $category->name,
     167      'pathName' => $category->pathName,
     168      'parentId' => $category->parentId,
     169    ];
     170
     171    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     172      $data['badges'] = $category->badges;
     173    }
     174
     175    return (hash('sha256', serialize($data)));
     176  }
     177
     178  /**
     179   * Get badges pending sync operations queue
     180   *
     181   * @since    1.0.0
     182   * @return array, object
     183   */
     184  public function get_badges_opqueue() {
     185    Crowdaa_Sync_Logs::log('Syncing, Badges OpQueue fetching');
     186
     187    $crowdaa_sync_articles_wp_to_api_enabled = (get_option('crowdaa_sync_articles_wp_to_api_enabled', 'yes') === 'yes');
     188    $crowdaa_sync_articles_api_to_wp_enabled = (get_option('crowdaa_sync_articles_api_to_wp_enabled', 'yes') === 'yes');
     189    $api_data_class = new Crowdaa_Sync_API();
     190    $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     191
     192    if(!get_option('crowdaa_auth_token')) {
     193      $result = [
     194        'error' => __('User is not connected', CROWDAA_SYNC_PLUGIN_NAME),
     195      ];
     196
     197      return ($result);
     198    }
     199
     200    $result = [
     201      'api_to_wp'  => [],
     202      'wp_to_api'  => [],
     203      'only_api'   => [],
     204      'only_wp'    => [],
     205      'remove_api' => [],
     206      'remove_wp'  => [],
     207    ];
     208
     209    if (!Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     210      return ($result);
     211    }
     212
     213    if (!$crowdaa_sync_articles_api_to_wp_enabled && !$crowdaa_sync_articles_wp_to_api_enabled) {
     214      return ($result);
     215    }
     216
     217    global $wpdb;
     218    $badges = $api_data_class->get_badges();
     219    $synced = $sync_db->get_synced_entries();
     220    $memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_membership_levels);
     221
     222    if (isset($badges->message)) {
     223      $result = [
     224        'error' => __('API query error : ', CROWDAA_SYNC_PLUGIN_NAME).$badges->message,
     225      ];
     226
     227      return ($result);
     228    }
     229
     230    Crowdaa_Sync_Logs::log('OpQueue building...', count($badges).' api badges and '.count($memberships).' wp permissions');
     231
     232    $badges_by_id = [];
     233    foreach ($badges as $badge) {
     234      $badge->hash = self::hash_badge($badge);
     235      $badges_by_id[$badge->_id] = $badge;
     236    }
     237
     238    $synced_by_api_id = [];
     239    $synced_by_wp_id = [];
     240    foreach ($synced as $item) {
     241      $item->badge_hash = $item->sync_data['badge_hash'];
     242      $item->membership_hash = $item->sync_data['membership_hash'];
     243      $synced_by_wp_id[$item->wp_id] = $item;
     244      $synced_by_api_id[$item->api_id] = $item;
     245    }
     246
     247    $memberships_by_id = [];
     248    foreach ($memberships as $membership) {
     249      $membership->hash = self::hash_pmpro_membership($membership);
     250      $memberships_by_id[$membership->id] = $membership;
     251    }
     252
     253    if ($crowdaa_sync_articles_wp_to_api_enabled) {
     254      foreach ($memberships_by_id as $id => $membership) {
     255        if (!array_key_exists($id, $synced_by_wp_id)) {
     256          $result['only_wp'][] = [
     257            'api_id' => null,
     258            'wp_id' => $membership->id,
     259            'name' => $membership->name,
     260            'description' => $membership->description,
     261            'public' => !!$membership->allow_signups,
     262            'hash' => $membership->hash,
     263          ];
     264        } else if ($synced_by_wp_id[$id]->membership_hash !== $membership->hash) {
     265          $result['wp_to_api'][] = [
     266            'api_id' => $synced_by_wp_id[$id]->api_id,
     267            'wp_id' => $membership->id,
     268            'name' => $membership->name,
     269            'description' => $membership->description,
     270            'public' => !!$membership->allow_signups,
     271            'hash' => $membership->hash,
     272          ];
     273        }
     274      }
     275
     276      foreach ($synced_by_wp_id as $wp_id => $synced_item) {
     277        if (!array_key_exists($wp_id, $memberships_by_id)) {
     278          $result['remove_api'][] = [
     279            'wp_id' => null,
     280            'api_id' => $synced_item->api_id,
     281          ];
     282        }
     283      }
     284    }
     285
     286    if ($crowdaa_sync_articles_api_to_wp_enabled) {
     287      foreach ($badges_by_id as $id => $badge) {
     288        if (!array_key_exists($id, $synced_by_api_id)) {
     289          $result['only_api'][] = [
     290            'api_id' => $badge->_id,
     291            'wp_id' => null,
     292            'name' => $badge->name,
     293            'description' => $badge->description,
     294            'public' => (array_search($badge->management, ['request', 'public']) !== false),
     295            'hash' => $badge->hash,
     296          ];
     297        } else if ($synced_by_api_id[$id]->badge_hash !== $badge->hash) {
     298          $result['api_to_wp'][] = [
     299            'api_id' => $badge->_id,
     300            'wp_id' => $synced_by_api_id[$id]->wp_id,
     301            'name' => $badge->name,
     302            'description' => $badge->description,
     303            'public' => (array_search($badge->management, ['request', 'public']) !== false),
     304            'hash' => $badge->hash,
     305          ];
     306        }
     307      }
     308
     309      foreach ($synced_by_api_id as $api_id => $synced_item) {
     310        if (!array_key_exists($api_id, $badges_by_id)) {
     311          $result['remove_wp'][] = [
     312            'wp_id' => $synced_item->wp_id,
     313            'api_id' => null,
     314          ];
     315        }
     316      }
     317    }
     318
     319    return ($result);
     320  }
     321
     322  public function get_categories_opqueue() {
     323    Crowdaa_Sync_Logs::log('Syncing, Categories OpQueue fetching');
     324
     325    $crowdaa_sync_articles_wp_to_api_enabled = (get_option('crowdaa_sync_articles_wp_to_api_enabled', 'yes') === 'yes');
     326    $crowdaa_sync_articles_api_to_wp_enabled = (get_option('crowdaa_sync_articles_api_to_wp_enabled', 'yes') === 'yes');
     327
     328    $result = [
     329      'api_to_wp'  => [],
     330      'wp_to_api'  => [],
     331      'only_api'   => [],
     332      'only_wp'    => [],
     333      'remove_api' => [],
     334      'remove_wp'  => [],
     335    ];
     336
     337    if (!$crowdaa_sync_articles_api_to_wp_enabled && !$crowdaa_sync_articles_wp_to_api_enabled) {
     338      return ($result);
     339    }
     340
     341    /// Fetching all categories and indexing by ID and updated field names
     342    $categories_by_id = [];
     343    $sync_api         = new Crowdaa_Sync_API();
     344    $sync_db          = new Crowdaa_Sync_Syncdb('categories');
     345    $synced           = $sync_db->get_synced_entries();
     346    $all_categories   = $sync_api->get_categories();
     347    if (isset($all_categories->message)) {
     348      return ([
     349        'error' => __('API query error : ', CROWDAA_SYNC_PLUGIN_NAME).$all_categories->message,
     350      ]);
     351    }
     352
     353    if ($all_categories->categories) {
     354      foreach ($all_categories->categories as $category) {
     355        if ($category->parentId) {
     356          $category->rootParentId = $category->parentId;
     357        }
     358        $category->hash = self::hash_category($category);
     359        $categories_by_id[$category->_id] = $category;
     360      }
     361    }
     362
     363    $args = array(
     364      'hide_empty' => false,
     365      'taxonomy'   => 'category',
     366    );
     367    $all_terms = get_terms($args);
     368    $terms_by_id = [];
     369    if(!empty($all_terms)) {
     370      foreach ($all_terms as $term) {
     371        $term->perms = [];
     372
     373        if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     374          global $wpdb;
     375
     376          $perms = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_categories, [
     377            'category_id' => $term->term_id,
     378          ], ['membership_id']);
     379          $perms_array = [];
     380          foreach ($perms as $perm) {
     381            $perms_array[] = $perm->membership_id;
     382          }
     383          $term->perms = $perms_array;
     384        }
     385
     386        $terms_by_id[$term->term_id] = $term;
     387      }
     388    }
     389
     390    /// Fetching filtering modes
     391    $sync_categories_mode = get_option('crowdaa_sync_categories_mode', 'blacklist');
     392    $sync_categories_list = get_option('crowdaa_sync_categories_list', '');
     393    if ($sync_categories_list === '') {
     394      $sync_categories_list = [];
     395    } else {
     396      $sync_categories_list = explode(',', $sync_categories_list);
     397    }
     398
     399    /// Getting list of categories names
     400    $sync_categories_names = [];
     401    foreach ($sync_categories_list as $id) {
     402      if (isset($terms_by_id[$id])) {
     403        $sync_categories_names = $terms_by_id[$id]->name;
     404      }
     405    }
     406
     407    /// Filtering allowed parents from the WP terms
     408    foreach ($terms_by_id as $term) {
     409      $root_term = $term;
     410      while ($root_term->parent) {
     411        $root_term = $terms_by_id[$root_term->parent];
     412      }
     413
     414      if ($sync_categories_mode === 'whitelist' && !in_array($root_term->term_id, $sync_categories_list)) {
     415        $term->rootParentId = null;
     416      } else if ($sync_categories_mode === 'blacklist' && in_array($root_term->term_id, $sync_categories_list)) {
     417        $term->rootParentId = null;
     418      } else if ($root_term->term_id !== $term->term_id) {
     419        $term->rootParentId = $root_term->term_id;
     420      } else {
     421        $term->rootParentId = null;
     422      }
     423      $term->hash = self::hash_term($term);
     424    }
     425
     426    /// Filtering allowed terms
     427    foreach ($terms_by_id as $id => $term) {
     428      if ($sync_categories_mode === 'whitelist' && !in_array($term->term_id, $sync_categories_list)) {
     429        unset($terms_by_id[$id]);
     430      } else if ($sync_categories_mode === 'blacklist' && in_array($term->term_id, $sync_categories_list)) {
     431        unset($terms_by_id[$id]);
     432      }
     433    }
     434
     435    /// Filtering allowed categories
     436    foreach ($categories_by_id as $id => $category) {
     437      if ($sync_categories_mode === 'whitelist' && !in_array($category->name, $sync_categories_names)) {
     438        unset($categories_by_id[$id]);
     439      } else if ($sync_categories_mode === 'blacklist' && in_array($category->name, $sync_categories_names)) {
     440        unset($categories_by_id[$id]);
     441      }
     442    }
     443
     444    /// Specific code to handle migration from previous sync mechanism
     445    if (count($synced) === 0) {
     446      $created = 0;
     447
     448      foreach ($terms_by_id as $term) {
     449        $api_id = get_term_meta($term->term_id, 'api_term_id', true);
     450        if ($api_id && isset($categories_by_id[$api_id])) {
     451          $sync_db->create_entry($term->term_id, $api_id, [
     452            'category_hash' => $categories_by_id[$api_id]->hash,
     453            'term_hash' => $term->hash,
     454          ]);
     455          $created++;
     456        }
     457      }
     458
     459      if ($created > 0) {
     460        $synced = $sync_db->get_synced_entries();
     461      }
     462    }
     463
     464    /// Storing synced
     465    $synced_by_api_id = [];
     466    $synced_by_wp_id = [];
     467    foreach ($synced as $item) {
     468      $item->category_hash = $item->sync_data['category_hash'];
     469      $item->term_hash = $item->sync_data['term_hash'];
     470      if ($sync_categories_mode === 'whitelist' && !in_array($item->wp_id, $sync_categories_list)) {
     471        $sync_db->delete_entry(['id' => $item->id]);
     472      } else if ($sync_categories_mode === 'blacklist' && in_array($item->wp_id, $sync_categories_list)) {
     473        $sync_db->delete_entry(['id' => $item->id]);
     474      } else {
     475        $synced_by_wp_id[$item->wp_id] = $item;
     476        $synced_by_api_id[$item->api_id] = $item;
     477      }
     478    }
     479
     480    Crowdaa_Sync_Logs::log('OpQueue building...', count($all_categories->categories).' api categories and '.count($all_terms).' wp categories');
     481
     482    /// Comparing states and storing oplist
     483    if ($crowdaa_sync_articles_wp_to_api_enabled) {
     484      foreach ([false, true] as $hasParent) {
     485        foreach ($terms_by_id as $id => $term) {
     486          if ((!!$term->rootParentId) === $hasParent) {
     487            if (!array_key_exists($id, $synced_by_wp_id)) {
     488              $result['only_wp'][] = [
     489                'api_id' => null,
     490                'wp_id' => $term->term_id,
     491                'name' => $term->name,
     492                'slug' => $term->slug,
     493                'parentId' => $term->rootParentId,
     494                'perms' => $term->perms,
     495                'hash' => $term->hash,
     496              ];
     497            } else if ($synced_by_wp_id[$id]->term_hash !== $term->hash) {
     498              $result['wp_to_api'][] = [
     499                'api_id' => $synced_by_wp_id[$id]->api_id,
     500                'wp_id' => $term->term_id,
     501                'name' => $term->name,
     502                'slug' => $term->slug,
     503                'parentId' => $term->rootParentId,
     504                'perms' => $term->perms,
     505                'hash' => $term->hash,
     506              ];
     507            }
     508          }
     509        }
     510      }
     511
     512      foreach ($synced_by_wp_id as $wp_id => $synced_item) {
     513        if (!array_key_exists($wp_id, $terms_by_id)) {
     514          $result['remove_api'][] = [
     515            'api_id' => $synced_item->api_id,
     516            'wp_id' => null,
     517          ];
     518        }
     519      }
     520    }
     521
     522    if ($crowdaa_sync_articles_api_to_wp_enabled) {
     523      foreach ([false, true] as $hasParent) {
     524        foreach ($categories_by_id as $id => $category) {
     525          if ((!!$category->parentId) === $hasParent) {
     526            if (!array_key_exists($id, $synced_by_api_id)) {
     527              $result['only_api'][] = [
     528                'api_id' => $category->_id,
     529                'wp_id' => null,
     530                'name' => $category->name,
     531                'slug' => $category->pathName,
     532                'parentId' => $category->parentId,
     533                'badges' => $category->badges,
     534                'hash' => $category->hash,
     535              ];
     536            } else if ($synced_by_api_id[$id]->category_hash !== $category->hash) {
     537              $result['api_to_wp'][] = [
     538                'api_id' => $category->_id,
     539                'wp_id' => $synced_by_api_id[$id]->wp_id,
     540                'name' => $category->name,
     541                'slug' => $category->pathName,
     542                'parentId' => $category->parentId,
     543                'badges' => $category->badges,
     544                'hash' => $category->hash,
     545              ];
     546            }
     547          }
     548        }
     549      }
     550
     551      foreach ($synced_by_api_id as $api_id => $synced_item) {
     552        if (!array_key_exists($api_id, $categories_by_id)) {
     553          $result['remove_wp'][] = [
     554            'wp_id' => $synced_item->wp_id,
     555            'api_id' => null,
     556          ];
     557        }
     558      }
     559    }
     560
     561    return ($result);
    107562  }
    108563
     
    214669    }
    215670
    216     // Compare posts API and WP
    217671    $result = [
    218672      'api_to_wp' => [],
     
    334788
    335789      $info_wp = new Crowdaa_Sync_Add_Info_WP();
     790      $badges_opqueue = $this->get_badges_opqueue();
     791      $categories_opqueue = $this->get_categories_opqueue();
    336792      $articles_opqueue = $this->get_articles_opqueue();
     793
     794      if (isset($badges_opqueue['error']) && $badges_opqueue['error']) {
     795        $result['error'] = $badges_opqueue['error'];
     796        Crowdaa_Sync_Logs::log('Queue', 'error', $badges_opqueue['error']);
     797        return ($result);
     798      }
     799
     800      if (isset($categories_opqueue['error']) && $categories_opqueue['error']) {
     801        $result['error'] = $categories_opqueue['error'];
     802        Crowdaa_Sync_Logs::log('Queue', 'error', $categories_opqueue['error']);
     803        return ($result);
     804      }
    337805
    338806      if (isset($articles_opqueue['error']) && $articles_opqueue['error']) {
     
    343811
    344812      $result['opqueue'] = [
    345         'articles' => $articles_opqueue,
     813        'articles'   => $articles_opqueue,
     814        'badges'     => $badges_opqueue,
     815        'categories' => $categories_opqueue,
    346816      ];
    347817
     818      self::log_opqueue($badges_opqueue, 'badges', 'api_to_wp');
     819      self::log_opqueue($badges_opqueue, 'badges', 'wp_to_api');
     820      self::log_opqueue($badges_opqueue, 'badges', 'only_api');
     821      self::log_opqueue($badges_opqueue, 'badges', 'only_wp');
     822      self::log_opqueue($badges_opqueue, 'badges', 'remove_api');
     823      self::log_opqueue($badges_opqueue, 'badges', 'remove_wp');
     824      self::log_opqueue($categories_opqueue, 'categories', 'api_to_wp');
     825      self::log_opqueue($categories_opqueue, 'categories', 'wp_to_api');
     826      self::log_opqueue($categories_opqueue, 'categories', 'only_api');
     827      self::log_opqueue($categories_opqueue, 'categories', 'only_wp');
     828      self::log_opqueue($categories_opqueue, 'categories', 'remove_api');
     829      self::log_opqueue($categories_opqueue, 'categories', 'remove_wp');
    348830      self::log_opqueue($articles_opqueue, 'articles', 'api_to_wp');
    349831      self::log_opqueue($articles_opqueue, 'articles', 'wp_to_api');
     
    356838
    357839      do_action('crowdaa_sync_articles_synchronization_start');
     840      // Sync WP => API
     841      if (
     842        count($badges_opqueue['wp_to_api']) > 0 ||
     843        count($badges_opqueue['only_wp']) > 0 ||
     844        count($badges_opqueue['remove_api']) > 0
     845      ) {
     846        /** @TODO Continue me, write this function */
     847        $api_errors = $this->sync_badges_api(
     848          $badges_opqueue['wp_to_api'],
     849          $badges_opqueue['only_wp'],
     850          $badges_opqueue['remove_api']
     851        );
     852      }
     853
     854      // Sync API => WP
     855      if (
     856        count($badges_opqueue['api_to_wp']) > 0 ||
     857        count($badges_opqueue['only_api']) > 0 ||
     858        count($badges_opqueue['remove_wp']) > 0
     859      ) {
     860        /** @TODO Continue me, write this function */
     861        $wp_errors = $info_wp->sync_badges_wp(
     862          $badges_opqueue['api_to_wp'],
     863          $badges_opqueue['only_api'],
     864          $badges_opqueue['remove_wp']
     865        );
     866      }
     867
     868      // Sync WP => API
     869      if (
     870        count($categories_opqueue['wp_to_api']) > 0 ||
     871        count($categories_opqueue['only_wp']) > 0 ||
     872        count($categories_opqueue['remove_api']) > 0
     873      ) {
     874        /** @TODO Continue me, write this function */
     875        $api_errors = $this->sync_categories_api(
     876          $categories_opqueue['wp_to_api'],
     877          $categories_opqueue['only_wp'],
     878          $categories_opqueue['remove_api']
     879        );
     880      }
     881
     882      // Sync API => WP
     883      if (
     884        count($categories_opqueue['api_to_wp']) > 0 ||
     885        count($categories_opqueue['only_api']) > 0 ||
     886        count($categories_opqueue['remove_wp']) > 0
     887      ) {
     888        /** @TODO Continue me, write this function */
     889        $wp_errors = $info_wp->sync_categories_wp(
     890          $categories_opqueue['api_to_wp'],
     891          $categories_opqueue['only_api'],
     892          $categories_opqueue['remove_wp']
     893        );
     894      }
     895
    358896      // Sync WP => API
    359897      if (is_array($articles_opqueue['wp_to_api']) && is_array($articles_opqueue['only_wp'])) {
     
    385923    } catch (Crowdaa_Sync_Post_Error $e) {
    386924      $result['error'] = __('Uncaught Post synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
     925    } catch (Crowdaa_Sync_Category_Error $e) {
     926      $result['error'] = __('Category synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
     927    } catch (Crowdaa_Sync_Badge_Error $e) {
     928      $result['error'] = __('Badge synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
    387929    } catch (Crowdaa_Sync_Error $e) {
    388930      $result['error'] = __('Fatal synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
     
    4671009  }
    4681010
     1011  public function sync_badges_api(
     1012    &$wp_to_api,
     1013    &$only_wp,
     1014    &$remove_api
     1015  ) {
     1016    $elements_to_process = array_merge($wp_to_api, $only_wp, $remove_api);
     1017    if (!$elements_to_process) {
     1018      return (false);
     1019    }
     1020    $sync_api = new Crowdaa_Sync_API();
     1021    $sync_db  = new Crowdaa_Sync_Syncdb('user_badges');
     1022    $errors   = [];
     1023
     1024    foreach ($elements_to_process as $curPermId => $curPerm) {
     1025      Crowdaa_Sync_Timer::check();
     1026      Crowdaa_Sync_Logs::log('Syncing WP>API Badge', $curPermId, wp_json_encode($curPerm));
     1027
     1028      try {
     1029        if (in_array($curPerm, $only_wp, true)) {
     1030          $badge = $sync_api->create_badge($curPerm['name'], $curPerm['description'], $curPerm['public']);
     1031          $sync_db->create_entry($curPerm['wp_id'], $badge->_id, [
     1032            'badge_hash' => self::hash_badge($badge),
     1033            'membership_hash' => $curPerm['hash'],
     1034          ]);
     1035        } else if (in_array($curPerm, $wp_to_api, true)) {
     1036          $badge = $sync_api->update_badge($curPerm['api_id'], $curPerm['name'], $curPerm['description'], $curPerm['public']);
     1037          $sync_db->update_entry(['api_id' => $curPerm['api_id']], [
     1038            'sync_data' => [
     1039              'badge_hash' => self::hash_badge($badge),
     1040              'membership_hash' => $curPerm['hash'],
     1041            ],
     1042          ]);
     1043        } else if (in_array($curPerm, $remove_api, true)) {
     1044          $sync_api->remove_badge($curPerm['api_id']);
     1045          $sync_db->delete_entry(['api_id' => $curPerm['api_id']]);
     1046        }
     1047      } catch (Crowdaa_Sync_Post_Skip_Error $e) {
     1048        Crowdaa_Sync_Logs::log($e->getMessage());
     1049        continue;
     1050      } catch (Crowdaa_Sync_Post_Error $e) {
     1051        Crowdaa_Sync_Logs::log('Badge sync error', $e->getMessage());
     1052        $errors[] = $e->getMessage();
     1053        continue;
     1054      }
     1055    }
     1056
     1057    if (count($elements_to_process) > 0) {
     1058      foreach ($errors as $error) {
     1059        Crowdaa_Sync_Logs::log('Created/updated/removed API badges errors', $error);
     1060      }
     1061
     1062      Crowdaa_Sync_Logs::log(
     1063        'Created/updated API badges',
     1064        count($only_wp).' badges created, '.
     1065        count($wp_to_api).' badges updated and '.
     1066        count($remove_api).' badges removed with '.count($errors).' errors'
     1067      );
     1068    }
     1069
     1070    return ($errors);
     1071  }
     1072
     1073  private static function term_perms_to_badges($perms) {
     1074    $perm_sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     1075    $badges = [];
     1076
     1077    foreach ($perms as $perm_id) {
     1078      $entry = $perm_sync_db->get_entry_with_wp_id($perm_id, 'api_id');
     1079      $badges[] = $entry->api_id;
     1080    }
     1081
     1082    return ($badges);
     1083  }
     1084
     1085  public function sync_categories_api(
     1086    &$wp_to_api,
     1087    &$only_wp,
     1088    &$remove_api
     1089  ) {
     1090    $elements_to_process = array_merge($wp_to_api, $only_wp, $remove_api);
     1091    if (!$elements_to_process) {
     1092      return (false);
     1093    }
     1094    $sync_api     = new Crowdaa_Sync_API();
     1095    $sync_db      = new Crowdaa_Sync_Syncdb('categories');
     1096    $errors       = [];
     1097
     1098    foreach ($elements_to_process as $curTermId => $curTerm) {
     1099      Crowdaa_Sync_Timer::check();
     1100      Crowdaa_Sync_Logs::log('Syncing WP>API Category', $curTermId, wp_json_encode($curTerm));
     1101
     1102      try {
     1103        if (in_array($curTerm, $only_wp, true)) {
     1104          $parentId = null;
     1105          if ($curTerm['parentId']) {
     1106            $parentId = $sync_db->get_entry_with_wp_id($curTerm['parentId'], 'api_id');
     1107            $parentId = $parentId->api_id;
     1108          }
     1109
     1110          $badges = null;
     1111
     1112          if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     1113            $badges = self::term_perms_to_badges($curTerm['perms']);
     1114          }
     1115
     1116          $category = $sync_api->create_category($curTerm['name'], $curTerm['slug'], $parentId, $badges);
     1117          $sync_db->create_entry($curTerm['wp_id'], $category->_id, [
     1118            'category_hash' => self::hash_category($category),
     1119            'term_hash' => $curTerm['hash'],
     1120          ]);
     1121        } else if (in_array($curTerm, $wp_to_api, true)) {
     1122          $parentId = null;
     1123          if ($curTerm['parentId']) {
     1124            $parentId = $sync_db->get_entry_with_wp_id($curTerm['parentId'], 'api_id');
     1125            $parentId = $parentId->api_id;
     1126          }
     1127
     1128          $badges = null;
     1129
     1130          if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     1131            $badges = self::term_perms_to_badges($curTerm['perms']);
     1132          }
     1133
     1134          $category = $sync_api->update_category($curTerm['api_id'], $curTerm['name'], $curTerm['slug'], $parentId, $badges);
     1135          $sync_db->update_entry(['api_id' => $curTerm['api_id']], [
     1136            'sync_data' => [
     1137              'category_hash' => self::hash_category($category),
     1138              'term_hash' => $curTerm['hash'],
     1139            ],
     1140          ]);
     1141        } else if (in_array($curTerm, $remove_api, true)) {
     1142          $sync_api->delete_category($curTerm['api_id']);
     1143          $sync_db->delete_entry(['api_id' => $curTerm['api_id']]);
     1144        }
     1145      } catch (Crowdaa_Sync_Post_Skip_Error $e) {
     1146        Crowdaa_Sync_Logs::log($e->getMessage());
     1147        continue;
     1148      } catch (Crowdaa_Sync_Post_Error $e) {
     1149        Crowdaa_Sync_Logs::log('Badge sync error', $e->getMessage());
     1150        $errors[] = $e->getMessage();
     1151        continue;
     1152      }
     1153    }
     1154
     1155    if (count($elements_to_process) > 0) {
     1156      foreach ($errors as $error) {
     1157        Crowdaa_Sync_Logs::log('Created/updated/removed API categories errors', $error);
     1158      }
     1159
     1160      Crowdaa_Sync_Logs::log(
     1161        'Created/updated API categories',
     1162        count($only_wp).' categories created, '.
     1163        count($wp_to_api).' categories updated and '.
     1164        count($remove_api).' categories removed with '.count($errors).' errors'
     1165      );
     1166    }
     1167
     1168    return ($errors);
     1169  }
     1170
    4691171  public function sync_info_api(&$wp_to_api, &$only_wp) {
    4701172    $posts_add_to_api = array_merge($wp_to_api, $only_wp);
     
    4731175    }
    4741176
    475     $cat_array        = [];
    476     $errors           = [];
    477     $sync_api         = new Crowdaa_Sync_API();
    478     $all_categories   = $sync_api->get_categories();
    479     if (isset($all_categories->message)) {
    480       throw new Crowdaa_Sync_Error(__('Categories fetch error : ', CROWDAA_SYNC_PLUGIN_NAME).$all_categories->message);
    481     }
    482     if ($all_categories->categories) {
    483       foreach ($all_categories->categories as $category) {
    484         $cat_array[$category->_id] = strtolower(trim($category->pathName));
    485       }
    486     }
    487 
    488     $args = array(
    489       'hide_empty' => false,
    490       'taxonomy'   => 'category',
    491     );
    492     $all_terms = get_terms($args);
    493     $terms_hash = [];
    494     if(!empty($all_terms)) {
    495       foreach ($all_terms as $term) {
    496         $terms_hash[$term->term_id] = $term;
    497       }
     1177    $errors             = [];
     1178    $sync_api           = new Crowdaa_Sync_API();
     1179    $cat_sync_db        = new Crowdaa_Sync_Syncdb('categories');
     1180    $cat_synced_entries = $cat_sync_db->get_synced_entries();
     1181
     1182    $cat_wp_to_api_id = [];
     1183    foreach ($cat_synced_entries as $item) {
     1184      $cat_wp_to_api_id[$item->wp_id] = $item->api_id;
    4981185    }
    4991186
     
    5221209    }
    5231210
    524     foreach ($terms_hash as $term) {
    525       $root_term = $term;
    526       while ($root_term->parent) {
    527         $root_term = $terms_hash[$root_term->parent];
    528       }
    529 
    530       if ($sync_categories_mode === 'whitelist' && !in_array($root_term->term_id, $sync_categories_list)) {
    531         $term->root_term_id = null;
    532         continue;
    533       } else if ($sync_categories_mode === 'blacklist' && in_array($root_term->term_id, $sync_categories_list)) {
    534         $term->root_term_id = null;
    535         continue;
    536       }
    537 
    538       if ($root_term->term_id !== $term->term_id) {
    539         $term->root_term_id = $root_term->term_id;
    540       } else {
    541         $term->root_term_id = $term->parent;
    542       }
    543     }
    544 
    5451211    foreach ($posts_add_to_api as $postArrayId => $post) {
    5461212      Crowdaa_Sync_Timer::check();
     
    5591225      $blacklisted = false;
    5601226      foreach ($post_terms as $term) {
    561         $blacklisted_term = false;
    562 
    5631227        if (in_array($term->term_id, $sync_categories_list)) {
    5641228          if ($sync_categories_mode === 'blacklist') {
     
    5671231            $whitelisted = $term->term_id;
    5681232            if (!$post_term) {
    569               $child_term = true; // Lie here to avoid losing this term.
    5701233              $post_term  = [
    571                 'id'   => $term->term_id,
    572                 'slug' => $term->slug,
    573                 'name' => $term->name,
     1234                'id'    => $term->term_id,
     1235                'child' => in_array($term->term_id, $child_terms),
     1236              ];
     1237            } else if (!$post_term['child'] && in_array($term->term_id, $child_terms)) {
     1238              $post_term  = [
     1239                'id'    => $term->term_id,
     1240                'child' => true,
    5741241              ];
    5751242            }
     
    5771244        } else if (
    5781245          $sync_categories_mode !== 'whitelist' &&
    579           !$blacklisted &&
    580           !$post_term &&
    581           in_array($term->term_id, $child_terms)
     1246          !$blacklisted
    5821247        ) {
    583           $child_term = true;
    584           $post_term  = [
    585             'id'   => $term->term_id,
    586             'slug' => $term->slug,
    587             'name' => $term->name,
    588           ];
     1248          if (!$post_term) {
     1249            $post_term  = [
     1250              'id'    => $term->term_id,
     1251              'child' => in_array($term->term_id, $child_terms),
     1252            ];
     1253          } else if (!$post_term['child'] && in_array($term->term_id, $child_terms)) {
     1254            $post_term  = [
     1255              'id'    => $term->term_id,
     1256              'child' => true,
     1257            ];
     1258          }
    5891259        }
    5901260      }
     
    6081278
    6091279        continue;
    610       }
    611 
    612       if ($child_term == false) {
    613         $post_term  = [
    614           'id'   => $post_terms[0]->term_id,
    615           'slug' => $post_terms[0]->slug,
    616           'name' => $post_terms[0]->name,
    617         ];
    618       }
    619 
    620       $term = $terms_hash[$post_term['id']];
    621       if ($term->root_term_id) {
    622         $term = $terms_hash[$term->root_term_id];
    623         $post_term['parent'] = [
    624           'id'   => $term->term_id,
    625           'slug' => $term->slug,
    626           'name' => $term->name,
    627         ];
    6281280      }
    6291281
     
    6411293        }
    6421294
    643         // Create or update parent category, if needed
    644         $parent_api_term_id = false;
    645         if (array_key_exists('parent', $post_term)) {
    646           $api_term_id = get_term_meta($post_term['parent']['id'], 'api_term_id', true);
    647           $api_term_need_update = get_term_meta($post_term['parent']['id'], 'crowdaa_need_sync', true);
    648           $sync_version = get_term_meta($post_term['parent']['id'], 'crowdaa_version', true);
    649           if (!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    650             $api_term_id = array_search(strtolower(trim($post_term['parent']['slug'])), $cat_array);
    651             if ($api_term_id !== false) {
    652               update_term_meta($post_term['parent']['id'], 'api_term_id', $api_term_id);
    653             }
    654           }
    655           $plain_term_name = html_entity_decode($post_term['parent']['name'], ENT_QUOTES);
    656 
    657           if(!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    658             $api_term_id = $sync_api->create_category_api($post_term['parent']['id'], $plain_term_name, $post_term['parent']['slug'], '');
    659             $cat_array[$api_term_id] = $post_term['parent']['slug'];
    660           } elseif($api_term_need_update !== 'no' || $sync_version !== Crowdaa_Sync_Versions::get_version()) {
    661             $sync_api->update_category_api($api_term_id, $post_term['parent']['id'], $plain_term_name, $post_term['parent']['slug'], '');
    662           }
    663 
    664           $parent_api_term_id = $api_term_id;
    665         }
    666 
    667         $api_term_id = get_term_meta($post_term['id'], 'api_term_id', true);
    668         $api_term_need_update = get_term_meta($post_term['id'], 'crowdaa_need_sync', true);
    669         $sync_version = get_term_meta($post_term['id'], 'crowdaa_version', true);
    670         if (!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    671           $api_term_id = array_search(strtolower(trim($post_term['slug'])), $cat_array);
    672           if ($api_term_id !== false) {
    673             update_term_meta($post_term['id'], 'api_term_id', $api_term_id);
    674           }
    675         }
    676         $plain_term_name = html_entity_decode($post_term['name'], ENT_QUOTES);
    677 
    678         if(!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    679           $api_term_id = $sync_api->create_category_api($post_term['id'], $plain_term_name, $post_term['slug'], $parent_api_term_id ?: '');
    680           $cat_array[$api_term_id] = $post_term['slug'];
    681         } elseif($api_term_need_update !== 'no' || $sync_version !== Crowdaa_Sync_Versions::get_version()) {
    682           $sync_api->update_category_api($api_term_id, $post_term['id'], $plain_term_name, $post_term['slug'], $parent_api_term_id ?: '');
     1295        // Get category API ID
     1296        $api_term_id = $cat_wp_to_api_id[$post_term['id']];
     1297        if (!$api_term_id) {
     1298          throw new Crowdaa_Sync_Post_Error('Could not find synced category for term '.$post_term['id'].'. This should not happen, aborting sync.');
     1299
     1300          continue;
    6831301        }
    6841302
  • crowdaa-sync/tags/1.2.0/admin/class-crowdaa-sync-add-info-wp.php

    r2620193 r2744975  
    2020  }
    2121
    22   /**
    23    * Create term
    24    *
    25    * @since    1.0.0
    26    * @param $cat_id
    27    * @param $cat_name
    28    * @return int
    29    */
    30   /** @TODO That whole function was rewritten to handle more edge-cases and was not tested, test it! */
    31   public function get_or_create_term($cat_id, $cat_name) {
    32     $cat_name = esc_html($cat_name);
    33     $post_type_taxonomy = 'category';
    34 
    35     $terms = get_terms([
    36       'hide_empty' => false,
    37       'taxonomy' => $post_type_taxonomy,
    38       'meta_query' => [
    39         [
    40            'key'       => 'api_term_id',
    41            'value'     => $cat_id,
    42            'compare'   => '=',
    43         ],
    44       ],
     22  private function create_permission($name, $description, $public) {
     23    global $wpdb;
     24
     25    $fields = [
     26      'name' => $name,
     27      'description' => $description,
     28      'allow_signups' => $public ? 1 : 0,
     29      'initial_payment' => 0.0,
     30      'billing_amount' => 0.0,
     31    ];
     32
     33    $insCount = $wpdb->insert(
     34      $wpdb->pmpro_membership_levels,
     35      $fields,
     36      Crowdaa_Sync_Utils::wpdb_formats_for($fields)
     37    );
     38
     39    if (!$insCount) {
     40      throw new Crowdaa_Sync_Badge_Error('Could not insert permission named "'.$name.'" in SQL database');
     41    }
     42
     43    $fields['id'] = $wpdb->insert_id;
     44
     45    return ((object) $fields);
     46  }
     47
     48  private function update_permission($wp_id, $name, $description, $public) {
     49    global $wpdb;
     50
     51    $fields = [
     52      'name' => $name,
     53      'description' => $description,
     54      'allow_signups' => $public ? 1 : 0,
     55    ];
     56    $where = ['id' => $wp_id];
     57
     58    $updCount = $wpdb->update(
     59      $wpdb->pmpro_membership_levels,
     60      $fields,
     61      $where,
     62      Crowdaa_Sync_Utils::wpdb_formats_for($fields),
     63      Crowdaa_Sync_Utils::wpdb_formats_for($where)
     64    );
     65
     66    if (!$updCount) {
     67      throw new Crowdaa_Sync_Badge_Error('Could not update permission named "'.$name.'" in SQL database');
     68    }
     69
     70    $fields['id'] = $wp_id;
     71
     72    return ((object) $fields);
     73  }
     74
     75  private function remove_permission($wp_id) {
     76    global $wpdb;
     77
     78    $where = ['id' => $wp_id];
     79    $where2 = ['membership_id' => $wp_id];
     80    $formats2 = Crowdaa_Sync_Utils::wpdb_formats_for($where2);
     81
     82    $wpdb->delete(
     83      $wpdb->pmpro_membership_levels,
     84      $where,
     85      Crowdaa_Sync_Utils::wpdb_formats_for($where)
     86    );
     87
     88    $wpdb->delete($wpdb->pmpro_membership_orders,      $where2, $formats2);
     89    $wpdb->delete($wpdb->pmpro_memberships_categories, $where2, $formats2);
     90    $wpdb->delete($wpdb->pmpro_memberships_pages,      $where2, $formats2);
     91    $wpdb->delete($wpdb->pmpro_memberships_users,      $where2, $formats2);
     92
     93    $where3 = ['pmpro_membership_level_id' => $wp_id];
     94    $formats3 = Crowdaa_Sync_Utils::wpdb_formats_for($where3);
     95    $wpdb->delete($wpdb->pmpro_membership_levelmeta,   $where3, $formats3);
     96  }
     97
     98  private function create_term($name, $slug, $parentId, $badges) {
     99    $term_data = wp_insert_term(esc_html($name), 'category', [
     100      'parent' => $parentId ?: 0,
     101      'slug'   => $slug ?: '',
    45102    ]);
    46 
    47     if (is_wp_error($terms) || !is_array($terms) || count($terms) === 0) {
    48       $terms = get_terms([
    49         'hide_empty' => false,
    50         'taxonomy' => $post_type_taxonomy,
    51         'name' => $cat_name,
    52       ]);
    53     }
    54 
    55     if (!is_wp_error($terms) && is_array($terms) && count($terms) > 0) {
    56       $term_by_name = null;
    57 
    58       foreach ($terms as $term) {
    59         $key = get_term_meta($term->term_id, 'api_term_id', false);
    60         if ($key === $cat_id) {
    61           if ($term->name !== $cat_name) {
    62             wp_update_term($term->term_id, $post_type_taxonomy, [
    63               'name' => $cat_name,
    64               'parent' => $term->parent,
    65               'slug' => $term->slug,
    66               'description' => $term->description,
    67             ]);
    68             update_term_meta($term->term_id, 'crowdaa_need_sync', 'no');
    69             update_term_meta($term->term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
     103    $term = get_term($term_data['term_id'], 'category');
     104
     105    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro') && $badges) {
     106      global $wpdb;
     107
     108      if (isset($badges->list) && count($badges->list) > 0) {
     109        $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     110
     111        foreach ($badges->list as $item) {
     112          $sync_obj = $sync_db->get_entry_with_api_id($item->id, 'wp_id');
     113
     114          Crowdaa_Sync_Utils::quick_insert(
     115            $wpdb->pmpro_memberships_categories,
     116            [
     117              'membership_id' => $sync_obj->wp_id,
     118              'category_id' => $term->term_id,
     119            ]
     120          );
     121        }
     122      }
     123    }
     124
     125    return ($term);
     126  }
     127
     128  private function update_term($term_id, $name, $slug, $parentId, $badges) {
     129    wp_update_term($term_id, 'category', [
     130      'name'   => esc_html($name),
     131      'parent' => $parentId ?: 0,
     132      'slug'   => $slug ?: '',
     133    ]);
     134
     135    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro') && $badges) {
     136      global $wpdb;
     137
     138      if (isset($badges->list) && is_array($badges->list)) {
     139        $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     140        $current_memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_categories, [
     141          'category_id' => $term_id,
     142        ], ['membership_id']);
     143        $membership_hash = [];
     144        foreach ($current_memberships as $membership) {
     145          $membership_hash[$membership->membership_id] = true;
     146        }
     147
     148        foreach ($badges->list as $item) {
     149          $sync_obj = $sync_db->get_entry_with_api_id($item->id, 'wp_id');
     150
     151          if (!isset($membership_hash[$sync_obj->wp_id])) {
     152            Crowdaa_Sync_Utils::quick_insert(
     153              $wpdb->pmpro_memberships_categories,
     154              [
     155                'membership_id' => $sync_obj->wp_id,
     156                'category_id' => $term_id,
     157              ]
     158            );
     159          } else {
     160            unset($membership_hash[$sync_obj->wp_id]);
    70161          }
    71           return $term->term_id;
    72         } else if (!$term_by_name && $key === false && $term->name === $cat_name) {
    73           $term_by_name = $term;
    74         }
    75       }
    76 
    77       if ($term_by_name) {
    78         update_term_meta($term_by_name->term_id, 'crowdaa_need_sync', 'no');
    79         update_term_meta($term_by_name->term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    80         return ($term_by_name->term_id);
    81       }
    82     }
    83 
    84     $term_id         = '';
    85     $data = [
    86       'description' => '',
    87       'parent'      => 0,
    88       'slug'        => '',
    89     ];
    90 
    91     $term = wp_insert_term($cat_name, $post_type_taxonomy, $data);
    92     if(!is_wp_error($term)) {
    93       $term_id = $term['term_id'];
    94       update_term_meta($term_id, 'api_term_id', $cat_id);
    95       update_term_meta($term_id, 'crowdaa_need_sync', 'no');
    96       update_term_meta($term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    97     }
    98     return $term_id;
     162        }
     163
     164        foreach ($membership_hash as $membership_id => $true) {
     165          Crowdaa_Sync_Utils::quick_delete($wpdb->pmpro_memberships_categories, [
     166            'category_id' => $term_id,
     167            'membership_id' => $membership_id,
     168          ]);
     169        }
     170      }
     171    }
     172
     173    $term = get_term($term_id, 'category');
     174
     175    return ($term);
     176  }
     177
     178  private function delete_term($term_id) {
     179    wp_delete_term($term_id, 'category');
     180  }
     181
     182  public function sync_badges_wp(
     183    &$api_to_wp,
     184    &$only_api,
     185    &$remove_wp
     186  ) {
     187    $errors            = [];
     188    $sync_db           = new Crowdaa_Sync_Syncdb('user_badges');
     189    $badges_sync_to_wp = array_merge($api_to_wp, $only_api, $remove_wp);
     190
     191    foreach($badges_sync_to_wp as $curBadgeId => $curBadge) {
     192      Crowdaa_Sync_Timer::check();
     193      Crowdaa_Sync_Logs::log('Syncing API>WP Badge', $curBadgeId, wp_json_encode($curBadge));
     194
     195      if (in_array($curBadge, $only_api, true)) {
     196        $permission = $this->create_permission($curBadge['name'], $curBadge['description'], $curBadge['public']);
     197        $sync_db->create_entry($permission->id, $curBadge['api_id'], [
     198          'badge_hash' => $curBadge['hash'],
     199          'membership_hash' => Crowdaa_Sync_Add_Info_API::hash_pmpro_membership($permission),
     200        ]);
     201      } else if (in_array($curBadge, $api_to_wp, true)) {
     202        $permission = $this->update_permission($curBadge['wp_id'], $curBadge['name'], $curBadge['description'], $curBadge['public']);
     203        $sync_db->update_entry(['wp_id' => $curBadge['wp_id']], [
     204          'sync_data' => [
     205            'badge_hash' => $curBadge['hash'],
     206            'membership_hash' => Crowdaa_Sync_Add_Info_API::hash_pmpro_membership($permission),
     207          ],
     208        ]);
     209      } else if (in_array($curBadge, $remove_wp, true)) {
     210        $this->remove_permission($curBadge['wp_id']);
     211        $sync_db->delete_entry(['wp_id' => $curBadge['wp_id']]);
     212      }
     213    }
     214
     215    if (count($badges_sync_to_wp) > 0) {
     216      Crowdaa_Sync_Logs::log(
     217        'Created/updated WP permissions',
     218        count($only_api).' permissions created, '.
     219        count($api_to_wp).' permissions updated and '.
     220        count($remove_wp).' permissions removed with '.
     221        count($errors).' errors'
     222      );
     223    }
     224
     225    return ($errors);
     226  }
     227
     228  public function sync_categories_wp(
     229    &$api_to_wp,
     230    &$only_api,
     231    &$remove_wp
     232  ) {
     233    $errors                = [];
     234    $sync_db               = new Crowdaa_Sync_Syncdb('categories');
     235    $categories_sync_to_wp = array_merge($api_to_wp, $only_api, $remove_wp);
     236
     237    foreach($categories_sync_to_wp as $curCategoryId => $curCategory) {
     238      Crowdaa_Sync_Timer::check();
     239      Crowdaa_Sync_Logs::log('Syncing API>WP Category', $curCategoryId, wp_json_encode($curCategory));
     240
     241      if (in_array($curCategory, $only_api, true)) {
     242        $parentId = null;
     243        if ($curCategory['parentId']) {
     244          $parentId = $sync_db->get_entry_with_api_id($curCategory['parentId'], 'wp_id');
     245          $parentId = $parentId->wp_id;
     246        }
     247
     248        $term = $this->create_term($curCategory['name'], $curCategory['slug'], $parentId, $curCategory['badges']);
     249        $term->rootParentId = $parentId;
     250        $sync_db->create_entry($term->term_id, $curCategory['api_id'], [
     251          'category_hash' => $curCategory['hash'],
     252          'term_hash' => Crowdaa_Sync_Add_Info_API::hash_term($term),
     253        ]);
     254      } else if (in_array($curCategory, $api_to_wp, true)) {
     255        $parentId = null;
     256        if ($curCategory['parentId']) {
     257          $parentId = $sync_db->get_entry_with_api_id($curCategory['parentId'], 'wp_id');
     258          $parentId = $parentId->wp_id;
     259        }
     260
     261        $term = $this->update_term($curCategory['wp_id'], $curCategory['name'], $curCategory['slug'], $parentId, $curCategory['badges']);
     262        $term->rootParentId = $parentId;
     263        $sync_db->update_entry(['wp_id' => $curCategory['wp_id']], [
     264          'sync_data' => [
     265            'category_hash' => $curCategory['hash'],
     266            'term_hash' => Crowdaa_Sync_Add_Info_API::hash_term($term),
     267          ],
     268        ]);
     269      } else if (in_array($curCategory, $remove_wp, true)) {
     270        $this->delete_term($curCategory['wp_id']);
     271        $sync_db->delete_entry(['wp_id' => $curCategory['wp_id']]);
     272      }
     273    }
     274
     275    if (count($categories_sync_to_wp) > 0) {
     276      Crowdaa_Sync_Logs::log(
     277        'Created/updated WP categories',
     278        count($only_api).' categories created, '.
     279        count($api_to_wp).' categories updated and '.
     280        count($remove_wp).' categories removed with '.
     281        count($errors).' errors'
     282      );
     283    }
     284
     285    return ($errors);
    99286  }
    100287
     
    151338  private function create_wp_post_from_api($api_data) {
    152339    $created_posts  = [];
    153 
    154     $categories = $this->get_or_create_term($api_data->category->_id, $api_data->category->name);
     340    $cat_sync_db    = new Crowdaa_Sync_Syncdb('categories');
     341
     342    $term = $cat_sync_db->get_entry_with_api_id($api_data->category->_id, 'wp_id');
     343    $term = get_term($term->wp_id, 'category');
    155344
    156345    $post_data = [
     
    167356    $post_type_taxonomy = 'category';
    168357
    169     wp_set_post_terms($wp_post_id, [$categories], $post_type_taxonomy);
     358    wp_set_post_terms($wp_post_id, [$term], $post_type_taxonomy);
    170359
    171360    $sync_errors = $this->post_sync_api_medias($api_data, $wp_post_id);
     
    185374    $created_posts  = [];
    186375
    187     $categories = $this->get_or_create_term($api_data->category->_id, $api_data->category->name);
     376    $term = $cat_sync_db->get_entry_with_api_id($api_data->category->_id, 'wp_id');
     377    $term = get_term($term->wp_id, 'category');
    188378
    189379    $data = [
     
    195385    $post_type_taxonomy = 'category';
    196386
    197     wp_set_post_terms($wp_post_id, [$categories], $post_type_taxonomy);
     387    wp_set_post_terms($wp_post_id, [$term], $post_type_taxonomy);
    198388    wp_update_post($data);
    199389    update_post_meta($wp_post_id, 'api_post_id', $api_data->_id);
     
    531721   */
    532722  private function get_uploads($img_url, $img_name) {
     723    $wp_upload_dir = wp_upload_dir();
     724    $file_path     = $wp_upload_dir['basedir'].'/'.'catalogue_images/'.$img_name;
     725
    533726    Crowdaa_Sync_Logs::log('Downloading media to Wordpress',
    534727      'img_url='.$img_url,
    535       'img_name='.$img_name,
     728      'img_path='.$file_path,
    536729    );
    537730
     
    541734        'timeout'         => 45,
    542735        'stream'          => true,
    543         'filename'        => $upload_fname,
     736        'filename'        => $file_path,
    544737        'sslcertificates' => CROWDAA_SYNC_CACERT_PATH,
    545738      ]);
  • crowdaa-sync/tags/1.2.0/admin/class-crowdaa-sync-admin-display.php

    r2722017 r2744975  
    2727   * @since    1.0.0
    2828   */
     29  public function database_reset() {
     30    if(empty($_POST) || !wp_verify_nonce($_POST['crowdaa_reset'], 'crowdaa_reset_data')) {
     31      return;
     32    }
     33
     34    Crowdaa_Sync_Logs::log('Running database reset');
     35
     36    update_option('crowdaa_cron_sync_enabled', 'no');
     37
     38    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     39      $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     40      $sync_db->reset();
     41    }
     42
     43    $sync_db = new Crowdaa_Sync_Syncdb('categories');
     44    $sync_db->reset();
     45
     46    $table = Crowdaa_Sync_Utils::db_prefix().'postmeta';
     47    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_picture_id']);
     48    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_videos_id']);
     49    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_feedpicture_id']);
     50    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_media_map']);
     51    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_post_id']);
     52    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key LIKE 'crowdaa_%'");
     53
     54    $table = Crowdaa_Sync_Utils::db_prefix().'termmeta';
     55    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_term_id']);
     56    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key LIKE 'crowdaa_%'");
     57
     58    Crowdaa_Sync_Versions::bump_version();
     59
     60    Crowdaa_Sync_Logs::log('Database reset done');
     61  }
     62
    2963  public function enable_sync() {
    3064    if(!isset($_POST['crowdaa_cron_sync_enabled']) || !wp_verify_nonce($_POST['crowdaa_cron_sync_enabled'], 'crowdaa_cron_sync_enabled_data')) {
     
    5488    } else {
    5589      update_option('crowdaa_sync_wpapi_register_enabled', 'no');
     90    }
     91
     92    if(isset($_POST['sync_perm_plugin'])) {
     93      update_option('crowdaa_sync_perm_plugin', $_POST['sync_perm_plugin']);
    5694    }
    5795
     
    69107      'WP-API register' => get_option('crowdaa_sync_wpapi_register_enabled') === 'yes',
    70108      'duration' => get_option('crowdaa_sync_max_duration', 60),
     109      'perm_plugin' => get_option('crowdaa_sync_perm_plugin', '-'),
    71110    ];
    72111    $sync_logs = apply_filters('crowdaa_sync_configure_levers_log', $sync_logs);
  • crowdaa-sync/tags/1.2.0/admin/class-crowdaa-sync-api.php

    r2722017 r2744975  
    8888  }
    8989
     90  public function get_badges() {
     91    $url = '/userBadges';
     92    $response = $this->http_request('GET', $url);
     93    $err = is_wp_error($response) ? $response->get_error_message() : null;
     94    if (!$err) {
     95      $body = wp_remote_retrieve_body($response);
     96      $json = json_decode($body);
     97    }
     98
     99    if ($err) {
     100      Crowdaa_Sync_Logs::log('Get badges query error', $err);
     101      return ((object) [
     102        'message' => $err,
     103      ]);
     104    }
     105
     106    if (isset($json->message)) {
     107      Crowdaa_Sync_Logs::log('Get badges error', $json->message);
     108    }
     109
     110    foreach ($json->userBadges as &$v) {
     111      if (!isset($v->management)) {
     112        $v->management = 'private-internal';
     113      }
     114      if (!isset($v->access)) {
     115        $v->access = 'hidden';
     116      }
     117    }
     118
     119    return ($json->userBadges);
     120  }
    90121
    91122  /**
     
    614645        $gallery_ids = array_diff($gallery_ids, $bad_ids);
    615646        if (count($gallery_ids) === 0 && !$thumbnail_id) {
    616           throw new Crowdaa_Sync_Post_Error(__('No picture could be synchronized for post ').$wp_post_id);
     647          throw new Crowdaa_Sync_Post_Error(__('No picture could be synchronized for post ', CROWDAA_SYNC_PLUGIN_NAME).$wp_post_id);
    617648        }
    618649      }
     
    789820  }
    790821
     822  public function create_badge($name, $description, $public) {
     823    $data = [
     824      'name'          => $name,
     825      'description'   => $description,
     826      'management'    => $public ? 'public' : 'private-internal',
     827      'access'        => 'teaser',
     828      'isDefault'     => false,
     829      'validationUrl' => '',
     830    ];
     831    $data = apply_filters('crowdaa_sync_api_create_badge_payload', $data);
     832
     833    $response = $this->http_request('POST', '/userBadges', $data);
     834    $err      = is_wp_error($response) ? $response->get_error_message() : null;
     835    if (!$err) {
     836      $body = wp_remote_retrieve_body($response);
     837      $json = json_decode($body);
     838    }
     839
     840    if ($err) {
     841      Crowdaa_Sync_Logs::log('Create badge query error', $name, $err);
     842      throw new Crowdaa_Sync_Post_Error(__('Query error during badge creation : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     843    } else {
     844      if (isset($json->message)) {
     845        Crowdaa_Sync_Logs::log('Create badge error', $name, $json->message);
     846        throw new Crowdaa_Sync_Post_Error(__('API error during badge creation : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     847      }
     848
     849      Crowdaa_Sync_Logs::log('Created badge', wp_json_encode($json->userBadge));
     850
     851      return ($json->userBadge);
     852    }
     853  }
     854
     855  public function update_badge($badge_id, $name, $description, $public) {
     856    $data = [
     857      'name'          => $name,
     858      'description'   => $description,
     859      'management'    => $public ? 'public' : 'private-internal',
     860      'access'        => 'teaser',
     861      'isDefault'     => false,
     862      'validationUrl' => '',
     863    ];
     864    $data = apply_filters('crowdaa_sync_api_update_badge_payload', $data);
     865
     866    $response = $this->http_request('PUT', "/userBadges/$badge_id", $data);
     867    $err      = is_wp_error($response) ? $response->get_error_message() : null;
     868    if (!$err) {
     869      $body = wp_remote_retrieve_body($response);
     870      $json = json_decode($body);
     871    }
     872
     873    if ($err) {
     874      Crowdaa_Sync_Logs::log('Update badge query error', $name, $err);
     875      throw new Crowdaa_Sync_Post_Error(__('Query error during badge update : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     876    } else {
     877      if (isset($json->message)) {
     878        Crowdaa_Sync_Logs::log('Update badge error', $name, $json->message);
     879        throw new Crowdaa_Sync_Post_Error(__('API error during badge update : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     880      }
     881
     882      Crowdaa_Sync_Logs::log('Updated badge', wp_json_encode($json->userBadge));
     883
     884      return ($json->userBadge);
     885    }
     886  }
     887
     888  public function remove_badge($badge_id) {
     889    $response = $this->http_request('DELETE', "/userBadges/$badge_id");
     890    $err      = is_wp_error($response) ? $response->get_error_message() : null;
     891    if (!$err) {
     892      $body = wp_remote_retrieve_body($response);
     893      $json = json_decode($body);
     894    }
     895
     896    if ($err) {
     897      Crowdaa_Sync_Logs::log('Delete badge query error', $name, $err);
     898      throw new Crowdaa_Sync_Post_Error(__('Query error during badge delete : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     899    } else {
     900      if (isset($json->message)) {
     901        Crowdaa_Sync_Logs::log('Delete badge error', $name, $json->message);
     902        throw new Crowdaa_Sync_Post_Error(__('API error during badge delete : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     903      }
     904
     905      Crowdaa_Sync_Logs::log('Deleted badge', $badge_id);
     906    }
     907
     908    return (true);
     909  }
     910
    791911  /**
    792912   * Create category on the API
     
    798918   * @return boolean
    799919   */
    800   public function create_category_api($term_id, $cat_name, $cat_slug, $parent_category_id = '') {
     920  public function create_category($cat_name, $cat_slug, $parent_category_id, $badges) {
    801921    $data = [
    802922      'name'     => $cat_name,
     
    809929      'action'   => '',
    810930    ];
     931
     932    if (is_array($badges)) {
     933      $data['badges'] = $badges;
     934      $data['badgesAllow'] = 'all';
     935    }
     936
    811937    $data = apply_filters('crowdaa_sync_api_create_category_payload', $data);
    812938
     
    820946    if ($err) {
    821947      Crowdaa_Sync_Logs::log('Create category query error', $cat_name, $err);
    822       throw new Crowdaa_Sync_Post_Error(__('Query error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     948      throw new Crowdaa_Sync_Category_Error(__('Query error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
    823949    } else {
    824950      if (isset($json->message)) {
    825951        Crowdaa_Sync_Logs::log('Create category error', $cat_name, $json->message);
    826         throw new Crowdaa_Sync_Post_Error(__('API error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
    827       }
    828 
    829       if ($term_id) {
    830         update_term_meta($term_id, 'api_term_id', $json->_id);
    831         update_term_meta($term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    832         update_term_meta($term_id, 'crowdaa_need_sync', 'no');
     952        throw new Crowdaa_Sync_Category_Error(__('API error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
    833953      }
    834954
    835955      Crowdaa_Sync_Logs::log('Created category', $cat_name, $json->_id);
    836       return ($json->_id);
     956
     957      return ($json);
    837958    }
    838959  }
     
    848969   * @return boolean
    849970   */
    850   public function update_category_api($cat_id, $term_id, $cat_name, $cat_slug, $parent_category_id = '') {
     971  public function update_category($cat_id, $cat_name, $cat_slug, $parent_category_id, $badges) {
    851972    $data = [
    852973      'name'     => $cat_name,
     
    859980      // 'order'    => null,
    860981    ];
     982
     983    if (is_array($badges)) {
     984      $data['badges'] = $badges;
     985      $data['badgesAllow'] = 'all';
     986    }
     987
    861988    $data = apply_filters('crowdaa_sync_api_update_category_payload', $data);
    862989
     
    870997    if ($err) {
    871998      Crowdaa_Sync_Logs::log('Updated category query error', $cat_name, $err);
    872       throw new Crowdaa_Sync_Post_Error(__('Query error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     999      throw new Crowdaa_Sync_Category_Error(__('Query error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
    8731000    } else {
    8741001      if (isset($json->message)) {
    8751002        Crowdaa_Sync_Logs::log('Updated category error', $json->message);
    876         throw new Crowdaa_Sync_Post_Error(__('API error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
    877       }
    878 
    879       update_term_meta($term_id, 'api_term_id', $cat_id);
    880       update_term_meta($term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    881       update_term_meta($term_id, 'crowdaa_need_sync', 'no');
     1003        throw new Crowdaa_Sync_Category_Error(__('API error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     1004      }
    8821005
    8831006      Crowdaa_Sync_Logs::log('Updated category', $cat_name);
     1007
     1008      /** API just returns 'true', so we must rebuild the object as it would have been returned... */
     1009      $ret = (object) $data;
     1010      $ret->_id = $cat_id;
     1011
     1012      if (is_array($badges)) {
     1013        $ret_badges = [];
     1014        foreach ($badges as $badge_id) {
     1015          $ret_badges[] = (object) ['id' => $badge_id];
     1016        }
     1017        $ret->badges = (object) [
     1018          'list' => $ret_badges,
     1019          'allow' => $data['badgesAllow'],
     1020        ];
     1021      }
     1022
     1023      return ($ret);
     1024    }
     1025  }
     1026
     1027  public function delete_category($cat_id) {
     1028    $response = $this->http_request('DELETE', '/press/categories/'.$cat_id);
     1029    $err    = is_wp_error($response) ? $response->get_error_message() : null;
     1030    if (!$err) {
     1031      $body = wp_remote_retrieve_body($response);
     1032      $json = json_decode($body);
     1033    }
     1034
     1035    if ($err) {
     1036      Crowdaa_Sync_Logs::log('Deleted category query error', $cat_name, $err);
     1037      throw new Crowdaa_Sync_Category_Error(__('Query error during category delete : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     1038    } else {
     1039      if (isset($json->message)) {
     1040        Crowdaa_Sync_Logs::log('Deleted category error', $json->message);
     1041        throw new Crowdaa_Sync_Category_Error(__('API error during category delete : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     1042      }
     1043
     1044      Crowdaa_Sync_Logs::log('Deleted category', $cat_name);
    8841045    }
    8851046  }
  • crowdaa-sync/tags/1.2.0/admin/class-crowdaa-sync-ext-hooks.php

    r2722017 r2744975  
    3939    }
    4040
     41    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     42      global $wpdb;
     43      $user_memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_users, [
     44        'user_id' => $user->data->ID,
     45        'status' => 'active',
     46      ], 'id');
     47
     48      if (count($user_memberships) > 0) {
     49        $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     50        $wp_ids = Crowdaa_Sync_Utils::object_array_extract_field('id', $user_memberships);
     51        $synced = $sync_db->get_entry_with_wp_id($wp_ids, 'api_id');
     52        $api_ids = Crowdaa_Sync_Utils::object_array_extract_field('api_id', $synced);
     53        $data['user_badges'] = $api_ids;
     54      }
     55    }
     56
     57    /**
     58     * @TODO Use that in the API.
     59     */
     60
    4161    return ($data);
    4262  }
  • crowdaa-sync/tags/1.2.0/admin/class-crowdaa-sync-wp-hooks.php

    r2620193 r2744975  
    2121    add_action('save_post', [$this, 'save_post_without_cat_notice']);
    2222    add_action('save_post', [$this, 'set_need_to_sync_for_post']);
    23     add_action('saved_category', [$this, 'set_need_to_sync_for_category']);
    2423    add_action('admin_notices', [$this, 'sync_admin_notice']);
    2524    add_action('before_delete_post', [$this, 'sync_delete_post']);
     
    9291
    9392  /**
    94    * Set need sync option for category synchronization
    95    *
    96    * @since    1.0.0
    97    * @param $post_id
    98    * @return void
    99    */
    100   public function set_need_to_sync_for_category($term_id) {
    101     update_term_meta($term_id, 'crowdaa_need_sync', 'yes');
    102   }
    103 
    104   /**
    10593   * Hide deleted post from WP to API
    10694   *
  • crowdaa-sync/tags/1.2.0/admin/css/crowdaa-sync-admin.css

    r2722017 r2744975  
    223223  margin-bottom: 10px;
    224224}
     225
     226#crowdaa-reset-form {
     227  display: none;
     228  position: fixed;
     229  top: 0;
     230  left: 0;
     231  right: 0;
     232  bottom: 0;
     233  background-color: rgba(88, 88, 88, 0.88);
     234  text-align: center;
     235  padding: 50px 0;
     236  z-index: 100000;
     237}
     238
     239#crowdaa-reset-form > div {
     240  background-color: white;
     241  padding: 20px 40px 40px;
     242  display: inline-block;
     243  text-align: left;
     244}
     245
     246#crowdaa-reset-form ul {
     247  padding-left: 20px;
     248}
     249
     250#crowdaa-reset-form li {
     251  list-style: initial;
     252}
     253
     254.crowdaa-reset-danger {
     255  background-color: rgb(255, 0, 0);
     256  color: white;
     257  font-weight: bold;
     258  border: none;
     259  border-radius: 10px;
     260  padding: 8px 14px;
     261}
     262
     263.crowdaa-reset-danger:hover {
     264  background-color: rgb(206, 0, 0);
     265  cursor: pointer;
     266}
     267
     268.crowdaa-reset-form-buttons {
     269  display: flex;
     270  justify-content: space-between;
     271  padding-top: 30px;
     272}
     273
     274#crowdaa-reset-dismiss {
     275  background-color: rgb(73, 189, 58);
     276  color: white;
     277  font-weight: bold;
     278  border: none;
     279  border-radius: 10px;
     280  padding: 8px 14px;
     281}
     282#crowdaa-reset-dismiss:hover {
     283  background-color: rgb(54, 143, 43);
     284  cursor: pointer;
     285}
  • crowdaa-sync/tags/1.2.0/admin/js/crowdaa-sync-admin.js

    r2722017 r2744975  
    77    }
    88
    9     function renderOpQueueFor(data, field) {
     9    function renderOpQueueForArticle(data, field) {
    1010      const list = data[field];
    1111      if (!list) {
    12         return('<ul><li>No posts</li></ul>');
     12        return(false);
    1313      }
    1414      if (list === 'disabled') {
     
    1616      }
    1717      if (list.length === 0) {
    18         return('<ul><li>No posts</li></ul>');
     18        return(false);
    1919      }
    2020
    2121      const render = list.reduce(function(acc, item) {
    2222        acc += '<li class="' + field + '"><i>' +
    23           'Post title: <strong>' + item.post_name + '</strong> ' +
    24           'Post CMS ID: <strong>' + (item.api_id ? item.api_id : 'New post') + '</strong>' +
     23          'Post title: <strong>' + escapeHtml(item.post_name) + '</strong> ' +
     24          'Post CMS ID: <strong>' + escapeHtml(item.api_id ? item.api_id : 'New post') + '</strong>' +
    2525          '</i></li>';
    2626        return(acc);
     
    3030    }
    3131
    32     function renderOpQueue(data) {
     32    function renderOpQueueForCategory(data, field) {
     33      const list = data[field];
     34      if (!list) {
     35        return(false);
     36      }
     37      if (list === 'disabled') {
     38        return('<ul><li>Synchronization disabled</li></ul>');
     39      }
     40      if (list.length === 0) {
     41        return(false);
     42      }
     43
     44      const render = list.reduce(function(acc, item) {
     45        acc += '<li class="' + field + '"><i title="' + escapeHtml(item.slug || '') + '">';
     46        if (item.name) {
     47          acc += 'Category : <strong>' + escapeHtml(item.name) + '</strong>';
     48        } else if (item.wp_id) {
     49          acc += 'WP Category ID : <strong>' + escapeHtml(item.wp_id) + '</strong>';
     50        } else if (item.api_id) {
     51          acc += 'API Category ID : <strong>' + escapeHtml(item.api_id) + '</strong>';
     52        }
     53        acc += '</i></li>';
     54        return(acc);
     55      }, '');
     56
     57      return ('<ul>' + render + '</ul>');
     58    }
     59
     60    function renderOpQueueForBadge(data, field) {
     61      const list = data[field];
     62      if (!list) {
     63        return(false);
     64      }
     65      if (list === 'disabled') {
     66        return('<ul><li>Synchronization disabled</li></ul>');
     67      }
     68      if (list.length === 0) {
     69        return(false);
     70      }
     71
     72      const render = list.reduce(function(acc, item) {
     73        acc += '<li class="' + field + '"><i title="' + escapeHtml(item.description || '') + '">';
     74        if (item.name) {
     75          acc += 'Permission : <strong>' + escapeHtml(item.name) + '</strong>';
     76        } else if (item.wp_id) {
     77          acc += 'WP Permission ID : <strong>' + escapeHtml(item.wp_id) + '</strong>';
     78        } else if (item.api_id) {
     79          acc += 'API Permission ID : <strong>' + escapeHtml(item.api_id) + '</strong>';
     80        }
     81        acc += '</i></li>';
     82        return(acc);
     83      }, '');
     84
     85      return ('<ul>' + render + '</ul>');
     86    }
     87
     88    function renderOpQueue(data, showDates, renderCb) {
    3389      let html = '';
    34 
    35       html += '<h2>Synchronize elements from Crowdaa CMS to WordPress</h2>';
    36       html += renderOpQueueFor(data, 'api_to_wp');
    37       html += '<h2>Synchronize elements from WordPress to Crowdaa CMS</h2>';
    38       html += renderOpQueueFor(data, 'wp_to_api');
    39       html += '<h2>Synchronize new elements from Crowdaa CMS</h2>';
    40       html += renderOpQueueFor(data, 'only_api');
    41       html += '<h2>Synchronize new elements from WordPress</h2>';
    42       html += renderOpQueueFor(data, 'only_wp');
     90      let renderedCount = 0;
     91
     92      if (data.error) {
     93        return ('<h3>' + escapeHtml(data.error) + '</h3>');
     94      }
     95
     96      function renderThis(title, key) {
     97        const result = renderCb(data, key);
     98        if (result) {
     99          html += title;
     100          html += result;
     101          renderedCount++;
     102        }
     103      }
     104
     105      renderThis('<h2>Synchronize elements from Crowdaa CMS to WordPress</h2>', 'api_to_wp');
     106      renderThis('<h2>Synchronize elements from WordPress to Crowdaa CMS</h2>', 'wp_to_api');
     107      renderThis('<h2>Synchronize new elements from Crowdaa CMS</h2>', 'only_api');
     108      renderThis('<h2>Synchronize new elements from WordPress</h2>', 'only_wp');
     109      if (data['remove_api']) renderThis('<h2>Elements to remove from Crowdaa CMS</h2>', 'remove_api');
     110      if (data['remove_wp']) renderThis('<h2>Elements to remove from Wordpress</h2>', 'remove_wp');
     111
     112      if (renderedCount === 0) {
     113        html += '<i>Nothing to do</i>';
     114      }
     115
    43116      html += '<br />';
    44117
     
    62135      }
    63136
    64       renderSyncFrom('wp_to_api', 'WordPress to API');
    65       renderSyncFrom('api_to_wp', 'API to WordPress');
     137      if (showDates) {
     138        renderSyncFrom('wp_to_api', 'WordPress to API');
     139        renderSyncFrom('api_to_wp', 'API to WordPress');
     140      }
    66141
    67142      return(html);
     
    105180    $('#crowdaa-sync-categories-mode-whitelist-checkbox').on('change', updateSyncCategoriesSelect);
    106181    updateSyncCategoriesSelect();
     182
     183    $('#crowdaa-reset-request').click(function(e) {
     184      e.preventDefault();
     185
     186      $('#crowdaa-reset-form').show();
     187    });
     188
     189    $('#crowdaa-reset-dismiss').click(function(e) {
     190      e.preventDefault();
     191
     192      $('#crowdaa-reset-form').hide();
     193    });
    107194
    108195    /**
     
    137224            }
    138225
     226            if (data.opqueue.categories) {
     227              if (data.error) {
     228                output += '<p>Here are the categories operations that were attempted :</p>';
     229              } else {
     230                output += '<p>Here are the categories operations that were done :</p>';
     231              }
     232              output += renderOpQueue(data.opqueue.categories, false, renderOpQueueForCategory);
     233            }
     234
     235            if (data.opqueue.badges) {
     236              if (data.error) {
     237                output += '<p>Here are the permission operations that were attempted :</p>';
     238              } else {
     239                output += '<p>Here are the permission operations that were done :</p>';
     240              }
     241              output += renderOpQueue(data.opqueue.badges, false, renderOpQueueForBadge);
     242            }
     243
    139244            if (data.opqueue.articles) {
    140245              if (data.error) {
    141                 output += '<p>Here are the articles operations that were attempted :</p>';
     246                output += '<p>Here are the article operations that were attempted :</p>';
    142247              } else {
    143                 output += '<p>Here are the articles operations that were done :</p>';
     248                output += '<p>Here are the article operations that were done :</p>';
    144249              }
    145               output += renderOpQueue(data.opqueue.articles);
     250              output += renderOpQueue(data.opqueue.articles, true, renderOpQueueForArticle);
    146251            }
    147252
     
    182287          } else {
    183288            $opqueue.html(
     289              '<p>Here are the category operations that should/will be done :</p>' +
     290              renderOpQueue(data.categories, false, renderOpQueueForCategory) +
     291              '<p>Here are the permission operations that should/will be done :</p>' +
     292              renderOpQueue(data.badges, false, renderOpQueueForBadge) +
    184293              '<p>Here are the article operations that should/will be done :</p>' +
    185               renderOpQueue(data.articles)
     294              renderOpQueue(data.articles, true, renderOpQueueForArticle)
    186295            );
    187296          }
  • crowdaa-sync/tags/1.2.0/admin/partials/crowdaa-sync-admin-display.php

    r2722017 r2744975  
    7070  </form>
    7171
     72  <form id="crowdaa-reset-form" method="post" action="<?php $admin_utils->database_reset(); ?>">
     73    <?php wp_nonce_field('crowdaa_reset_data', 'crowdaa_reset'); ?>
     74    <div>
     75      <h3><?php esc_html_e('DO YOU REALLY WANT TO RESET THE DATABASE?', CROWDAA_SYNC_PLUGIN_NAME); ?></h3>
     76      <?php esc_html_e('This action will erase all synchronization data. If you want to run a synchronization again after this step, you will either have to :', CROWDAA_SYNC_PLUGIN_NAME); ?>
     77      <ul>
     78        <li><?php esc_html_e('Change the targeted Crowdaa application', CROWDAA_SYNC_PLUGIN_NAME); ?></li>
     79        <li><?php esc_html_e('Erase the Crowdaa app content (categories, badges and articles)', CROWDAA_SYNC_PLUGIN_NAME); ?></li>
     80        <li><?php esc_html_e('Erase the Wordpress content (categories, permissions and articles)', CROWDAA_SYNC_PLUGIN_NAME); ?></li>
     81      </ul>
     82
     83      <?php esc_html_e('This will also disable automatic synchronization.', CROWDAA_SYNC_PLUGIN_NAME); ?>
     84
     85      <div class="crowdaa-reset-form-buttons">
     86        <button type="button" id="crowdaa-reset-dismiss">
     87          <?php esc_html_e('Cancel', CROWDAA_SYNC_PLUGIN_NAME); ?>
     88        </button>
     89
     90        <button type="submit" class="crowdaa-reset-danger">
     91          <?php esc_html_e('RESET SYNC DATABASE', CROWDAA_SYNC_PLUGIN_NAME); ?>
     92        </button>
     93      </div>
     94    </div>
     95  </form>
     96
     97  <button type="button" class="crowdaa-reset-danger" id="crowdaa-reset-request">
     98    <?php esc_html_e('RESET SYNC DATABASE', CROWDAA_SYNC_PLUGIN_NAME); ?>
     99  </button>
    72100
    73101  <?php
     
    84112        $sync_wpapi_register_enabled = (get_option('crowdaa_sync_wpapi_register_enabled', 'yes') === 'yes');
    85113        $sync_max_duration           = get_option('crowdaa_sync_max_duration', 60);
    86         ?>
    87         <label class="sync-form-checkbox-label">
    88           <span class="sync-form-label"><?php esc_html_e('Periodic synchronization enabled'); ?></span> &nbsp;
     114        $sync_perm_plugin            = get_option('crowdaa_sync_perm_plugin', Crowdaa_Sync_Permissions::all_plugins_list()[0]);
     115        ?>
     116        <label class="sync-form-checkbox-label">
     117          <span class="sync-form-label"><?php esc_html_e('Periodic synchronization enabled', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    89118          <input type="checkbox" name="cron_sync_enable" class="sync-enable-checkbox"
    90119            <?php echo ($sync_cron_enabled ? 'checked="checked"' : ''); ?>
     
    93122        <br />
    94123        <label class="sync-form-checkbox-label">
    95           <span class="sync-form-label"><?php esc_html_e('Synchronize WordPress content to API'); ?></span> &nbsp;
     124          <span class="sync-form-label"><?php esc_html_e('Synchronize WordPress content to API', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    96125          <input type="checkbox" name="sync_wp_to_api_enable" class="sync-enable-checkbox"
    97126            <?php echo ($sync_wp_to_api_enabled ? 'checked="checked"' : ''); ?>
     
    100129        <br />
    101130        <label class="sync-form-checkbox-label">
    102           <span class="sync-form-label"><?php esc_html_e('Synchronize API content to WordPress'); ?></span> &nbsp;
     131          <span class="sync-form-label"><?php esc_html_e('Synchronize API content to WordPress', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    103132          <input type="checkbox" name="sync_api_to_wp_enable" class="sync-enable-checkbox"
    104133            <?php echo ($sync_api_to_wp_enabled ? 'checked="checked"' : ''); ?>
     
    107136        <br />
    108137        <label class="sync-form-checkbox-label">
    109           <span class="sync-form-label"><?php esc_html_e('Enable WP register from app'); ?></span> &nbsp;
     138          <span class="sync-form-label"><?php esc_html_e('Enable WP register from app', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    110139          <input type="checkbox" name="sync_wpapi_register_enable" class="sync-enable-checkbox"
    111140            <?php echo ($sync_wpapi_register_enabled ? 'checked="checked"' : ''); ?>
     
    115144        <?php do_action('crowdaa_sync_configuration_levers'); ?>
    116145        <label class="sync-form-checkbox-label">
    117           <span class="sync-form-label"><?php esc_html_e('Maximum synchronization duration (minutes)'); ?></span> &nbsp;
     146          <span class="sync-form-label"><?php esc_html_e('Maximum synchronization duration (minutes)', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    118147          <input type="number" name="sync_max_duration" min="2" id="sync-duration-field"
    119148            value="<?php echo esc_attr($sync_max_duration); ?>"
    120149          />
     150        </label>
     151        <br />
     152        <label class="sync-form-checkbox-label">
     153          <span class="sync-form-label"><?php esc_html_e('Permissions plugin', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
     154          <select class="sync-permissions-plugin-select" name="sync_perm_plugin[]">
     155            <?php
     156            $perm_plugins_list = Crowdaa_Sync_Permissions::plugins_list();
     157            foreach ($perm_plugins_list as $plugin) { ?>
     158              <option
     159                value="<?php echo esc_attr($plugin); ?>"
     160                <?php echo ($plugin === $sync_perm_plugin ? 'selected="selected"' : ''); ?>
     161              >
     162                <?php esc_html_e($plugin, CROWDAA_SYNC_PLUGIN_NAME); ?>
     163              </option>
     164            <?php } ?>
     165          </select>
    121166        </label>
    122167        <br />
  • crowdaa-sync/tags/1.2.0/crowdaa-sync.php

    r2722534 r2744975  
    1414 * Plugin URI:       
    1515 * Description:       Plugin for synchronizing WordPress site and Crowdaa CMS
    16  * Version:           1.1.1
     16 * Version:           1.2.0
    1717 * Requires at least: 5.5
    1818 * Requires PHP:      7.2
     
    3434 * Uses SemVer - https://semver.org
    3535 */
    36 define('CROWDAA_SYNC_VERSION', '1.1.1');
     36define('CROWDAA_SYNC_VERSION', '1.2.0');
    3737define('CROWDAA_SYNC_PLUGIN_DIR', __DIR__);
    3838define('CROWDAA_SYNC_PLUGIN_NAME', 'crowdaa-sync');
  • crowdaa-sync/tags/1.2.0/includes/class-crowdaa-sync-exception.php

    r2620193 r2744975  
    2222 */
    2323class Crowdaa_Sync_Error extends Exception {}
     24
     25/**
     26 * An exception to handle errors on a single badge synchronzation, requesting to abort.
     27 *
     28 * @since      1.0.0
     29 * @package    Crowdaa-Sync
     30 * @subpackage Crowdaa-Sync/includes
     31 * @author     Crowdaa <contact@crowdaa.com>
     32 */
     33class Crowdaa_Sync_Badge_Error extends Exception {}
     34
     35/**
     36 * An exception to handle errors on a single category synchronzation, requesting to abort.
     37 *
     38 * @since      1.0.0
     39 * @package    Crowdaa-Sync
     40 * @subpackage Crowdaa-Sync/includes
     41 * @author     Crowdaa <contact@crowdaa.com>
     42 */
     43class Crowdaa_Sync_Category_Error extends Exception {}
    2444
    2545/**
  • crowdaa-sync/tags/1.2.0/includes/class-crowdaa-sync.php

    r2722017 r2744975  
    109109
    110110    /**
     111     * The class responsible for general utils used accross the plugin.
     112     */
     113    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-utils.php';
     114
     115    /**
    111116     * The class responsible logging & logs management.
    112117     */
     
    130135
    131136    /**
     137     * The class responsible for permissions plugins management for the plugin.
     138     */
     139    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-permissions.php';
     140
     141    /**
    132142     * The class responsible for checking the execution time of this plugin.
    133143     */
    134144    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-timer.php';
     145
     146    /**
     147     * The class responsible for handling custom synchronizations.
     148     */
     149    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-syncdb.php';
    135150
    136151    /**
  • crowdaa-sync/trunk/CHANGELOG

    r2722017 r2744975  
    66
    77## [Unreleased]
     8
     9## [1.2.0] - 2022-06-14
     10
     11### Added
     12- Permissions/badges synchronization
     13- Synchronization database reset
     14
     15### Changed
     16- Separated categories synchronization from post synchronization
    817
    918## [1.1.0] - 2022-05-11
  • crowdaa-sync/trunk/README.txt

    r2722534 r2744975  
    66Requires PHP: 7.3
    77Tested up to: 5.9
    8 Stable tag: 1.1.1
     8Stable tag: 1.2.0
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
  • crowdaa-sync/trunk/admin/class-crowdaa-sync-add-info-api.php

    r2722017 r2744975  
    100100   */
    101101  public function get_opqueue_ajax() {
     102    $categories_opqueue = $this->get_categories_opqueue();
     103    $badges_opqueue = $this->get_badges_opqueue();
    102104    $articles_opqueue = $this->get_articles_opqueue();
    103105
    104106    wp_send_json([
    105107      'articles' => $articles_opqueue,
     108      'badges' => $badges_opqueue,
     109      'categories' => $categories_opqueue,
    106110    ]);
     111  }
     112
     113  public static function hash_badge(&$badge) {
     114    $data = [
     115      'name' => $badge->name,
     116      'description' => $badge->description,
     117      'access' => $badge->access,
     118      'management' => $badge->management,
     119      'createdAt' => $badge->createdAt,
     120    ];
     121
     122    if (isset($badge->updatedAt)) {
     123      $data['updatedAt'] = $badge->updatedAt;
     124    }
     125
     126    return (hash('sha256', serialize($data)));
     127  }
     128
     129  public static function hash_pmpro_membership(&$membership) {
     130    $data = [
     131      'name'          => ''.   $membership->name,
     132      'description'   => ''.   $membership->description,
     133      'allow_signups' => (int) $membership->allow_signups,
     134    ];
     135
     136    return (hash('sha256', serialize($data)));
     137  }
     138
     139  public static function hash_term(&$term) {
     140    $data = [
     141      'id'          => $term->term_id,
     142      'name'        => $term->name,
     143      'slug'        => $term->slug,
     144      'parent'      => $term->parent,
     145    ];
     146
     147    if (isset($term->rootParentId)) {
     148      $data['rootParentId'] = $term->rootParentId;
     149    }
     150
     151    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     152      global $wpdb;
     153      $memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_categories, [
     154        'category_id' => $term->term_id,
     155      ], ['membership_id']);
     156
     157      $data['memberships'] = $memberships;
     158    }
     159
     160    return (hash('sha256', serialize($data)));
     161  }
     162
     163  public static function hash_category(&$category) {
     164    $data = [
     165      'id'       => $category->_id,
     166      'name'     => $category->name,
     167      'pathName' => $category->pathName,
     168      'parentId' => $category->parentId,
     169    ];
     170
     171    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     172      $data['badges'] = $category->badges;
     173    }
     174
     175    return (hash('sha256', serialize($data)));
     176  }
     177
     178  /**
     179   * Get badges pending sync operations queue
     180   *
     181   * @since    1.0.0
     182   * @return array, object
     183   */
     184  public function get_badges_opqueue() {
     185    Crowdaa_Sync_Logs::log('Syncing, Badges OpQueue fetching');
     186
     187    $crowdaa_sync_articles_wp_to_api_enabled = (get_option('crowdaa_sync_articles_wp_to_api_enabled', 'yes') === 'yes');
     188    $crowdaa_sync_articles_api_to_wp_enabled = (get_option('crowdaa_sync_articles_api_to_wp_enabled', 'yes') === 'yes');
     189    $api_data_class = new Crowdaa_Sync_API();
     190    $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     191
     192    if(!get_option('crowdaa_auth_token')) {
     193      $result = [
     194        'error' => __('User is not connected', CROWDAA_SYNC_PLUGIN_NAME),
     195      ];
     196
     197      return ($result);
     198    }
     199
     200    $result = [
     201      'api_to_wp'  => [],
     202      'wp_to_api'  => [],
     203      'only_api'   => [],
     204      'only_wp'    => [],
     205      'remove_api' => [],
     206      'remove_wp'  => [],
     207    ];
     208
     209    if (!Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     210      return ($result);
     211    }
     212
     213    if (!$crowdaa_sync_articles_api_to_wp_enabled && !$crowdaa_sync_articles_wp_to_api_enabled) {
     214      return ($result);
     215    }
     216
     217    global $wpdb;
     218    $badges = $api_data_class->get_badges();
     219    $synced = $sync_db->get_synced_entries();
     220    $memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_membership_levels);
     221
     222    if (isset($badges->message)) {
     223      $result = [
     224        'error' => __('API query error : ', CROWDAA_SYNC_PLUGIN_NAME).$badges->message,
     225      ];
     226
     227      return ($result);
     228    }
     229
     230    Crowdaa_Sync_Logs::log('OpQueue building...', count($badges).' api badges and '.count($memberships).' wp permissions');
     231
     232    $badges_by_id = [];
     233    foreach ($badges as $badge) {
     234      $badge->hash = self::hash_badge($badge);
     235      $badges_by_id[$badge->_id] = $badge;
     236    }
     237
     238    $synced_by_api_id = [];
     239    $synced_by_wp_id = [];
     240    foreach ($synced as $item) {
     241      $item->badge_hash = $item->sync_data['badge_hash'];
     242      $item->membership_hash = $item->sync_data['membership_hash'];
     243      $synced_by_wp_id[$item->wp_id] = $item;
     244      $synced_by_api_id[$item->api_id] = $item;
     245    }
     246
     247    $memberships_by_id = [];
     248    foreach ($memberships as $membership) {
     249      $membership->hash = self::hash_pmpro_membership($membership);
     250      $memberships_by_id[$membership->id] = $membership;
     251    }
     252
     253    if ($crowdaa_sync_articles_wp_to_api_enabled) {
     254      foreach ($memberships_by_id as $id => $membership) {
     255        if (!array_key_exists($id, $synced_by_wp_id)) {
     256          $result['only_wp'][] = [
     257            'api_id' => null,
     258            'wp_id' => $membership->id,
     259            'name' => $membership->name,
     260            'description' => $membership->description,
     261            'public' => !!$membership->allow_signups,
     262            'hash' => $membership->hash,
     263          ];
     264        } else if ($synced_by_wp_id[$id]->membership_hash !== $membership->hash) {
     265          $result['wp_to_api'][] = [
     266            'api_id' => $synced_by_wp_id[$id]->api_id,
     267            'wp_id' => $membership->id,
     268            'name' => $membership->name,
     269            'description' => $membership->description,
     270            'public' => !!$membership->allow_signups,
     271            'hash' => $membership->hash,
     272          ];
     273        }
     274      }
     275
     276      foreach ($synced_by_wp_id as $wp_id => $synced_item) {
     277        if (!array_key_exists($wp_id, $memberships_by_id)) {
     278          $result['remove_api'][] = [
     279            'wp_id' => null,
     280            'api_id' => $synced_item->api_id,
     281          ];
     282        }
     283      }
     284    }
     285
     286    if ($crowdaa_sync_articles_api_to_wp_enabled) {
     287      foreach ($badges_by_id as $id => $badge) {
     288        if (!array_key_exists($id, $synced_by_api_id)) {
     289          $result['only_api'][] = [
     290            'api_id' => $badge->_id,
     291            'wp_id' => null,
     292            'name' => $badge->name,
     293            'description' => $badge->description,
     294            'public' => (array_search($badge->management, ['request', 'public']) !== false),
     295            'hash' => $badge->hash,
     296          ];
     297        } else if ($synced_by_api_id[$id]->badge_hash !== $badge->hash) {
     298          $result['api_to_wp'][] = [
     299            'api_id' => $badge->_id,
     300            'wp_id' => $synced_by_api_id[$id]->wp_id,
     301            'name' => $badge->name,
     302            'description' => $badge->description,
     303            'public' => (array_search($badge->management, ['request', 'public']) !== false),
     304            'hash' => $badge->hash,
     305          ];
     306        }
     307      }
     308
     309      foreach ($synced_by_api_id as $api_id => $synced_item) {
     310        if (!array_key_exists($api_id, $badges_by_id)) {
     311          $result['remove_wp'][] = [
     312            'wp_id' => $synced_item->wp_id,
     313            'api_id' => null,
     314          ];
     315        }
     316      }
     317    }
     318
     319    return ($result);
     320  }
     321
     322  public function get_categories_opqueue() {
     323    Crowdaa_Sync_Logs::log('Syncing, Categories OpQueue fetching');
     324
     325    $crowdaa_sync_articles_wp_to_api_enabled = (get_option('crowdaa_sync_articles_wp_to_api_enabled', 'yes') === 'yes');
     326    $crowdaa_sync_articles_api_to_wp_enabled = (get_option('crowdaa_sync_articles_api_to_wp_enabled', 'yes') === 'yes');
     327
     328    $result = [
     329      'api_to_wp'  => [],
     330      'wp_to_api'  => [],
     331      'only_api'   => [],
     332      'only_wp'    => [],
     333      'remove_api' => [],
     334      'remove_wp'  => [],
     335    ];
     336
     337    if (!$crowdaa_sync_articles_api_to_wp_enabled && !$crowdaa_sync_articles_wp_to_api_enabled) {
     338      return ($result);
     339    }
     340
     341    /// Fetching all categories and indexing by ID and updated field names
     342    $categories_by_id = [];
     343    $sync_api         = new Crowdaa_Sync_API();
     344    $sync_db          = new Crowdaa_Sync_Syncdb('categories');
     345    $synced           = $sync_db->get_synced_entries();
     346    $all_categories   = $sync_api->get_categories();
     347    if (isset($all_categories->message)) {
     348      return ([
     349        'error' => __('API query error : ', CROWDAA_SYNC_PLUGIN_NAME).$all_categories->message,
     350      ]);
     351    }
     352
     353    if ($all_categories->categories) {
     354      foreach ($all_categories->categories as $category) {
     355        if ($category->parentId) {
     356          $category->rootParentId = $category->parentId;
     357        }
     358        $category->hash = self::hash_category($category);
     359        $categories_by_id[$category->_id] = $category;
     360      }
     361    }
     362
     363    $args = array(
     364      'hide_empty' => false,
     365      'taxonomy'   => 'category',
     366    );
     367    $all_terms = get_terms($args);
     368    $terms_by_id = [];
     369    if(!empty($all_terms)) {
     370      foreach ($all_terms as $term) {
     371        $term->perms = [];
     372
     373        if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     374          global $wpdb;
     375
     376          $perms = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_categories, [
     377            'category_id' => $term->term_id,
     378          ], ['membership_id']);
     379          $perms_array = [];
     380          foreach ($perms as $perm) {
     381            $perms_array[] = $perm->membership_id;
     382          }
     383          $term->perms = $perms_array;
     384        }
     385
     386        $terms_by_id[$term->term_id] = $term;
     387      }
     388    }
     389
     390    /// Fetching filtering modes
     391    $sync_categories_mode = get_option('crowdaa_sync_categories_mode', 'blacklist');
     392    $sync_categories_list = get_option('crowdaa_sync_categories_list', '');
     393    if ($sync_categories_list === '') {
     394      $sync_categories_list = [];
     395    } else {
     396      $sync_categories_list = explode(',', $sync_categories_list);
     397    }
     398
     399    /// Getting list of categories names
     400    $sync_categories_names = [];
     401    foreach ($sync_categories_list as $id) {
     402      if (isset($terms_by_id[$id])) {
     403        $sync_categories_names = $terms_by_id[$id]->name;
     404      }
     405    }
     406
     407    /// Filtering allowed parents from the WP terms
     408    foreach ($terms_by_id as $term) {
     409      $root_term = $term;
     410      while ($root_term->parent) {
     411        $root_term = $terms_by_id[$root_term->parent];
     412      }
     413
     414      if ($sync_categories_mode === 'whitelist' && !in_array($root_term->term_id, $sync_categories_list)) {
     415        $term->rootParentId = null;
     416      } else if ($sync_categories_mode === 'blacklist' && in_array($root_term->term_id, $sync_categories_list)) {
     417        $term->rootParentId = null;
     418      } else if ($root_term->term_id !== $term->term_id) {
     419        $term->rootParentId = $root_term->term_id;
     420      } else {
     421        $term->rootParentId = null;
     422      }
     423      $term->hash = self::hash_term($term);
     424    }
     425
     426    /// Filtering allowed terms
     427    foreach ($terms_by_id as $id => $term) {
     428      if ($sync_categories_mode === 'whitelist' && !in_array($term->term_id, $sync_categories_list)) {
     429        unset($terms_by_id[$id]);
     430      } else if ($sync_categories_mode === 'blacklist' && in_array($term->term_id, $sync_categories_list)) {
     431        unset($terms_by_id[$id]);
     432      }
     433    }
     434
     435    /// Filtering allowed categories
     436    foreach ($categories_by_id as $id => $category) {
     437      if ($sync_categories_mode === 'whitelist' && !in_array($category->name, $sync_categories_names)) {
     438        unset($categories_by_id[$id]);
     439      } else if ($sync_categories_mode === 'blacklist' && in_array($category->name, $sync_categories_names)) {
     440        unset($categories_by_id[$id]);
     441      }
     442    }
     443
     444    /// Specific code to handle migration from previous sync mechanism
     445    if (count($synced) === 0) {
     446      $created = 0;
     447
     448      foreach ($terms_by_id as $term) {
     449        $api_id = get_term_meta($term->term_id, 'api_term_id', true);
     450        if ($api_id && isset($categories_by_id[$api_id])) {
     451          $sync_db->create_entry($term->term_id, $api_id, [
     452            'category_hash' => $categories_by_id[$api_id]->hash,
     453            'term_hash' => $term->hash,
     454          ]);
     455          $created++;
     456        }
     457      }
     458
     459      if ($created > 0) {
     460        $synced = $sync_db->get_synced_entries();
     461      }
     462    }
     463
     464    /// Storing synced
     465    $synced_by_api_id = [];
     466    $synced_by_wp_id = [];
     467    foreach ($synced as $item) {
     468      $item->category_hash = $item->sync_data['category_hash'];
     469      $item->term_hash = $item->sync_data['term_hash'];
     470      if ($sync_categories_mode === 'whitelist' && !in_array($item->wp_id, $sync_categories_list)) {
     471        $sync_db->delete_entry(['id' => $item->id]);
     472      } else if ($sync_categories_mode === 'blacklist' && in_array($item->wp_id, $sync_categories_list)) {
     473        $sync_db->delete_entry(['id' => $item->id]);
     474      } else {
     475        $synced_by_wp_id[$item->wp_id] = $item;
     476        $synced_by_api_id[$item->api_id] = $item;
     477      }
     478    }
     479
     480    Crowdaa_Sync_Logs::log('OpQueue building...', count($all_categories->categories).' api categories and '.count($all_terms).' wp categories');
     481
     482    /// Comparing states and storing oplist
     483    if ($crowdaa_sync_articles_wp_to_api_enabled) {
     484      foreach ([false, true] as $hasParent) {
     485        foreach ($terms_by_id as $id => $term) {
     486          if ((!!$term->rootParentId) === $hasParent) {
     487            if (!array_key_exists($id, $synced_by_wp_id)) {
     488              $result['only_wp'][] = [
     489                'api_id' => null,
     490                'wp_id' => $term->term_id,
     491                'name' => $term->name,
     492                'slug' => $term->slug,
     493                'parentId' => $term->rootParentId,
     494                'perms' => $term->perms,
     495                'hash' => $term->hash,
     496              ];
     497            } else if ($synced_by_wp_id[$id]->term_hash !== $term->hash) {
     498              $result['wp_to_api'][] = [
     499                'api_id' => $synced_by_wp_id[$id]->api_id,
     500                'wp_id' => $term->term_id,
     501                'name' => $term->name,
     502                'slug' => $term->slug,
     503                'parentId' => $term->rootParentId,
     504                'perms' => $term->perms,
     505                'hash' => $term->hash,
     506              ];
     507            }
     508          }
     509        }
     510      }
     511
     512      foreach ($synced_by_wp_id as $wp_id => $synced_item) {
     513        if (!array_key_exists($wp_id, $terms_by_id)) {
     514          $result['remove_api'][] = [
     515            'api_id' => $synced_item->api_id,
     516            'wp_id' => null,
     517          ];
     518        }
     519      }
     520    }
     521
     522    if ($crowdaa_sync_articles_api_to_wp_enabled) {
     523      foreach ([false, true] as $hasParent) {
     524        foreach ($categories_by_id as $id => $category) {
     525          if ((!!$category->parentId) === $hasParent) {
     526            if (!array_key_exists($id, $synced_by_api_id)) {
     527              $result['only_api'][] = [
     528                'api_id' => $category->_id,
     529                'wp_id' => null,
     530                'name' => $category->name,
     531                'slug' => $category->pathName,
     532                'parentId' => $category->parentId,
     533                'badges' => $category->badges,
     534                'hash' => $category->hash,
     535              ];
     536            } else if ($synced_by_api_id[$id]->category_hash !== $category->hash) {
     537              $result['api_to_wp'][] = [
     538                'api_id' => $category->_id,
     539                'wp_id' => $synced_by_api_id[$id]->wp_id,
     540                'name' => $category->name,
     541                'slug' => $category->pathName,
     542                'parentId' => $category->parentId,
     543                'badges' => $category->badges,
     544                'hash' => $category->hash,
     545              ];
     546            }
     547          }
     548        }
     549      }
     550
     551      foreach ($synced_by_api_id as $api_id => $synced_item) {
     552        if (!array_key_exists($api_id, $categories_by_id)) {
     553          $result['remove_wp'][] = [
     554            'wp_id' => $synced_item->wp_id,
     555            'api_id' => null,
     556          ];
     557        }
     558      }
     559    }
     560
     561    return ($result);
    107562  }
    108563
     
    214669    }
    215670
    216     // Compare posts API and WP
    217671    $result = [
    218672      'api_to_wp' => [],
     
    334788
    335789      $info_wp = new Crowdaa_Sync_Add_Info_WP();
     790      $badges_opqueue = $this->get_badges_opqueue();
     791      $categories_opqueue = $this->get_categories_opqueue();
    336792      $articles_opqueue = $this->get_articles_opqueue();
     793
     794      if (isset($badges_opqueue['error']) && $badges_opqueue['error']) {
     795        $result['error'] = $badges_opqueue['error'];
     796        Crowdaa_Sync_Logs::log('Queue', 'error', $badges_opqueue['error']);
     797        return ($result);
     798      }
     799
     800      if (isset($categories_opqueue['error']) && $categories_opqueue['error']) {
     801        $result['error'] = $categories_opqueue['error'];
     802        Crowdaa_Sync_Logs::log('Queue', 'error', $categories_opqueue['error']);
     803        return ($result);
     804      }
    337805
    338806      if (isset($articles_opqueue['error']) && $articles_opqueue['error']) {
     
    343811
    344812      $result['opqueue'] = [
    345         'articles' => $articles_opqueue,
     813        'articles'   => $articles_opqueue,
     814        'badges'     => $badges_opqueue,
     815        'categories' => $categories_opqueue,
    346816      ];
    347817
     818      self::log_opqueue($badges_opqueue, 'badges', 'api_to_wp');
     819      self::log_opqueue($badges_opqueue, 'badges', 'wp_to_api');
     820      self::log_opqueue($badges_opqueue, 'badges', 'only_api');
     821      self::log_opqueue($badges_opqueue, 'badges', 'only_wp');
     822      self::log_opqueue($badges_opqueue, 'badges', 'remove_api');
     823      self::log_opqueue($badges_opqueue, 'badges', 'remove_wp');
     824      self::log_opqueue($categories_opqueue, 'categories', 'api_to_wp');
     825      self::log_opqueue($categories_opqueue, 'categories', 'wp_to_api');
     826      self::log_opqueue($categories_opqueue, 'categories', 'only_api');
     827      self::log_opqueue($categories_opqueue, 'categories', 'only_wp');
     828      self::log_opqueue($categories_opqueue, 'categories', 'remove_api');
     829      self::log_opqueue($categories_opqueue, 'categories', 'remove_wp');
    348830      self::log_opqueue($articles_opqueue, 'articles', 'api_to_wp');
    349831      self::log_opqueue($articles_opqueue, 'articles', 'wp_to_api');
     
    356838
    357839      do_action('crowdaa_sync_articles_synchronization_start');
     840      // Sync WP => API
     841      if (
     842        count($badges_opqueue['wp_to_api']) > 0 ||
     843        count($badges_opqueue['only_wp']) > 0 ||
     844        count($badges_opqueue['remove_api']) > 0
     845      ) {
     846        /** @TODO Continue me, write this function */
     847        $api_errors = $this->sync_badges_api(
     848          $badges_opqueue['wp_to_api'],
     849          $badges_opqueue['only_wp'],
     850          $badges_opqueue['remove_api']
     851        );
     852      }
     853
     854      // Sync API => WP
     855      if (
     856        count($badges_opqueue['api_to_wp']) > 0 ||
     857        count($badges_opqueue['only_api']) > 0 ||
     858        count($badges_opqueue['remove_wp']) > 0
     859      ) {
     860        /** @TODO Continue me, write this function */
     861        $wp_errors = $info_wp->sync_badges_wp(
     862          $badges_opqueue['api_to_wp'],
     863          $badges_opqueue['only_api'],
     864          $badges_opqueue['remove_wp']
     865        );
     866      }
     867
     868      // Sync WP => API
     869      if (
     870        count($categories_opqueue['wp_to_api']) > 0 ||
     871        count($categories_opqueue['only_wp']) > 0 ||
     872        count($categories_opqueue['remove_api']) > 0
     873      ) {
     874        /** @TODO Continue me, write this function */
     875        $api_errors = $this->sync_categories_api(
     876          $categories_opqueue['wp_to_api'],
     877          $categories_opqueue['only_wp'],
     878          $categories_opqueue['remove_api']
     879        );
     880      }
     881
     882      // Sync API => WP
     883      if (
     884        count($categories_opqueue['api_to_wp']) > 0 ||
     885        count($categories_opqueue['only_api']) > 0 ||
     886        count($categories_opqueue['remove_wp']) > 0
     887      ) {
     888        /** @TODO Continue me, write this function */
     889        $wp_errors = $info_wp->sync_categories_wp(
     890          $categories_opqueue['api_to_wp'],
     891          $categories_opqueue['only_api'],
     892          $categories_opqueue['remove_wp']
     893        );
     894      }
     895
    358896      // Sync WP => API
    359897      if (is_array($articles_opqueue['wp_to_api']) && is_array($articles_opqueue['only_wp'])) {
     
    385923    } catch (Crowdaa_Sync_Post_Error $e) {
    386924      $result['error'] = __('Uncaught Post synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
     925    } catch (Crowdaa_Sync_Category_Error $e) {
     926      $result['error'] = __('Category synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
     927    } catch (Crowdaa_Sync_Badge_Error $e) {
     928      $result['error'] = __('Badge synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
    387929    } catch (Crowdaa_Sync_Error $e) {
    388930      $result['error'] = __('Fatal synchronization error : ', CROWDAA_SYNC_PLUGIN_NAME).$e->getMessage();
     
    4671009  }
    4681010
     1011  public function sync_badges_api(
     1012    &$wp_to_api,
     1013    &$only_wp,
     1014    &$remove_api
     1015  ) {
     1016    $elements_to_process = array_merge($wp_to_api, $only_wp, $remove_api);
     1017    if (!$elements_to_process) {
     1018      return (false);
     1019    }
     1020    $sync_api = new Crowdaa_Sync_API();
     1021    $sync_db  = new Crowdaa_Sync_Syncdb('user_badges');
     1022    $errors   = [];
     1023
     1024    foreach ($elements_to_process as $curPermId => $curPerm) {
     1025      Crowdaa_Sync_Timer::check();
     1026      Crowdaa_Sync_Logs::log('Syncing WP>API Badge', $curPermId, wp_json_encode($curPerm));
     1027
     1028      try {
     1029        if (in_array($curPerm, $only_wp, true)) {
     1030          $badge = $sync_api->create_badge($curPerm['name'], $curPerm['description'], $curPerm['public']);
     1031          $sync_db->create_entry($curPerm['wp_id'], $badge->_id, [
     1032            'badge_hash' => self::hash_badge($badge),
     1033            'membership_hash' => $curPerm['hash'],
     1034          ]);
     1035        } else if (in_array($curPerm, $wp_to_api, true)) {
     1036          $badge = $sync_api->update_badge($curPerm['api_id'], $curPerm['name'], $curPerm['description'], $curPerm['public']);
     1037          $sync_db->update_entry(['api_id' => $curPerm['api_id']], [
     1038            'sync_data' => [
     1039              'badge_hash' => self::hash_badge($badge),
     1040              'membership_hash' => $curPerm['hash'],
     1041            ],
     1042          ]);
     1043        } else if (in_array($curPerm, $remove_api, true)) {
     1044          $sync_api->remove_badge($curPerm['api_id']);
     1045          $sync_db->delete_entry(['api_id' => $curPerm['api_id']]);
     1046        }
     1047      } catch (Crowdaa_Sync_Post_Skip_Error $e) {
     1048        Crowdaa_Sync_Logs::log($e->getMessage());
     1049        continue;
     1050      } catch (Crowdaa_Sync_Post_Error $e) {
     1051        Crowdaa_Sync_Logs::log('Badge sync error', $e->getMessage());
     1052        $errors[] = $e->getMessage();
     1053        continue;
     1054      }
     1055    }
     1056
     1057    if (count($elements_to_process) > 0) {
     1058      foreach ($errors as $error) {
     1059        Crowdaa_Sync_Logs::log('Created/updated/removed API badges errors', $error);
     1060      }
     1061
     1062      Crowdaa_Sync_Logs::log(
     1063        'Created/updated API badges',
     1064        count($only_wp).' badges created, '.
     1065        count($wp_to_api).' badges updated and '.
     1066        count($remove_api).' badges removed with '.count($errors).' errors'
     1067      );
     1068    }
     1069
     1070    return ($errors);
     1071  }
     1072
     1073  private static function term_perms_to_badges($perms) {
     1074    $perm_sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     1075    $badges = [];
     1076
     1077    foreach ($perms as $perm_id) {
     1078      $entry = $perm_sync_db->get_entry_with_wp_id($perm_id, 'api_id');
     1079      $badges[] = $entry->api_id;
     1080    }
     1081
     1082    return ($badges);
     1083  }
     1084
     1085  public function sync_categories_api(
     1086    &$wp_to_api,
     1087    &$only_wp,
     1088    &$remove_api
     1089  ) {
     1090    $elements_to_process = array_merge($wp_to_api, $only_wp, $remove_api);
     1091    if (!$elements_to_process) {
     1092      return (false);
     1093    }
     1094    $sync_api     = new Crowdaa_Sync_API();
     1095    $sync_db      = new Crowdaa_Sync_Syncdb('categories');
     1096    $errors       = [];
     1097
     1098    foreach ($elements_to_process as $curTermId => $curTerm) {
     1099      Crowdaa_Sync_Timer::check();
     1100      Crowdaa_Sync_Logs::log('Syncing WP>API Category', $curTermId, wp_json_encode($curTerm));
     1101
     1102      try {
     1103        if (in_array($curTerm, $only_wp, true)) {
     1104          $parentId = null;
     1105          if ($curTerm['parentId']) {
     1106            $parentId = $sync_db->get_entry_with_wp_id($curTerm['parentId'], 'api_id');
     1107            $parentId = $parentId->api_id;
     1108          }
     1109
     1110          $badges = null;
     1111
     1112          if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     1113            $badges = self::term_perms_to_badges($curTerm['perms']);
     1114          }
     1115
     1116          $category = $sync_api->create_category($curTerm['name'], $curTerm['slug'], $parentId, $badges);
     1117          $sync_db->create_entry($curTerm['wp_id'], $category->_id, [
     1118            'category_hash' => self::hash_category($category),
     1119            'term_hash' => $curTerm['hash'],
     1120          ]);
     1121        } else if (in_array($curTerm, $wp_to_api, true)) {
     1122          $parentId = null;
     1123          if ($curTerm['parentId']) {
     1124            $parentId = $sync_db->get_entry_with_wp_id($curTerm['parentId'], 'api_id');
     1125            $parentId = $parentId->api_id;
     1126          }
     1127
     1128          $badges = null;
     1129
     1130          if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     1131            $badges = self::term_perms_to_badges($curTerm['perms']);
     1132          }
     1133
     1134          $category = $sync_api->update_category($curTerm['api_id'], $curTerm['name'], $curTerm['slug'], $parentId, $badges);
     1135          $sync_db->update_entry(['api_id' => $curTerm['api_id']], [
     1136            'sync_data' => [
     1137              'category_hash' => self::hash_category($category),
     1138              'term_hash' => $curTerm['hash'],
     1139            ],
     1140          ]);
     1141        } else if (in_array($curTerm, $remove_api, true)) {
     1142          $sync_api->delete_category($curTerm['api_id']);
     1143          $sync_db->delete_entry(['api_id' => $curTerm['api_id']]);
     1144        }
     1145      } catch (Crowdaa_Sync_Post_Skip_Error $e) {
     1146        Crowdaa_Sync_Logs::log($e->getMessage());
     1147        continue;
     1148      } catch (Crowdaa_Sync_Post_Error $e) {
     1149        Crowdaa_Sync_Logs::log('Badge sync error', $e->getMessage());
     1150        $errors[] = $e->getMessage();
     1151        continue;
     1152      }
     1153    }
     1154
     1155    if (count($elements_to_process) > 0) {
     1156      foreach ($errors as $error) {
     1157        Crowdaa_Sync_Logs::log('Created/updated/removed API categories errors', $error);
     1158      }
     1159
     1160      Crowdaa_Sync_Logs::log(
     1161        'Created/updated API categories',
     1162        count($only_wp).' categories created, '.
     1163        count($wp_to_api).' categories updated and '.
     1164        count($remove_api).' categories removed with '.count($errors).' errors'
     1165      );
     1166    }
     1167
     1168    return ($errors);
     1169  }
     1170
    4691171  public function sync_info_api(&$wp_to_api, &$only_wp) {
    4701172    $posts_add_to_api = array_merge($wp_to_api, $only_wp);
     
    4731175    }
    4741176
    475     $cat_array        = [];
    476     $errors           = [];
    477     $sync_api         = new Crowdaa_Sync_API();
    478     $all_categories   = $sync_api->get_categories();
    479     if (isset($all_categories->message)) {
    480       throw new Crowdaa_Sync_Error(__('Categories fetch error : ', CROWDAA_SYNC_PLUGIN_NAME).$all_categories->message);
    481     }
    482     if ($all_categories->categories) {
    483       foreach ($all_categories->categories as $category) {
    484         $cat_array[$category->_id] = strtolower(trim($category->pathName));
    485       }
    486     }
    487 
    488     $args = array(
    489       'hide_empty' => false,
    490       'taxonomy'   => 'category',
    491     );
    492     $all_terms = get_terms($args);
    493     $terms_hash = [];
    494     if(!empty($all_terms)) {
    495       foreach ($all_terms as $term) {
    496         $terms_hash[$term->term_id] = $term;
    497       }
     1177    $errors             = [];
     1178    $sync_api           = new Crowdaa_Sync_API();
     1179    $cat_sync_db        = new Crowdaa_Sync_Syncdb('categories');
     1180    $cat_synced_entries = $cat_sync_db->get_synced_entries();
     1181
     1182    $cat_wp_to_api_id = [];
     1183    foreach ($cat_synced_entries as $item) {
     1184      $cat_wp_to_api_id[$item->wp_id] = $item->api_id;
    4981185    }
    4991186
     
    5221209    }
    5231210
    524     foreach ($terms_hash as $term) {
    525       $root_term = $term;
    526       while ($root_term->parent) {
    527         $root_term = $terms_hash[$root_term->parent];
    528       }
    529 
    530       if ($sync_categories_mode === 'whitelist' && !in_array($root_term->term_id, $sync_categories_list)) {
    531         $term->root_term_id = null;
    532         continue;
    533       } else if ($sync_categories_mode === 'blacklist' && in_array($root_term->term_id, $sync_categories_list)) {
    534         $term->root_term_id = null;
    535         continue;
    536       }
    537 
    538       if ($root_term->term_id !== $term->term_id) {
    539         $term->root_term_id = $root_term->term_id;
    540       } else {
    541         $term->root_term_id = $term->parent;
    542       }
    543     }
    544 
    5451211    foreach ($posts_add_to_api as $postArrayId => $post) {
    5461212      Crowdaa_Sync_Timer::check();
     
    5591225      $blacklisted = false;
    5601226      foreach ($post_terms as $term) {
    561         $blacklisted_term = false;
    562 
    5631227        if (in_array($term->term_id, $sync_categories_list)) {
    5641228          if ($sync_categories_mode === 'blacklist') {
     
    5671231            $whitelisted = $term->term_id;
    5681232            if (!$post_term) {
    569               $child_term = true; // Lie here to avoid losing this term.
    5701233              $post_term  = [
    571                 'id'   => $term->term_id,
    572                 'slug' => $term->slug,
    573                 'name' => $term->name,
     1234                'id'    => $term->term_id,
     1235                'child' => in_array($term->term_id, $child_terms),
     1236              ];
     1237            } else if (!$post_term['child'] && in_array($term->term_id, $child_terms)) {
     1238              $post_term  = [
     1239                'id'    => $term->term_id,
     1240                'child' => true,
    5741241              ];
    5751242            }
     
    5771244        } else if (
    5781245          $sync_categories_mode !== 'whitelist' &&
    579           !$blacklisted &&
    580           !$post_term &&
    581           in_array($term->term_id, $child_terms)
     1246          !$blacklisted
    5821247        ) {
    583           $child_term = true;
    584           $post_term  = [
    585             'id'   => $term->term_id,
    586             'slug' => $term->slug,
    587             'name' => $term->name,
    588           ];
     1248          if (!$post_term) {
     1249            $post_term  = [
     1250              'id'    => $term->term_id,
     1251              'child' => in_array($term->term_id, $child_terms),
     1252            ];
     1253          } else if (!$post_term['child'] && in_array($term->term_id, $child_terms)) {
     1254            $post_term  = [
     1255              'id'    => $term->term_id,
     1256              'child' => true,
     1257            ];
     1258          }
    5891259        }
    5901260      }
     
    6081278
    6091279        continue;
    610       }
    611 
    612       if ($child_term == false) {
    613         $post_term  = [
    614           'id'   => $post_terms[0]->term_id,
    615           'slug' => $post_terms[0]->slug,
    616           'name' => $post_terms[0]->name,
    617         ];
    618       }
    619 
    620       $term = $terms_hash[$post_term['id']];
    621       if ($term->root_term_id) {
    622         $term = $terms_hash[$term->root_term_id];
    623         $post_term['parent'] = [
    624           'id'   => $term->term_id,
    625           'slug' => $term->slug,
    626           'name' => $term->name,
    627         ];
    6281280      }
    6291281
     
    6411293        }
    6421294
    643         // Create or update parent category, if needed
    644         $parent_api_term_id = false;
    645         if (array_key_exists('parent', $post_term)) {
    646           $api_term_id = get_term_meta($post_term['parent']['id'], 'api_term_id', true);
    647           $api_term_need_update = get_term_meta($post_term['parent']['id'], 'crowdaa_need_sync', true);
    648           $sync_version = get_term_meta($post_term['parent']['id'], 'crowdaa_version', true);
    649           if (!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    650             $api_term_id = array_search(strtolower(trim($post_term['parent']['slug'])), $cat_array);
    651             if ($api_term_id !== false) {
    652               update_term_meta($post_term['parent']['id'], 'api_term_id', $api_term_id);
    653             }
    654           }
    655           $plain_term_name = html_entity_decode($post_term['parent']['name'], ENT_QUOTES);
    656 
    657           if(!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    658             $api_term_id = $sync_api->create_category_api($post_term['parent']['id'], $plain_term_name, $post_term['parent']['slug'], '');
    659             $cat_array[$api_term_id] = $post_term['parent']['slug'];
    660           } elseif($api_term_need_update !== 'no' || $sync_version !== Crowdaa_Sync_Versions::get_version()) {
    661             $sync_api->update_category_api($api_term_id, $post_term['parent']['id'], $plain_term_name, $post_term['parent']['slug'], '');
    662           }
    663 
    664           $parent_api_term_id = $api_term_id;
    665         }
    666 
    667         $api_term_id = get_term_meta($post_term['id'], 'api_term_id', true);
    668         $api_term_need_update = get_term_meta($post_term['id'], 'crowdaa_need_sync', true);
    669         $sync_version = get_term_meta($post_term['id'], 'crowdaa_version', true);
    670         if (!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    671           $api_term_id = array_search(strtolower(trim($post_term['slug'])), $cat_array);
    672           if ($api_term_id !== false) {
    673             update_term_meta($post_term['id'], 'api_term_id', $api_term_id);
    674           }
    675         }
    676         $plain_term_name = html_entity_decode($post_term['name'], ENT_QUOTES);
    677 
    678         if(!$api_term_id || !array_key_exists($api_term_id, $cat_array)) {
    679           $api_term_id = $sync_api->create_category_api($post_term['id'], $plain_term_name, $post_term['slug'], $parent_api_term_id ?: '');
    680           $cat_array[$api_term_id] = $post_term['slug'];
    681         } elseif($api_term_need_update !== 'no' || $sync_version !== Crowdaa_Sync_Versions::get_version()) {
    682           $sync_api->update_category_api($api_term_id, $post_term['id'], $plain_term_name, $post_term['slug'], $parent_api_term_id ?: '');
     1295        // Get category API ID
     1296        $api_term_id = $cat_wp_to_api_id[$post_term['id']];
     1297        if (!$api_term_id) {
     1298          throw new Crowdaa_Sync_Post_Error('Could not find synced category for term '.$post_term['id'].'. This should not happen, aborting sync.');
     1299
     1300          continue;
    6831301        }
    6841302
  • crowdaa-sync/trunk/admin/class-crowdaa-sync-add-info-wp.php

    r2620193 r2744975  
    2020  }
    2121
    22   /**
    23    * Create term
    24    *
    25    * @since    1.0.0
    26    * @param $cat_id
    27    * @param $cat_name
    28    * @return int
    29    */
    30   /** @TODO That whole function was rewritten to handle more edge-cases and was not tested, test it! */
    31   public function get_or_create_term($cat_id, $cat_name) {
    32     $cat_name = esc_html($cat_name);
    33     $post_type_taxonomy = 'category';
    34 
    35     $terms = get_terms([
    36       'hide_empty' => false,
    37       'taxonomy' => $post_type_taxonomy,
    38       'meta_query' => [
    39         [
    40            'key'       => 'api_term_id',
    41            'value'     => $cat_id,
    42            'compare'   => '=',
    43         ],
    44       ],
     22  private function create_permission($name, $description, $public) {
     23    global $wpdb;
     24
     25    $fields = [
     26      'name' => $name,
     27      'description' => $description,
     28      'allow_signups' => $public ? 1 : 0,
     29      'initial_payment' => 0.0,
     30      'billing_amount' => 0.0,
     31    ];
     32
     33    $insCount = $wpdb->insert(
     34      $wpdb->pmpro_membership_levels,
     35      $fields,
     36      Crowdaa_Sync_Utils::wpdb_formats_for($fields)
     37    );
     38
     39    if (!$insCount) {
     40      throw new Crowdaa_Sync_Badge_Error('Could not insert permission named "'.$name.'" in SQL database');
     41    }
     42
     43    $fields['id'] = $wpdb->insert_id;
     44
     45    return ((object) $fields);
     46  }
     47
     48  private function update_permission($wp_id, $name, $description, $public) {
     49    global $wpdb;
     50
     51    $fields = [
     52      'name' => $name,
     53      'description' => $description,
     54      'allow_signups' => $public ? 1 : 0,
     55    ];
     56    $where = ['id' => $wp_id];
     57
     58    $updCount = $wpdb->update(
     59      $wpdb->pmpro_membership_levels,
     60      $fields,
     61      $where,
     62      Crowdaa_Sync_Utils::wpdb_formats_for($fields),
     63      Crowdaa_Sync_Utils::wpdb_formats_for($where)
     64    );
     65
     66    if (!$updCount) {
     67      throw new Crowdaa_Sync_Badge_Error('Could not update permission named "'.$name.'" in SQL database');
     68    }
     69
     70    $fields['id'] = $wp_id;
     71
     72    return ((object) $fields);
     73  }
     74
     75  private function remove_permission($wp_id) {
     76    global $wpdb;
     77
     78    $where = ['id' => $wp_id];
     79    $where2 = ['membership_id' => $wp_id];
     80    $formats2 = Crowdaa_Sync_Utils::wpdb_formats_for($where2);
     81
     82    $wpdb->delete(
     83      $wpdb->pmpro_membership_levels,
     84      $where,
     85      Crowdaa_Sync_Utils::wpdb_formats_for($where)
     86    );
     87
     88    $wpdb->delete($wpdb->pmpro_membership_orders,      $where2, $formats2);
     89    $wpdb->delete($wpdb->pmpro_memberships_categories, $where2, $formats2);
     90    $wpdb->delete($wpdb->pmpro_memberships_pages,      $where2, $formats2);
     91    $wpdb->delete($wpdb->pmpro_memberships_users,      $where2, $formats2);
     92
     93    $where3 = ['pmpro_membership_level_id' => $wp_id];
     94    $formats3 = Crowdaa_Sync_Utils::wpdb_formats_for($where3);
     95    $wpdb->delete($wpdb->pmpro_membership_levelmeta,   $where3, $formats3);
     96  }
     97
     98  private function create_term($name, $slug, $parentId, $badges) {
     99    $term_data = wp_insert_term(esc_html($name), 'category', [
     100      'parent' => $parentId ?: 0,
     101      'slug'   => $slug ?: '',
    45102    ]);
    46 
    47     if (is_wp_error($terms) || !is_array($terms) || count($terms) === 0) {
    48       $terms = get_terms([
    49         'hide_empty' => false,
    50         'taxonomy' => $post_type_taxonomy,
    51         'name' => $cat_name,
    52       ]);
    53     }
    54 
    55     if (!is_wp_error($terms) && is_array($terms) && count($terms) > 0) {
    56       $term_by_name = null;
    57 
    58       foreach ($terms as $term) {
    59         $key = get_term_meta($term->term_id, 'api_term_id', false);
    60         if ($key === $cat_id) {
    61           if ($term->name !== $cat_name) {
    62             wp_update_term($term->term_id, $post_type_taxonomy, [
    63               'name' => $cat_name,
    64               'parent' => $term->parent,
    65               'slug' => $term->slug,
    66               'description' => $term->description,
    67             ]);
    68             update_term_meta($term->term_id, 'crowdaa_need_sync', 'no');
    69             update_term_meta($term->term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
     103    $term = get_term($term_data['term_id'], 'category');
     104
     105    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro') && $badges) {
     106      global $wpdb;
     107
     108      if (isset($badges->list) && count($badges->list) > 0) {
     109        $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     110
     111        foreach ($badges->list as $item) {
     112          $sync_obj = $sync_db->get_entry_with_api_id($item->id, 'wp_id');
     113
     114          Crowdaa_Sync_Utils::quick_insert(
     115            $wpdb->pmpro_memberships_categories,
     116            [
     117              'membership_id' => $sync_obj->wp_id,
     118              'category_id' => $term->term_id,
     119            ]
     120          );
     121        }
     122      }
     123    }
     124
     125    return ($term);
     126  }
     127
     128  private function update_term($term_id, $name, $slug, $parentId, $badges) {
     129    wp_update_term($term_id, 'category', [
     130      'name'   => esc_html($name),
     131      'parent' => $parentId ?: 0,
     132      'slug'   => $slug ?: '',
     133    ]);
     134
     135    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro') && $badges) {
     136      global $wpdb;
     137
     138      if (isset($badges->list) && is_array($badges->list)) {
     139        $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     140        $current_memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_categories, [
     141          'category_id' => $term_id,
     142        ], ['membership_id']);
     143        $membership_hash = [];
     144        foreach ($current_memberships as $membership) {
     145          $membership_hash[$membership->membership_id] = true;
     146        }
     147
     148        foreach ($badges->list as $item) {
     149          $sync_obj = $sync_db->get_entry_with_api_id($item->id, 'wp_id');
     150
     151          if (!isset($membership_hash[$sync_obj->wp_id])) {
     152            Crowdaa_Sync_Utils::quick_insert(
     153              $wpdb->pmpro_memberships_categories,
     154              [
     155                'membership_id' => $sync_obj->wp_id,
     156                'category_id' => $term_id,
     157              ]
     158            );
     159          } else {
     160            unset($membership_hash[$sync_obj->wp_id]);
    70161          }
    71           return $term->term_id;
    72         } else if (!$term_by_name && $key === false && $term->name === $cat_name) {
    73           $term_by_name = $term;
    74         }
    75       }
    76 
    77       if ($term_by_name) {
    78         update_term_meta($term_by_name->term_id, 'crowdaa_need_sync', 'no');
    79         update_term_meta($term_by_name->term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    80         return ($term_by_name->term_id);
    81       }
    82     }
    83 
    84     $term_id         = '';
    85     $data = [
    86       'description' => '',
    87       'parent'      => 0,
    88       'slug'        => '',
    89     ];
    90 
    91     $term = wp_insert_term($cat_name, $post_type_taxonomy, $data);
    92     if(!is_wp_error($term)) {
    93       $term_id = $term['term_id'];
    94       update_term_meta($term_id, 'api_term_id', $cat_id);
    95       update_term_meta($term_id, 'crowdaa_need_sync', 'no');
    96       update_term_meta($term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    97     }
    98     return $term_id;
     162        }
     163
     164        foreach ($membership_hash as $membership_id => $true) {
     165          Crowdaa_Sync_Utils::quick_delete($wpdb->pmpro_memberships_categories, [
     166            'category_id' => $term_id,
     167            'membership_id' => $membership_id,
     168          ]);
     169        }
     170      }
     171    }
     172
     173    $term = get_term($term_id, 'category');
     174
     175    return ($term);
     176  }
     177
     178  private function delete_term($term_id) {
     179    wp_delete_term($term_id, 'category');
     180  }
     181
     182  public function sync_badges_wp(
     183    &$api_to_wp,
     184    &$only_api,
     185    &$remove_wp
     186  ) {
     187    $errors            = [];
     188    $sync_db           = new Crowdaa_Sync_Syncdb('user_badges');
     189    $badges_sync_to_wp = array_merge($api_to_wp, $only_api, $remove_wp);
     190
     191    foreach($badges_sync_to_wp as $curBadgeId => $curBadge) {
     192      Crowdaa_Sync_Timer::check();
     193      Crowdaa_Sync_Logs::log('Syncing API>WP Badge', $curBadgeId, wp_json_encode($curBadge));
     194
     195      if (in_array($curBadge, $only_api, true)) {
     196        $permission = $this->create_permission($curBadge['name'], $curBadge['description'], $curBadge['public']);
     197        $sync_db->create_entry($permission->id, $curBadge['api_id'], [
     198          'badge_hash' => $curBadge['hash'],
     199          'membership_hash' => Crowdaa_Sync_Add_Info_API::hash_pmpro_membership($permission),
     200        ]);
     201      } else if (in_array($curBadge, $api_to_wp, true)) {
     202        $permission = $this->update_permission($curBadge['wp_id'], $curBadge['name'], $curBadge['description'], $curBadge['public']);
     203        $sync_db->update_entry(['wp_id' => $curBadge['wp_id']], [
     204          'sync_data' => [
     205            'badge_hash' => $curBadge['hash'],
     206            'membership_hash' => Crowdaa_Sync_Add_Info_API::hash_pmpro_membership($permission),
     207          ],
     208        ]);
     209      } else if (in_array($curBadge, $remove_wp, true)) {
     210        $this->remove_permission($curBadge['wp_id']);
     211        $sync_db->delete_entry(['wp_id' => $curBadge['wp_id']]);
     212      }
     213    }
     214
     215    if (count($badges_sync_to_wp) > 0) {
     216      Crowdaa_Sync_Logs::log(
     217        'Created/updated WP permissions',
     218        count($only_api).' permissions created, '.
     219        count($api_to_wp).' permissions updated and '.
     220        count($remove_wp).' permissions removed with '.
     221        count($errors).' errors'
     222      );
     223    }
     224
     225    return ($errors);
     226  }
     227
     228  public function sync_categories_wp(
     229    &$api_to_wp,
     230    &$only_api,
     231    &$remove_wp
     232  ) {
     233    $errors                = [];
     234    $sync_db               = new Crowdaa_Sync_Syncdb('categories');
     235    $categories_sync_to_wp = array_merge($api_to_wp, $only_api, $remove_wp);
     236
     237    foreach($categories_sync_to_wp as $curCategoryId => $curCategory) {
     238      Crowdaa_Sync_Timer::check();
     239      Crowdaa_Sync_Logs::log('Syncing API>WP Category', $curCategoryId, wp_json_encode($curCategory));
     240
     241      if (in_array($curCategory, $only_api, true)) {
     242        $parentId = null;
     243        if ($curCategory['parentId']) {
     244          $parentId = $sync_db->get_entry_with_api_id($curCategory['parentId'], 'wp_id');
     245          $parentId = $parentId->wp_id;
     246        }
     247
     248        $term = $this->create_term($curCategory['name'], $curCategory['slug'], $parentId, $curCategory['badges']);
     249        $term->rootParentId = $parentId;
     250        $sync_db->create_entry($term->term_id, $curCategory['api_id'], [
     251          'category_hash' => $curCategory['hash'],
     252          'term_hash' => Crowdaa_Sync_Add_Info_API::hash_term($term),
     253        ]);
     254      } else if (in_array($curCategory, $api_to_wp, true)) {
     255        $parentId = null;
     256        if ($curCategory['parentId']) {
     257          $parentId = $sync_db->get_entry_with_api_id($curCategory['parentId'], 'wp_id');
     258          $parentId = $parentId->wp_id;
     259        }
     260
     261        $term = $this->update_term($curCategory['wp_id'], $curCategory['name'], $curCategory['slug'], $parentId, $curCategory['badges']);
     262        $term->rootParentId = $parentId;
     263        $sync_db->update_entry(['wp_id' => $curCategory['wp_id']], [
     264          'sync_data' => [
     265            'category_hash' => $curCategory['hash'],
     266            'term_hash' => Crowdaa_Sync_Add_Info_API::hash_term($term),
     267          ],
     268        ]);
     269      } else if (in_array($curCategory, $remove_wp, true)) {
     270        $this->delete_term($curCategory['wp_id']);
     271        $sync_db->delete_entry(['wp_id' => $curCategory['wp_id']]);
     272      }
     273    }
     274
     275    if (count($categories_sync_to_wp) > 0) {
     276      Crowdaa_Sync_Logs::log(
     277        'Created/updated WP categories',
     278        count($only_api).' categories created, '.
     279        count($api_to_wp).' categories updated and '.
     280        count($remove_wp).' categories removed with '.
     281        count($errors).' errors'
     282      );
     283    }
     284
     285    return ($errors);
    99286  }
    100287
     
    151338  private function create_wp_post_from_api($api_data) {
    152339    $created_posts  = [];
    153 
    154     $categories = $this->get_or_create_term($api_data->category->_id, $api_data->category->name);
     340    $cat_sync_db    = new Crowdaa_Sync_Syncdb('categories');
     341
     342    $term = $cat_sync_db->get_entry_with_api_id($api_data->category->_id, 'wp_id');
     343    $term = get_term($term->wp_id, 'category');
    155344
    156345    $post_data = [
     
    167356    $post_type_taxonomy = 'category';
    168357
    169     wp_set_post_terms($wp_post_id, [$categories], $post_type_taxonomy);
     358    wp_set_post_terms($wp_post_id, [$term], $post_type_taxonomy);
    170359
    171360    $sync_errors = $this->post_sync_api_medias($api_data, $wp_post_id);
     
    185374    $created_posts  = [];
    186375
    187     $categories = $this->get_or_create_term($api_data->category->_id, $api_data->category->name);
     376    $term = $cat_sync_db->get_entry_with_api_id($api_data->category->_id, 'wp_id');
     377    $term = get_term($term->wp_id, 'category');
    188378
    189379    $data = [
     
    195385    $post_type_taxonomy = 'category';
    196386
    197     wp_set_post_terms($wp_post_id, [$categories], $post_type_taxonomy);
     387    wp_set_post_terms($wp_post_id, [$term], $post_type_taxonomy);
    198388    wp_update_post($data);
    199389    update_post_meta($wp_post_id, 'api_post_id', $api_data->_id);
     
    531721   */
    532722  private function get_uploads($img_url, $img_name) {
     723    $wp_upload_dir = wp_upload_dir();
     724    $file_path     = $wp_upload_dir['basedir'].'/'.'catalogue_images/'.$img_name;
     725
    533726    Crowdaa_Sync_Logs::log('Downloading media to Wordpress',
    534727      'img_url='.$img_url,
    535       'img_name='.$img_name,
     728      'img_path='.$file_path,
    536729    );
    537730
     
    541734        'timeout'         => 45,
    542735        'stream'          => true,
    543         'filename'        => $upload_fname,
     736        'filename'        => $file_path,
    544737        'sslcertificates' => CROWDAA_SYNC_CACERT_PATH,
    545738      ]);
  • crowdaa-sync/trunk/admin/class-crowdaa-sync-admin-display.php

    r2722017 r2744975  
    2727   * @since    1.0.0
    2828   */
     29  public function database_reset() {
     30    if(empty($_POST) || !wp_verify_nonce($_POST['crowdaa_reset'], 'crowdaa_reset_data')) {
     31      return;
     32    }
     33
     34    Crowdaa_Sync_Logs::log('Running database reset');
     35
     36    update_option('crowdaa_cron_sync_enabled', 'no');
     37
     38    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     39      $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     40      $sync_db->reset();
     41    }
     42
     43    $sync_db = new Crowdaa_Sync_Syncdb('categories');
     44    $sync_db->reset();
     45
     46    $table = Crowdaa_Sync_Utils::db_prefix().'postmeta';
     47    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_picture_id']);
     48    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_videos_id']);
     49    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_feedpicture_id']);
     50    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_media_map']);
     51    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_post_id']);
     52    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key LIKE 'crowdaa_%'");
     53
     54    $table = Crowdaa_Sync_Utils::db_prefix().'termmeta';
     55    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key = %s", ['api_term_id']);
     56    Crowdaa_Sync_Utils::quick_query("DELETE FROM `$table` WHERE meta_key LIKE 'crowdaa_%'");
     57
     58    Crowdaa_Sync_Versions::bump_version();
     59
     60    Crowdaa_Sync_Logs::log('Database reset done');
     61  }
     62
    2963  public function enable_sync() {
    3064    if(!isset($_POST['crowdaa_cron_sync_enabled']) || !wp_verify_nonce($_POST['crowdaa_cron_sync_enabled'], 'crowdaa_cron_sync_enabled_data')) {
     
    5488    } else {
    5589      update_option('crowdaa_sync_wpapi_register_enabled', 'no');
     90    }
     91
     92    if(isset($_POST['sync_perm_plugin'])) {
     93      update_option('crowdaa_sync_perm_plugin', $_POST['sync_perm_plugin']);
    5694    }
    5795
     
    69107      'WP-API register' => get_option('crowdaa_sync_wpapi_register_enabled') === 'yes',
    70108      'duration' => get_option('crowdaa_sync_max_duration', 60),
     109      'perm_plugin' => get_option('crowdaa_sync_perm_plugin', '-'),
    71110    ];
    72111    $sync_logs = apply_filters('crowdaa_sync_configure_levers_log', $sync_logs);
  • crowdaa-sync/trunk/admin/class-crowdaa-sync-api.php

    r2722017 r2744975  
    8888  }
    8989
     90  public function get_badges() {
     91    $url = '/userBadges';
     92    $response = $this->http_request('GET', $url);
     93    $err = is_wp_error($response) ? $response->get_error_message() : null;
     94    if (!$err) {
     95      $body = wp_remote_retrieve_body($response);
     96      $json = json_decode($body);
     97    }
     98
     99    if ($err) {
     100      Crowdaa_Sync_Logs::log('Get badges query error', $err);
     101      return ((object) [
     102        'message' => $err,
     103      ]);
     104    }
     105
     106    if (isset($json->message)) {
     107      Crowdaa_Sync_Logs::log('Get badges error', $json->message);
     108    }
     109
     110    foreach ($json->userBadges as &$v) {
     111      if (!isset($v->management)) {
     112        $v->management = 'private-internal';
     113      }
     114      if (!isset($v->access)) {
     115        $v->access = 'hidden';
     116      }
     117    }
     118
     119    return ($json->userBadges);
     120  }
    90121
    91122  /**
     
    614645        $gallery_ids = array_diff($gallery_ids, $bad_ids);
    615646        if (count($gallery_ids) === 0 && !$thumbnail_id) {
    616           throw new Crowdaa_Sync_Post_Error(__('No picture could be synchronized for post ').$wp_post_id);
     647          throw new Crowdaa_Sync_Post_Error(__('No picture could be synchronized for post ', CROWDAA_SYNC_PLUGIN_NAME).$wp_post_id);
    617648        }
    618649      }
     
    789820  }
    790821
     822  public function create_badge($name, $description, $public) {
     823    $data = [
     824      'name'          => $name,
     825      'description'   => $description,
     826      'management'    => $public ? 'public' : 'private-internal',
     827      'access'        => 'teaser',
     828      'isDefault'     => false,
     829      'validationUrl' => '',
     830    ];
     831    $data = apply_filters('crowdaa_sync_api_create_badge_payload', $data);
     832
     833    $response = $this->http_request('POST', '/userBadges', $data);
     834    $err      = is_wp_error($response) ? $response->get_error_message() : null;
     835    if (!$err) {
     836      $body = wp_remote_retrieve_body($response);
     837      $json = json_decode($body);
     838    }
     839
     840    if ($err) {
     841      Crowdaa_Sync_Logs::log('Create badge query error', $name, $err);
     842      throw new Crowdaa_Sync_Post_Error(__('Query error during badge creation : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     843    } else {
     844      if (isset($json->message)) {
     845        Crowdaa_Sync_Logs::log('Create badge error', $name, $json->message);
     846        throw new Crowdaa_Sync_Post_Error(__('API error during badge creation : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     847      }
     848
     849      Crowdaa_Sync_Logs::log('Created badge', wp_json_encode($json->userBadge));
     850
     851      return ($json->userBadge);
     852    }
     853  }
     854
     855  public function update_badge($badge_id, $name, $description, $public) {
     856    $data = [
     857      'name'          => $name,
     858      'description'   => $description,
     859      'management'    => $public ? 'public' : 'private-internal',
     860      'access'        => 'teaser',
     861      'isDefault'     => false,
     862      'validationUrl' => '',
     863    ];
     864    $data = apply_filters('crowdaa_sync_api_update_badge_payload', $data);
     865
     866    $response = $this->http_request('PUT', "/userBadges/$badge_id", $data);
     867    $err      = is_wp_error($response) ? $response->get_error_message() : null;
     868    if (!$err) {
     869      $body = wp_remote_retrieve_body($response);
     870      $json = json_decode($body);
     871    }
     872
     873    if ($err) {
     874      Crowdaa_Sync_Logs::log('Update badge query error', $name, $err);
     875      throw new Crowdaa_Sync_Post_Error(__('Query error during badge update : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     876    } else {
     877      if (isset($json->message)) {
     878        Crowdaa_Sync_Logs::log('Update badge error', $name, $json->message);
     879        throw new Crowdaa_Sync_Post_Error(__('API error during badge update : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     880      }
     881
     882      Crowdaa_Sync_Logs::log('Updated badge', wp_json_encode($json->userBadge));
     883
     884      return ($json->userBadge);
     885    }
     886  }
     887
     888  public function remove_badge($badge_id) {
     889    $response = $this->http_request('DELETE', "/userBadges/$badge_id");
     890    $err      = is_wp_error($response) ? $response->get_error_message() : null;
     891    if (!$err) {
     892      $body = wp_remote_retrieve_body($response);
     893      $json = json_decode($body);
     894    }
     895
     896    if ($err) {
     897      Crowdaa_Sync_Logs::log('Delete badge query error', $name, $err);
     898      throw new Crowdaa_Sync_Post_Error(__('Query error during badge delete : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     899    } else {
     900      if (isset($json->message)) {
     901        Crowdaa_Sync_Logs::log('Delete badge error', $name, $json->message);
     902        throw new Crowdaa_Sync_Post_Error(__('API error during badge delete : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     903      }
     904
     905      Crowdaa_Sync_Logs::log('Deleted badge', $badge_id);
     906    }
     907
     908    return (true);
     909  }
     910
    791911  /**
    792912   * Create category on the API
     
    798918   * @return boolean
    799919   */
    800   public function create_category_api($term_id, $cat_name, $cat_slug, $parent_category_id = '') {
     920  public function create_category($cat_name, $cat_slug, $parent_category_id, $badges) {
    801921    $data = [
    802922      'name'     => $cat_name,
     
    809929      'action'   => '',
    810930    ];
     931
     932    if (is_array($badges)) {
     933      $data['badges'] = $badges;
     934      $data['badgesAllow'] = 'all';
     935    }
     936
    811937    $data = apply_filters('crowdaa_sync_api_create_category_payload', $data);
    812938
     
    820946    if ($err) {
    821947      Crowdaa_Sync_Logs::log('Create category query error', $cat_name, $err);
    822       throw new Crowdaa_Sync_Post_Error(__('Query error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     948      throw new Crowdaa_Sync_Category_Error(__('Query error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
    823949    } else {
    824950      if (isset($json->message)) {
    825951        Crowdaa_Sync_Logs::log('Create category error', $cat_name, $json->message);
    826         throw new Crowdaa_Sync_Post_Error(__('API error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
    827       }
    828 
    829       if ($term_id) {
    830         update_term_meta($term_id, 'api_term_id', $json->_id);
    831         update_term_meta($term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    832         update_term_meta($term_id, 'crowdaa_need_sync', 'no');
     952        throw new Crowdaa_Sync_Category_Error(__('API error during category creation : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
    833953      }
    834954
    835955      Crowdaa_Sync_Logs::log('Created category', $cat_name, $json->_id);
    836       return ($json->_id);
     956
     957      return ($json);
    837958    }
    838959  }
     
    848969   * @return boolean
    849970   */
    850   public function update_category_api($cat_id, $term_id, $cat_name, $cat_slug, $parent_category_id = '') {
     971  public function update_category($cat_id, $cat_name, $cat_slug, $parent_category_id, $badges) {
    851972    $data = [
    852973      'name'     => $cat_name,
     
    859980      // 'order'    => null,
    860981    ];
     982
     983    if (is_array($badges)) {
     984      $data['badges'] = $badges;
     985      $data['badgesAllow'] = 'all';
     986    }
     987
    861988    $data = apply_filters('crowdaa_sync_api_update_category_payload', $data);
    862989
     
    870997    if ($err) {
    871998      Crowdaa_Sync_Logs::log('Updated category query error', $cat_name, $err);
    872       throw new Crowdaa_Sync_Post_Error(__('Query error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     999      throw new Crowdaa_Sync_Category_Error(__('Query error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
    8731000    } else {
    8741001      if (isset($json->message)) {
    8751002        Crowdaa_Sync_Logs::log('Updated category error', $json->message);
    876         throw new Crowdaa_Sync_Post_Error(__('API error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
    877       }
    878 
    879       update_term_meta($term_id, 'api_term_id', $cat_id);
    880       update_term_meta($term_id, 'crowdaa_version', Crowdaa_Sync_Versions::get_version());
    881       update_term_meta($term_id, 'crowdaa_need_sync', 'no');
     1003        throw new Crowdaa_Sync_Category_Error(__('API error during category update : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     1004      }
    8821005
    8831006      Crowdaa_Sync_Logs::log('Updated category', $cat_name);
     1007
     1008      /** API just returns 'true', so we must rebuild the object as it would have been returned... */
     1009      $ret = (object) $data;
     1010      $ret->_id = $cat_id;
     1011
     1012      if (is_array($badges)) {
     1013        $ret_badges = [];
     1014        foreach ($badges as $badge_id) {
     1015          $ret_badges[] = (object) ['id' => $badge_id];
     1016        }
     1017        $ret->badges = (object) [
     1018          'list' => $ret_badges,
     1019          'allow' => $data['badgesAllow'],
     1020        ];
     1021      }
     1022
     1023      return ($ret);
     1024    }
     1025  }
     1026
     1027  public function delete_category($cat_id) {
     1028    $response = $this->http_request('DELETE', '/press/categories/'.$cat_id);
     1029    $err    = is_wp_error($response) ? $response->get_error_message() : null;
     1030    if (!$err) {
     1031      $body = wp_remote_retrieve_body($response);
     1032      $json = json_decode($body);
     1033    }
     1034
     1035    if ($err) {
     1036      Crowdaa_Sync_Logs::log('Deleted category query error', $cat_name, $err);
     1037      throw new Crowdaa_Sync_Category_Error(__('Query error during category delete : ', CROWDAA_SYNC_PLUGIN_NAME).$err);
     1038    } else {
     1039      if (isset($json->message)) {
     1040        Crowdaa_Sync_Logs::log('Deleted category error', $json->message);
     1041        throw new Crowdaa_Sync_Category_Error(__('API error during category delete : ', CROWDAA_SYNC_PLUGIN_NAME).$json->message);
     1042      }
     1043
     1044      Crowdaa_Sync_Logs::log('Deleted category', $cat_name);
    8841045    }
    8851046  }
  • crowdaa-sync/trunk/admin/class-crowdaa-sync-ext-hooks.php

    r2722017 r2744975  
    3939    }
    4040
     41    if (Crowdaa_Sync_Utils::have_plugin('paid-memberships-pro')) {
     42      global $wpdb;
     43      $user_memberships = Crowdaa_Sync_Utils::quick_select($wpdb->pmpro_memberships_users, [
     44        'user_id' => $user->data->ID,
     45        'status' => 'active',
     46      ], 'id');
     47
     48      if (count($user_memberships) > 0) {
     49        $sync_db = new Crowdaa_Sync_Syncdb('user_badges');
     50        $wp_ids = Crowdaa_Sync_Utils::object_array_extract_field('id', $user_memberships);
     51        $synced = $sync_db->get_entry_with_wp_id($wp_ids, 'api_id');
     52        $api_ids = Crowdaa_Sync_Utils::object_array_extract_field('api_id', $synced);
     53        $data['user_badges'] = $api_ids;
     54      }
     55    }
     56
     57    /**
     58     * @TODO Use that in the API.
     59     */
     60
    4161    return ($data);
    4262  }
  • crowdaa-sync/trunk/admin/class-crowdaa-sync-wp-hooks.php

    r2620193 r2744975  
    2121    add_action('save_post', [$this, 'save_post_without_cat_notice']);
    2222    add_action('save_post', [$this, 'set_need_to_sync_for_post']);
    23     add_action('saved_category', [$this, 'set_need_to_sync_for_category']);
    2423    add_action('admin_notices', [$this, 'sync_admin_notice']);
    2524    add_action('before_delete_post', [$this, 'sync_delete_post']);
     
    9291
    9392  /**
    94    * Set need sync option for category synchronization
    95    *
    96    * @since    1.0.0
    97    * @param $post_id
    98    * @return void
    99    */
    100   public function set_need_to_sync_for_category($term_id) {
    101     update_term_meta($term_id, 'crowdaa_need_sync', 'yes');
    102   }
    103 
    104   /**
    10593   * Hide deleted post from WP to API
    10694   *
  • crowdaa-sync/trunk/admin/css/crowdaa-sync-admin.css

    r2722017 r2744975  
    223223  margin-bottom: 10px;
    224224}
     225
     226#crowdaa-reset-form {
     227  display: none;
     228  position: fixed;
     229  top: 0;
     230  left: 0;
     231  right: 0;
     232  bottom: 0;
     233  background-color: rgba(88, 88, 88, 0.88);
     234  text-align: center;
     235  padding: 50px 0;
     236  z-index: 100000;
     237}
     238
     239#crowdaa-reset-form > div {
     240  background-color: white;
     241  padding: 20px 40px 40px;
     242  display: inline-block;
     243  text-align: left;
     244}
     245
     246#crowdaa-reset-form ul {
     247  padding-left: 20px;
     248}
     249
     250#crowdaa-reset-form li {
     251  list-style: initial;
     252}
     253
     254.crowdaa-reset-danger {
     255  background-color: rgb(255, 0, 0);
     256  color: white;
     257  font-weight: bold;
     258  border: none;
     259  border-radius: 10px;
     260  padding: 8px 14px;
     261}
     262
     263.crowdaa-reset-danger:hover {
     264  background-color: rgb(206, 0, 0);
     265  cursor: pointer;
     266}
     267
     268.crowdaa-reset-form-buttons {
     269  display: flex;
     270  justify-content: space-between;
     271  padding-top: 30px;
     272}
     273
     274#crowdaa-reset-dismiss {
     275  background-color: rgb(73, 189, 58);
     276  color: white;
     277  font-weight: bold;
     278  border: none;
     279  border-radius: 10px;
     280  padding: 8px 14px;
     281}
     282#crowdaa-reset-dismiss:hover {
     283  background-color: rgb(54, 143, 43);
     284  cursor: pointer;
     285}
  • crowdaa-sync/trunk/admin/js/crowdaa-sync-admin.js

    r2722017 r2744975  
    77    }
    88
    9     function renderOpQueueFor(data, field) {
     9    function renderOpQueueForArticle(data, field) {
    1010      const list = data[field];
    1111      if (!list) {
    12         return('<ul><li>No posts</li></ul>');
     12        return(false);
    1313      }
    1414      if (list === 'disabled') {
     
    1616      }
    1717      if (list.length === 0) {
    18         return('<ul><li>No posts</li></ul>');
     18        return(false);
    1919      }
    2020
    2121      const render = list.reduce(function(acc, item) {
    2222        acc += '<li class="' + field + '"><i>' +
    23           'Post title: <strong>' + item.post_name + '</strong> ' +
    24           'Post CMS ID: <strong>' + (item.api_id ? item.api_id : 'New post') + '</strong>' +
     23          'Post title: <strong>' + escapeHtml(item.post_name) + '</strong> ' +
     24          'Post CMS ID: <strong>' + escapeHtml(item.api_id ? item.api_id : 'New post') + '</strong>' +
    2525          '</i></li>';
    2626        return(acc);
     
    3030    }
    3131
    32     function renderOpQueue(data) {
     32    function renderOpQueueForCategory(data, field) {
     33      const list = data[field];
     34      if (!list) {
     35        return(false);
     36      }
     37      if (list === 'disabled') {
     38        return('<ul><li>Synchronization disabled</li></ul>');
     39      }
     40      if (list.length === 0) {
     41        return(false);
     42      }
     43
     44      const render = list.reduce(function(acc, item) {
     45        acc += '<li class="' + field + '"><i title="' + escapeHtml(item.slug || '') + '">';
     46        if (item.name) {
     47          acc += 'Category : <strong>' + escapeHtml(item.name) + '</strong>';
     48        } else if (item.wp_id) {
     49          acc += 'WP Category ID : <strong>' + escapeHtml(item.wp_id) + '</strong>';
     50        } else if (item.api_id) {
     51          acc += 'API Category ID : <strong>' + escapeHtml(item.api_id) + '</strong>';
     52        }
     53        acc += '</i></li>';
     54        return(acc);
     55      }, '');
     56
     57      return ('<ul>' + render + '</ul>');
     58    }
     59
     60    function renderOpQueueForBadge(data, field) {
     61      const list = data[field];
     62      if (!list) {
     63        return(false);
     64      }
     65      if (list === 'disabled') {
     66        return('<ul><li>Synchronization disabled</li></ul>');
     67      }
     68      if (list.length === 0) {
     69        return(false);
     70      }
     71
     72      const render = list.reduce(function(acc, item) {
     73        acc += '<li class="' + field + '"><i title="' + escapeHtml(item.description || '') + '">';
     74        if (item.name) {
     75          acc += 'Permission : <strong>' + escapeHtml(item.name) + '</strong>';
     76        } else if (item.wp_id) {
     77          acc += 'WP Permission ID : <strong>' + escapeHtml(item.wp_id) + '</strong>';
     78        } else if (item.api_id) {
     79          acc += 'API Permission ID : <strong>' + escapeHtml(item.api_id) + '</strong>';
     80        }
     81        acc += '</i></li>';
     82        return(acc);
     83      }, '');
     84
     85      return ('<ul>' + render + '</ul>');
     86    }
     87
     88    function renderOpQueue(data, showDates, renderCb) {
    3389      let html = '';
    34 
    35       html += '<h2>Synchronize elements from Crowdaa CMS to WordPress</h2>';
    36       html += renderOpQueueFor(data, 'api_to_wp');
    37       html += '<h2>Synchronize elements from WordPress to Crowdaa CMS</h2>';
    38       html += renderOpQueueFor(data, 'wp_to_api');
    39       html += '<h2>Synchronize new elements from Crowdaa CMS</h2>';
    40       html += renderOpQueueFor(data, 'only_api');
    41       html += '<h2>Synchronize new elements from WordPress</h2>';
    42       html += renderOpQueueFor(data, 'only_wp');
     90      let renderedCount = 0;
     91
     92      if (data.error) {
     93        return ('<h3>' + escapeHtml(data.error) + '</h3>');
     94      }
     95
     96      function renderThis(title, key) {
     97        const result = renderCb(data, key);
     98        if (result) {
     99          html += title;
     100          html += result;
     101          renderedCount++;
     102        }
     103      }
     104
     105      renderThis('<h2>Synchronize elements from Crowdaa CMS to WordPress</h2>', 'api_to_wp');
     106      renderThis('<h2>Synchronize elements from WordPress to Crowdaa CMS</h2>', 'wp_to_api');
     107      renderThis('<h2>Synchronize new elements from Crowdaa CMS</h2>', 'only_api');
     108      renderThis('<h2>Synchronize new elements from WordPress</h2>', 'only_wp');
     109      if (data['remove_api']) renderThis('<h2>Elements to remove from Crowdaa CMS</h2>', 'remove_api');
     110      if (data['remove_wp']) renderThis('<h2>Elements to remove from Wordpress</h2>', 'remove_wp');
     111
     112      if (renderedCount === 0) {
     113        html += '<i>Nothing to do</i>';
     114      }
     115
    43116      html += '<br />';
    44117
     
    62135      }
    63136
    64       renderSyncFrom('wp_to_api', 'WordPress to API');
    65       renderSyncFrom('api_to_wp', 'API to WordPress');
     137      if (showDates) {
     138        renderSyncFrom('wp_to_api', 'WordPress to API');
     139        renderSyncFrom('api_to_wp', 'API to WordPress');
     140      }
    66141
    67142      return(html);
     
    105180    $('#crowdaa-sync-categories-mode-whitelist-checkbox').on('change', updateSyncCategoriesSelect);
    106181    updateSyncCategoriesSelect();
     182
     183    $('#crowdaa-reset-request').click(function(e) {
     184      e.preventDefault();
     185
     186      $('#crowdaa-reset-form').show();
     187    });
     188
     189    $('#crowdaa-reset-dismiss').click(function(e) {
     190      e.preventDefault();
     191
     192      $('#crowdaa-reset-form').hide();
     193    });
    107194
    108195    /**
     
    137224            }
    138225
     226            if (data.opqueue.categories) {
     227              if (data.error) {
     228                output += '<p>Here are the categories operations that were attempted :</p>';
     229              } else {
     230                output += '<p>Here are the categories operations that were done :</p>';
     231              }
     232              output += renderOpQueue(data.opqueue.categories, false, renderOpQueueForCategory);
     233            }
     234
     235            if (data.opqueue.badges) {
     236              if (data.error) {
     237                output += '<p>Here are the permission operations that were attempted :</p>';
     238              } else {
     239                output += '<p>Here are the permission operations that were done :</p>';
     240              }
     241              output += renderOpQueue(data.opqueue.badges, false, renderOpQueueForBadge);
     242            }
     243
    139244            if (data.opqueue.articles) {
    140245              if (data.error) {
    141                 output += '<p>Here are the articles operations that were attempted :</p>';
     246                output += '<p>Here are the article operations that were attempted :</p>';
    142247              } else {
    143                 output += '<p>Here are the articles operations that were done :</p>';
     248                output += '<p>Here are the article operations that were done :</p>';
    144249              }
    145               output += renderOpQueue(data.opqueue.articles);
     250              output += renderOpQueue(data.opqueue.articles, true, renderOpQueueForArticle);
    146251            }
    147252
     
    182287          } else {
    183288            $opqueue.html(
     289              '<p>Here are the category operations that should/will be done :</p>' +
     290              renderOpQueue(data.categories, false, renderOpQueueForCategory) +
     291              '<p>Here are the permission operations that should/will be done :</p>' +
     292              renderOpQueue(data.badges, false, renderOpQueueForBadge) +
    184293              '<p>Here are the article operations that should/will be done :</p>' +
    185               renderOpQueue(data.articles)
     294              renderOpQueue(data.articles, true, renderOpQueueForArticle)
    186295            );
    187296          }
  • crowdaa-sync/trunk/admin/partials/crowdaa-sync-admin-display.php

    r2722017 r2744975  
    7070  </form>
    7171
     72  <form id="crowdaa-reset-form" method="post" action="<?php $admin_utils->database_reset(); ?>">
     73    <?php wp_nonce_field('crowdaa_reset_data', 'crowdaa_reset'); ?>
     74    <div>
     75      <h3><?php esc_html_e('DO YOU REALLY WANT TO RESET THE DATABASE?', CROWDAA_SYNC_PLUGIN_NAME); ?></h3>
     76      <?php esc_html_e('This action will erase all synchronization data. If you want to run a synchronization again after this step, you will either have to :', CROWDAA_SYNC_PLUGIN_NAME); ?>
     77      <ul>
     78        <li><?php esc_html_e('Change the targeted Crowdaa application', CROWDAA_SYNC_PLUGIN_NAME); ?></li>
     79        <li><?php esc_html_e('Erase the Crowdaa app content (categories, badges and articles)', CROWDAA_SYNC_PLUGIN_NAME); ?></li>
     80        <li><?php esc_html_e('Erase the Wordpress content (categories, permissions and articles)', CROWDAA_SYNC_PLUGIN_NAME); ?></li>
     81      </ul>
     82
     83      <?php esc_html_e('This will also disable automatic synchronization.', CROWDAA_SYNC_PLUGIN_NAME); ?>
     84
     85      <div class="crowdaa-reset-form-buttons">
     86        <button type="button" id="crowdaa-reset-dismiss">
     87          <?php esc_html_e('Cancel', CROWDAA_SYNC_PLUGIN_NAME); ?>
     88        </button>
     89
     90        <button type="submit" class="crowdaa-reset-danger">
     91          <?php esc_html_e('RESET SYNC DATABASE', CROWDAA_SYNC_PLUGIN_NAME); ?>
     92        </button>
     93      </div>
     94    </div>
     95  </form>
     96
     97  <button type="button" class="crowdaa-reset-danger" id="crowdaa-reset-request">
     98    <?php esc_html_e('RESET SYNC DATABASE', CROWDAA_SYNC_PLUGIN_NAME); ?>
     99  </button>
    72100
    73101  <?php
     
    84112        $sync_wpapi_register_enabled = (get_option('crowdaa_sync_wpapi_register_enabled', 'yes') === 'yes');
    85113        $sync_max_duration           = get_option('crowdaa_sync_max_duration', 60);
    86         ?>
    87         <label class="sync-form-checkbox-label">
    88           <span class="sync-form-label"><?php esc_html_e('Periodic synchronization enabled'); ?></span> &nbsp;
     114        $sync_perm_plugin            = get_option('crowdaa_sync_perm_plugin', Crowdaa_Sync_Permissions::all_plugins_list()[0]);
     115        ?>
     116        <label class="sync-form-checkbox-label">
     117          <span class="sync-form-label"><?php esc_html_e('Periodic synchronization enabled', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    89118          <input type="checkbox" name="cron_sync_enable" class="sync-enable-checkbox"
    90119            <?php echo ($sync_cron_enabled ? 'checked="checked"' : ''); ?>
     
    93122        <br />
    94123        <label class="sync-form-checkbox-label">
    95           <span class="sync-form-label"><?php esc_html_e('Synchronize WordPress content to API'); ?></span> &nbsp;
     124          <span class="sync-form-label"><?php esc_html_e('Synchronize WordPress content to API', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    96125          <input type="checkbox" name="sync_wp_to_api_enable" class="sync-enable-checkbox"
    97126            <?php echo ($sync_wp_to_api_enabled ? 'checked="checked"' : ''); ?>
     
    100129        <br />
    101130        <label class="sync-form-checkbox-label">
    102           <span class="sync-form-label"><?php esc_html_e('Synchronize API content to WordPress'); ?></span> &nbsp;
     131          <span class="sync-form-label"><?php esc_html_e('Synchronize API content to WordPress', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    103132          <input type="checkbox" name="sync_api_to_wp_enable" class="sync-enable-checkbox"
    104133            <?php echo ($sync_api_to_wp_enabled ? 'checked="checked"' : ''); ?>
     
    107136        <br />
    108137        <label class="sync-form-checkbox-label">
    109           <span class="sync-form-label"><?php esc_html_e('Enable WP register from app'); ?></span> &nbsp;
     138          <span class="sync-form-label"><?php esc_html_e('Enable WP register from app', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    110139          <input type="checkbox" name="sync_wpapi_register_enable" class="sync-enable-checkbox"
    111140            <?php echo ($sync_wpapi_register_enabled ? 'checked="checked"' : ''); ?>
     
    115144        <?php do_action('crowdaa_sync_configuration_levers'); ?>
    116145        <label class="sync-form-checkbox-label">
    117           <span class="sync-form-label"><?php esc_html_e('Maximum synchronization duration (minutes)'); ?></span> &nbsp;
     146          <span class="sync-form-label"><?php esc_html_e('Maximum synchronization duration (minutes)', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
    118147          <input type="number" name="sync_max_duration" min="2" id="sync-duration-field"
    119148            value="<?php echo esc_attr($sync_max_duration); ?>"
    120149          />
     150        </label>
     151        <br />
     152        <label class="sync-form-checkbox-label">
     153          <span class="sync-form-label"><?php esc_html_e('Permissions plugin', CROWDAA_SYNC_PLUGIN_NAME); ?></span> &nbsp;
     154          <select class="sync-permissions-plugin-select" name="sync_perm_plugin[]">
     155            <?php
     156            $perm_plugins_list = Crowdaa_Sync_Permissions::plugins_list();
     157            foreach ($perm_plugins_list as $plugin) { ?>
     158              <option
     159                value="<?php echo esc_attr($plugin); ?>"
     160                <?php echo ($plugin === $sync_perm_plugin ? 'selected="selected"' : ''); ?>
     161              >
     162                <?php esc_html_e($plugin, CROWDAA_SYNC_PLUGIN_NAME); ?>
     163              </option>
     164            <?php } ?>
     165          </select>
    121166        </label>
    122167        <br />
  • crowdaa-sync/trunk/crowdaa-sync.php

    r2722534 r2744975  
    1414 * Plugin URI:       
    1515 * Description:       Plugin for synchronizing WordPress site and Crowdaa CMS
    16  * Version:           1.1.1
     16 * Version:           1.2.0
    1717 * Requires at least: 5.5
    1818 * Requires PHP:      7.2
     
    3434 * Uses SemVer - https://semver.org
    3535 */
    36 define('CROWDAA_SYNC_VERSION', '1.1.1');
     36define('CROWDAA_SYNC_VERSION', '1.2.0');
    3737define('CROWDAA_SYNC_PLUGIN_DIR', __DIR__);
    3838define('CROWDAA_SYNC_PLUGIN_NAME', 'crowdaa-sync');
  • crowdaa-sync/trunk/includes/class-crowdaa-sync-exception.php

    r2620193 r2744975  
    2222 */
    2323class Crowdaa_Sync_Error extends Exception {}
     24
     25/**
     26 * An exception to handle errors on a single badge synchronzation, requesting to abort.
     27 *
     28 * @since      1.0.0
     29 * @package    Crowdaa-Sync
     30 * @subpackage Crowdaa-Sync/includes
     31 * @author     Crowdaa <contact@crowdaa.com>
     32 */
     33class Crowdaa_Sync_Badge_Error extends Exception {}
     34
     35/**
     36 * An exception to handle errors on a single category synchronzation, requesting to abort.
     37 *
     38 * @since      1.0.0
     39 * @package    Crowdaa-Sync
     40 * @subpackage Crowdaa-Sync/includes
     41 * @author     Crowdaa <contact@crowdaa.com>
     42 */
     43class Crowdaa_Sync_Category_Error extends Exception {}
    2444
    2545/**
  • crowdaa-sync/trunk/includes/class-crowdaa-sync.php

    r2722017 r2744975  
    109109
    110110    /**
     111     * The class responsible for general utils used accross the plugin.
     112     */
     113    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-utils.php';
     114
     115    /**
    111116     * The class responsible logging & logs management.
    112117     */
     
    130135
    131136    /**
     137     * The class responsible for permissions plugins management for the plugin.
     138     */
     139    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-permissions.php';
     140
     141    /**
    132142     * The class responsible for checking the execution time of this plugin.
    133143     */
    134144    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-timer.php';
     145
     146    /**
     147     * The class responsible for handling custom synchronizations.
     148     */
     149    require_once CROWDAA_SYNC_PLUGIN_DIR.'/includes/class-crowdaa-sync-syncdb.php';
    135150
    136151    /**
Note: See TracChangeset for help on using the changeset viewer.