Changeset 3412229
- Timestamp:
- 12/05/2025 01:37:57 PM (4 months ago)
- Location:
- ringier-bus/trunk
- Files:
-
- 11 edited
-
CHANGELOG.md (modified) (1 diff)
-
README.md (modified) (2 diffs)
-
assets/js/sync-tools.js (modified) (6 diffs)
-
readme.txt (modified) (2 diffs)
-
ringier-bus.php (modified) (2 diffs)
-
src/Core/AdminSyncPage.php (modified) (9 diffs)
-
src/Core/Bus/AuthorEvent.php (modified) (3 diffs)
-
src/Core/Bus/BusHelper.php (modified) (6 diffs)
-
src/Core/Bus/TermEvent.php (modified) (3 diffs)
-
src/Core/Enum.php (modified) (1 diff)
-
src/Core/Utils.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ringier-bus/trunk/CHANGELOG.md
r3321163 r3412229 13 13 * (dependency) Fully remove Guzzle/Symfony dependencies 14 14 * (dependency) Fully remove Timber/Twig 15 16 17 ## [3.4.1] - 2025-12-02 ## 18 19 ### Added ### 20 * (code) Added a check to see if the Ringier Author plugin is enabled 21 * If yes, only send events for authors that have their public profile set to ENABLED 22 * If that plugin is not present or disabled, it's business as usual 23 24 ### Fixed ### 25 * (payload) TopicEvents: title, slug and url should be array of objects 15 26 16 27 -
ringier-bus/trunk/README.md
r3321163 r3412229 6 6 **Tags:** ringier, bus, api, cde 7 7 **Requires at least:** 6.0 8 **Tested up to:** 6. 8.19 **Stable tag:** 3.4. 08 **Tested up to:** 6.9 9 **Stable tag:** 3.4.1 10 10 **Requires PHP:** 8.1 11 11 **License:** GPLv2 or later … … 114 114 ``` 115 115 116 ### 4. Controlling Author Event Dispatch ### 117 118 You can control whether the Ringier Bus plugin should dispatch Author events for a specific user by using the **ringier_bus_should_dispatch_author_event** filter. 119 This filter allows you to override the default logic to force enablement or disablement based on your own custom logic - when you want full control over which authors get sent to the Event Bus. 120 121 Example: 122 ```php 123 /** 124 * Example 125 */ 126 add_filter('ringier_bus_should_dispatch_author_event', function (bool $should_dispatch, int $user_id): bool { 127 128 // Example: Always send events for Administrators, ignoring the "Show Profile" checkbox 129 if (user_can($user_id, 'administrator')) { 130 return true; 131 } 132 133 // Example condition: never sync user ID 1234 134 if ($user_id === 1234) { 135 return false; 136 } 137 138 // Otherwise, use the default logic 139 return $should_dispatch; 140 }, 10, 2); 141 ``` 142 143 This filter gives you full flexibility to: 144 - Disable syncing for certain authors 145 - Force syncing regardless of profile visibility 146 - Apply environment-specific rules (e.g., staging vs production) 147 - Implement client-specific dispatch policies 148 116 149 ## Contributing ## 117 150 -
ringier-bus/trunk/assets/js/sync-tools.js
r3316910 r3412229 24 24 const { message, done, skipped } = response.data; 25 25 26 if (skipped) { 27 skippedCount++; 28 progressDiv.append(`<div style="color: red; font-weight: bold;">${message}</div>`); 29 } else { 30 successCount++; 31 progressDiv.append(`<div>${message}</div>`); 32 } 33 34 if (!done) { 35 offset++; 36 syncNextAuthor(); 37 } else { 26 // 1. Check if we are done first 27 if (done) { 28 // If done, we stop the loop and print totals immediately. 29 // We do NOT increment successCount here because this is the "termination" packet. 38 30 progressDiv.append(` 39 31 <hr /> … … 41 33 <ul> 42 34 <li><strong>${successCount}</strong> authors successfully synced</li> 43 <li><strong>${skippedCount}</strong> authors skipped ( no matching role)</li>35 <li><strong>${skippedCount}</strong> authors skipped (Profile Disabled or no matching role)</li> 44 36 </ul> 45 37 <strong style="color: green;">Sync complete!</strong> 46 38 `); 39 } else { 40 // 2. If NOT done, it means we definitely processed a user row. 41 if (skipped) { 42 skippedCount++; 43 progressDiv.append(`<div style="color: red; font-weight: bold;">${message}</div>`); 44 } else { 45 successCount++; 46 progressDiv.append(`<div>${message}</div>`); 47 } 48 49 // 3. Move to next offset and recurse 50 offset++; 51 syncNextAuthor(); 47 52 } 48 53 } else { … … 58 63 59 64 function syncCategories(lastId = 0) { 65 // 1. Initialize the counter 66 let syncedCount = 0; 67 60 68 progressDivCat.html(` 61 <h3>Starting category sync...</h3>62 <p style="font-weight: bold; color: #0073aa;">Please do NOT close this window until the sync is completed.</p>63 <hr />64 `);69 <h3>Starting category sync...</h3> 70 <p style="font-weight: bold; color: #0073aa;">Please do NOT close this window until the sync is completed.</p> 71 <hr /> 72 `); 65 73 66 74 function syncNextCategory(currentId) { … … 71 79 if (response.success && response.data) { 72 80 const { message, done, last_id } = response.data; 73 progressDivCat.append('<div style="color: teal;">[Category] ' + message + '</div>');74 81 75 if (!done) { 82 if (done) { 83 // 3. Display the final count in the summary 84 progressDivCat.append(` 85 <hr /> 86 <h3>Category Sync Complete:</h3> 87 <ul> 88 <li><strong>${syncedCount}</strong> categories successfully synced.</li> 89 </ul> 90 <strong style="color: green;">Process finished.</strong> 91 `); 92 } else { 93 // 2. Increment the counter 94 syncedCount++; 95 96 progressDivCat.append(`<div style="color: teal;">[${syncedCount}] ${message}</div>`); 76 97 syncNextCategory(last_id); 77 } else {78 progressDivCat.append('<strong style="color: green;">All categories have been synced.</strong>');79 98 } 80 99 } else { 81 progressDivCat.append('<div style="color:red;">Error syncing category: ' + response.data+ '</div>');100 progressDivCat.append('<div style="color:red;">Error syncing category: ' + (response.data || 'Unknown error') + '</div>'); 82 101 } 102 }).fail(function(xhr) { 103 progressDivCat.append('<div style="color:red;">Network/Server Error: ' + xhr.status + ' ' + xhr.statusText + '</div>'); 83 104 }); 84 105 } … … 88 109 89 110 function syncTags(lastId = 0) { 90 progressDivTag.html(` 111 // 1. Initialize Sync Counter 112 let syncedCount = 0; 113 114 progressDivTag.html(` 91 115 <h3>Starting tag sync...</h3> 92 116 <p style="font-weight: bold; color: #0073aa;">Please do NOT close this window until the sync is completed.</p> … … 101 125 if (response.success && response.data) { 102 126 const { message, done, last_id } = response.data; 103 progressDivTag.append('<div style="color: purple;">[Tag] ' + message + '</div>');104 127 105 if (!done) { 128 // 2. Logic Check: Are we done? 129 if (done) { 130 progressDivTag.append(` 131 <hr /> 132 <h3>Tag Sync Complete:</h3> 133 <ul> 134 <li><strong>${syncedCount}</strong> tags successfully synced.</li> 135 </ul> 136 <strong style="color: green;">Process finished.</strong> 137 `); 138 } else { 139 // 3. Not done: Increment count and display row 140 syncedCount++; 141 progressDivTag.append(`<div style="color: purple;">[${syncedCount}] ${message}</div>`); 142 143 // 4. Recurse with new ID 106 144 syncNextTag(last_id); 107 } else {108 progressDivTag.append('<strong style="color: green;">All tags have been synced.</strong>');109 145 } 110 146 } else { 111 progressDivTag.append( '<div style="color:red;">Error syncing tag: ' + response.data + '</div>');147 progressDivTag.append(`<div style="color:red;">Error syncing tag: ${response.data || 'Unknown error'}</div>`); 112 148 } 149 }).fail(function(xhr) { 150 // 5. Catch Network/Server Errors 151 progressDivTag.append(`<div style="color:red;">Network/Server Error: ${xhr.status} - ${xhr.statusText}</div>`); 113 152 }); 114 153 } -
ringier-bus/trunk/readme.txt
r3321607 r3412229 3 3 Tags: ringier, bus, api, cde 4 4 Requires at least: 6.0 5 Tested up to: 6. 8.16 Stable tag: 3.4. 05 Tested up to: 6.9 6 Stable tag: 3.4.1 7 7 Requires PHP: 8.1 8 8 License: GPLv2 or later … … 95 95 add_filter('ringier_bus_build_article_payload', 'custom_build_article_payload', 10, 3); 96 96 ``` 97 98 ### 4. Controlling Author Event Dispatch ### 99 100 You can control whether the Ringier Bus plugin should dispatch Author events for a specific user by using the **ringier_bus_should_dispatch_author_event** filter. 101 This filter allows you to override the default logic to force enablement or disablement based on your own custom logic - when you want full control over which authors get sent to the Event Bus. 102 103 Example: 104 ```php 105 /** 106 * Example: Prevent event dispatch for a specific user ID. 107 */ 108 add_filter('ringier_bus_should_dispatch_author_event', function (bool $should_dispatch, int $user_id): bool { 109 110 // Example: Always send events for Administrators, ignoring the "Show Profile" checkbox 111 if (user_can($user_id, 'administrator')) { 112 return true; 113 } 114 115 // Example condition: never sync user ID 1234 116 if ($user_id === 1234) { 117 return false; 118 } 119 120 // Otherwise, use the default logic 121 return $should_dispatch; 122 }, 10, 2); 123 ``` 124 125 This filter gives you full flexibility to: 126 - Disable syncing for certain authors 127 - Force syncing regardless of profile visibility 128 - Apply environment-specific rules (e.g., staging vs production) 129 - Implement client-specific dispatch policies 97 130 98 131 ## Contributing ## -
ringier-bus/trunk/ringier-bus.php
r3321163 r3412229 11 11 * Plugin URI: https://github.com/RingierIMU/mkt-plugin-wordpress-bus 12 12 * Description: A plugin to push events to Ringier CDE via the BUS API whenever an article is created, updated or deleted 13 * Version: 3.4. 013 * Version: 3.4.1 14 14 * Requires at least: 6.0 15 15 * Author: Ringier SA, Wasseem Khayrattee … … 50 50 */ 51 51 define('RINGIER_BUS_DS', DIRECTORY_SEPARATOR); 52 define('RINGIER_BUS_PLUGIN_VERSION', '3.4. 0');52 define('RINGIER_BUS_PLUGIN_VERSION', '3.4.1'); 53 53 define('RINGIER_BUS_PLUGIN_MINIMUM_WP_VERSION', '6.0'); 54 54 define('RINGIER_BUS_PLUGIN_DIR_URL', plugin_dir_url(__FILE__)); //has trailing slash at end -
ringier-bus/trunk/src/Core/AdminSyncPage.php
r3316910 r3412229 98 98 $perPage = 1; 99 99 100 // Fetch users in raw batches — we'll filter later101 100 $users = get_users([ 101 'role__in' => Enum::AUTHOR_ROLE_LIST, // Only get specific roles 102 102 'number' => $perPage, 103 103 'offset' => $offset, … … 105 105 ]); 106 106 107 // If no users found, we are done 107 108 if (empty($users)) { 108 109 wp_send_json_success(['message' => 'All authors have been synced.', 'done' => true]); … … 110 111 111 112 $user = $users[0]; 112 $roles = (array) $user->roles;113 113 $user_id = $user->ID; 114 114 115 // Check if user has at least one allowed role116 $allowedRoles = Enum::AUTHOR_ROLE_LIST;117 $intersects = array_intersect($roles, $allowedRoles);118 119 if (empty($intersects)) {120 wp_send_json_success([121 'message' => "Skipping User ID {$user_id} ({$user->user_login}) — no allowed role.",122 'done' => false,123 'skipped' => true, // signal the JS to style it differently124 ]);125 }126 127 115 try { 128 BusHelper::dispatchAuthorEvent(116 $was_dispatched = BusHelper::dispatchAuthorEvent( 129 117 $user_id, 130 118 (array) $user->data, … … 132 120 ); 133 121 134 wp_send_json_success([ 135 'message' => "Synced Author (ID {$user_id}) - {$user->user_login}", 136 'done' => false, 137 ]); 122 if ($was_dispatched) { 123 wp_send_json_success([ 124 'message' => "Synced Author (ID {$user_id}) - {$user->user_login}", 125 'done' => false, 126 'skipped' => false, 127 ]); 128 } else { 129 wp_send_json_success([ 130 'message' => "Skipped User ID {$user_id} - Profile Disabled or no matching role.", 131 'done' => false, 132 'skipped' => true, 133 ]); 134 } 135 138 136 } catch (\Throwable $e) { 139 137 wp_send_json_error([ … … 146 144 public static function handleCategoriesSync(): void 147 145 { 146 // Use global $wpdb for a precise, lightweight query 147 global $wpdb; 148 148 149 $last_id = isset($_POST['last_id']) ? (int) $_POST['last_id'] : 0; 149 150 150 $all_terms = get_terms([ 151 'taxonomy' => 'category', 152 'hide_empty' => false, 153 'orderby' => 'term_id', 154 'order' => 'ASC', 155 'fields' => 'all', 156 ]); 157 158 $next_term = null; 159 foreach ($all_terms as $term) { 160 if ($term->term_id > $last_id) { 161 $next_term = $term; 162 break; 163 } 164 } 165 166 if (!$next_term) { 151 // Instead of loading ALL terms, we query the database for exactly ONE ID 152 // that is higher than our current $last_id. 153 $next_term_id = $wpdb->get_var($wpdb->prepare( 154 "SELECT t.term_id 155 FROM {$wpdb->terms} t 156 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id 157 WHERE tt.taxonomy = %s 158 AND t.term_id > %d 159 ORDER BY t.term_id ASC 160 LIMIT 1", 161 'category', // The taxonomy 162 $last_id // The cursor 163 )); 164 165 // If no ID returned, we are done 166 if (!$next_term_id) { 167 167 wp_send_json_success([ 168 168 'message' => 'All categories have been synced.', … … 170 170 ]); 171 171 } 172 173 // Now we fetch the full object for just this ONE term 174 $next_term = get_term($next_term_id, 'category'); 172 175 173 176 try { … … 182 185 'message' => "Synced Category (ID {$next_term->term_id}) – {$next_term->name}", 183 186 'done' => false, 187 // We send back the new ID so the JS knows where to start next time 184 188 'last_id' => $next_term->term_id, 185 189 ]); … … 191 195 public static function handleTagsSync(): void 192 196 { 197 global $wpdb; 198 193 199 $last_id = isset($_POST['last_id']) ? (int) $_POST['last_id'] : 0; 194 200 195 $all_terms = get_terms([ 196 'taxonomy' => 'post_tag', 197 'hide_empty' => false, 198 'orderby' => 'term_id', 199 'order' => 'ASC', 200 'fields' => 'all', 201 ]); 202 203 $next_term = null; 204 foreach ($all_terms as $term) { 205 if ($term->term_id > $last_id) { 206 $next_term = $term; 207 break; 208 } 209 } 210 211 if (!$next_term) { 201 // Query the DB directly for the next available Term ID in the 'post_tag' taxonomy. 202 // This is significantly faster than loading all terms into an array. 203 $next_term_id = $wpdb->get_var($wpdb->prepare( 204 "SELECT t.term_id 205 FROM {$wpdb->terms} t 206 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id 207 WHERE tt.taxonomy = %s 208 AND t.term_id > %d 209 ORDER BY t.term_id ASC 210 LIMIT 1", 211 'post_tag', // taxo 212 $last_id 213 )); 214 215 // If no ID is returned, we have reached the end. 216 if (!$next_term_id) { 212 217 wp_send_json_success([ 213 218 'message' => 'All tags have been synced.', … … 215 220 ]); 216 221 } 222 223 // Fetch the full object for this specific tag 224 $next_term = get_term($next_term_id, 'post_tag'); 217 225 218 226 try { -
ringier-bus/trunk/src/Core/Bus/AuthorEvent.php
r3316910 r3412229 93 93 private function buildMainRequestBody(array $author_data): array 94 94 { 95 $author_ID = $author_data['id'];96 97 95 return [[ 98 96 'events' => [ … … 100 98 ], 101 99 'from' => $this->authClient->getVentureId(), 102 'reference' => "$author_ID",100 'reference' => wp_generate_uuid4(), 103 101 'created_at' => date('Y-m-d\TH:i:s.vP'), //NOTE: \DateTime::RFC3339_EXTENDED has been deprecated 104 102 'version' => Enum::BUS_API_VERSION, … … 117 115 118 116 return [ 119 'reference' => $author_data['reference'],120 'url' => $author_data['url'],121 'name' => $author_data['name'],122 'writer_type' => $author_data['writer_type'],123 'status' => $author_page_status,124 'created_at' => $author_data['created_at'],125 'updated_at' => $author_data['updated_at'],117 'reference' => (string) $author_data['reference'], 118 'url' => (string) $author_data['url'], 119 'name' => (string) $author_data['name'], 120 'writer_type' => (string) $author_data['writer_type'], 121 'status' => (string) $author_page_status, 122 'created_at' => Utils::formatDate($author_data['created_at']), 123 'updated_at' => Utils::formatDate($author_data['updated_at']), 126 124 'image' => $author_data['image'], 127 125 ]; -
ringier-bus/trunk/src/Core/Bus/BusHelper.php
r3316910 r3412229 162 162 } 163 163 164 // Ensure created_at exists - for older terms created before this plugin was installed 165 $created_at = get_term_meta($term_id, Enum::DB_CREATED_AT, true); 166 if (empty($created_at)) { 167 update_term_meta($term_id, Enum::DB_CREATED_AT, current_time('mysql')); 168 } 169 164 170 update_term_meta($term_id, Enum::DB_UPDATED_AT, current_time('mysql')); 165 171 … … 352 358 ]; 353 359 self::dispatchAuthorEvent($user_id, $userdata, Enum::EVENT_AUTHOR_DELETED); 360 } 361 362 /** 363 * Determine whether the BUS plugin should dispatch an author-related event 364 * for a given user. This method implements layered logic: 365 * 366 * 1. If the Ringier Author Addon is NOT active: 367 * - Always dispatch events (backwards-compatible behaviour). 368 * 369 * 2. If the Ringier Author Addon IS active: 370 * - Only dispatch the event when the user's profile meta field 371 * `ringier_show_author_profile_page` is set to "on". 372 * (The addon stores only "on" or "off".) 373 * 374 * 3. After internal evaluation, the decision is passed through the 375 * 'ringier_bus_should_dispatch_author_event' filter, allowing other 376 * plugins/themes or clients to override or extend the logic. 377 * 378 * @param int $user_id The WordPress user ID being evaluated. 379 * 380 * @return bool True if the BUS should dispatch the author event, 381 * false otherwise. 382 */ 383 public static function shouldDispatchAuthorEvent(int $user_id): bool 384 { 385 // Default behaviour if addon is not active 386 $should_dispatch = true; 387 388 // If Ringier Author Addon is active, respect its "show profile" checkbox 389 if (defined('RINGIER_AUTHOR_ADDON_PLUGIN_VERSION')) { 390 $raw_value = get_user_meta($user_id, Enum::META_SHOW_PROFILE_PAGE_KEY, true); 391 $normalized = mb_strtolower((string) $raw_value); 392 393 // Ringier Author stores ONLY 'on' or 'off' 394 $should_dispatch = ($normalized === Enum::STATUS_ON); 395 } 396 397 /** 398 * Filter whether the Ringier BUS plugin should dispatch an author event 399 * for a specific user. 400 * 401 * This enables full extensibility: other plugins/themes or clients may override 402 * this behaviour globally or conditionally. 403 * 404 * @param bool $should_dispatch The computed base decision. 405 * @param int $user_id The user ID being evaluated. 406 */ 407 return (bool) apply_filters( 408 'ringier_bus_should_dispatch_author_event', 409 $should_dispatch, 410 $user_id 411 ); 354 412 } 355 413 … … 770 828 * @param array $userdata 771 829 * @param string $event_type 772 */ 773 public static function dispatchAuthorEvent(int $user_id, array $userdata, string $event_type): void 774 { 830 * 831 * @return bool 832 */ 833 public static function dispatchAuthorEvent(int $user_id, array $userdata, string $event_type): bool 834 { 835 // If the gatekeeper says "No", we stop immediately. 836 if (!self::shouldDispatchAuthorEvent($user_id)) { 837 // ringier_errorlogthis("Skipped event {$event_type} for user {$user_id} due to privacy settings."); 838 return false; 839 } 840 775 841 $author_data = Utils::buildAuthorInfo($user_id, $userdata); 776 842 … … 780 846 Utils::pushToSlack($event_type . ': endpointUrl is empty', Enum::LOG_ERROR); 781 847 782 return ;848 return false; 783 849 } 784 850 … … 796 862 Utils::pushToSlack("[{$event_type}] Failed to acquire BUS token", Enum::LOG_ERROR); 797 863 798 return ;864 return false; 799 865 } 800 866 … … 802 868 $authorEvent->setEventType($event_type); 803 869 $authorEvent->sendToBus($author_data); 870 871 return true; 804 872 } 805 873 } -
ringier-bus/trunk/src/Core/Bus/TermEvent.php
r3316910 r3412229 95 95 private function buildMainRequestBody(array $topic_data): array 96 96 { 97 $topic_id = $topic_data['id'];98 99 97 return [[ 100 98 'events' => [ … … 102 100 ], 103 101 'from' => $this->authClient->getVentureId(), 104 'reference' => "$topic_id",102 'reference' => wp_generate_uuid4(), 105 103 'created_at' => date('Y-m-d\TH:i:s.vP'), //NOTE: \DateTime::RFC3339_EXTENDED has been deprecated 106 104 'version' => Enum::BUS_API_VERSION, … … 113 111 private function buildTopicPayloadData(array $topic_data): array 114 112 { 113 $date_created = Utils::formatDate($topic_data['created_at']); 114 if (empty($date_created)) { 115 $date_created = Utils::formatDate($topic_data['updated_at']); 116 } 117 115 118 return [ 116 'reference' => $topic_data['id'],117 'status' => $topic_data['status'],118 'created_at' => Utils::formatDate($topic_data['created_at']),119 'reference' => (string) $topic_data['id'], 120 'status' => (string) $topic_data['status'], 121 'created_at' => $date_created, 119 122 'updated_at' => Utils::formatDate($topic_data['updated_at']), 120 123 'url' => [ 121 'culture' => ringier_getLocale(), 122 'value' => $topic_data['url'], 124 [ 125 'culture' => (string) ringier_getLocale(), 126 'value' => (string) $topic_data['url'], 127 ], 123 128 ], 124 129 'title' => [ 125 'culture' => ringier_getLocale(), 126 'value' => $topic_data['title'], 130 [ 131 'culture' => (string) ringier_getLocale(), 132 'value' => (string) $topic_data['title'], 133 ], 127 134 ], 128 135 'slug' => [ 129 'culture' => ringier_getLocale(), 130 'value' => $topic_data['slug'], 136 [ 137 'culture' => (string) ringier_getLocale(), 138 'value' => (string) $topic_data['slug'], 139 ], 131 140 ], 132 'page_type' => $topic_data['page_type'],141 'page_type' => (string) $topic_data['page_type'], 133 142 ]; 134 143 } -
ringier-bus/trunk/src/Core/Enum.php
r3316910 r3412229 87 87 const EVENT_TOPIC_DELETED = 'TopicDeleted'; 88 88 const META_SHOW_PROFILE_PAGE_KEY = 'ringier_show_author_profile_page'; 89 const STATUS_OFF = 'off'; 90 const STATUS_ON = 'on'; 89 91 const META_HIGH_RES_IMAGE_URL = 'ringier_high_res_image_url'; 90 92 -
ringier-bus/trunk/src/Core/Utils.php
r3321163 r3412229 9 9 10 10 use DateInterval; 11 use RingierBusPlugin\Bus\BusHelper; 11 12 12 13 class Utils … … 665 666 * This applies only to Ringier's inhouse ventures who uses our AuthorAddon plugin 666 667 */ 667 $show_profile_page = get_user_meta($user_id, Enum::META_SHOW_PROFILE_PAGE_KEY, true);668 668 $author_page_status = Enum::JSON_FIELD_STATUS_ONLINE; 669 if ( empty($show_profile_page) || strcmp($show_profile_page, 'off') === 0) {669 if (!BusHelper::shouldDispatchAuthorEvent($user_id)) { 670 670 $author_page_status = Enum::JSON_FIELD_STATUS_OFFLINE; 671 671 }
Note: See TracChangeset
for help on using the changeset viewer.