Skip to content

Show contributors for docs and articles in free version#210

Open
haideralibd wants to merge 9 commits into
weDevsOfficial:developfrom
welabs-ltd:feat/improve-pro-prompts
Open

Show contributors for docs and articles in free version#210
haideralibd wants to merge 9 commits into
weDevsOfficial:developfrom
welabs-ltd:feat/improve-pro-prompts

Conversation

@haideralibd

@haideralibd haideralibd commented Apr 11, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added display of contributor avatars for documentation articles and parent documentation posts.
    • Introduced a new API endpoint to fetch contributors for specific documentation.
  • Enhancements
    • Contributor information is now automatically tracked and updated when documentation is edited or saved.
    • Parent documentation pages aggregate contributor data from their child articles.
  • Bug Fixes
    • Improved handling of contributor metadata to ensure accuracy and prevent duplication.
  • Other
    • Updated plugin version to 2.1.12.

@haideralibd haideralibd self-assigned this Apr 11, 2025
@coderabbitai

coderabbitai Bot commented Apr 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This update introduces contributor management for documentation posts, including new backend classes, REST API endpoints, and frontend components to display contributor avatars. It adds logic to aggregate and store contributor data, updates plugin metadata, and refines UI elements to show contributor information and track upgrade button clicks.

Changes

Files / Grouped Paths Change Summary
includes/API/API.php Added a REST API route to fetch contributors for a documentation post by ID, and a corresponding public method to retrieve contributor IDs from post meta.
includes/Hooks.php Introduced a Hooks class to manage and synchronize contributor metadata on documentation save events, handling both parent and section posts.
includes/WedocsContributor.php Added a WedocsContributor class with methods to initialize and update contributor data for articles and documentation posts, ensuring contributors are set once.
includes/functions.php Introduced three functions for updating, retrieving, and aggregating documentation contributors and children, supporting the new contributor management system.
package.json, readme.txt, wedocs.php Updated plugin version to 2.1.12; imported new classes; added a method to check and initialize contributors on plugin load; registered new hooks.
src/components/Documentations/ContributorUsers.js Added a new React component to fetch and display up to four contributor avatars for a documentation post, with tooltips and a badge for additional contributors.
src/components/ProPreviews/index.js Switched to the new ContributorUsers component for displaying contributors; updated hook filters to pass post IDs; fixed block structure.
src/components/ProPreviews/common/UpgradeButton.js Updated the upgrade button URL to include UTM parameters for tracking.

Suggested labels

QA Approved, Ready To Merge

Suggested reviewers

  • iftakharul-islam

Poem

🐇
Hopping through docs, I see
Contributors now, as clear as can be!
Avatars twinkle, updates anew,
Version bumps and APIs too.
With every save, our credits grow—
In the garden of docs, let contributors show!
🌱✨

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@haideralibd haideralibd marked this pull request as ready for review May 20, 2025 09:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (10)
src/components/Documentations/ContributorUsers.js (2)

45-65: Simplify conditional rendering with optional chaining.

The code can be simplified by using optional chaining more effectively.

-        { userAvatars &&
-            userAvatars?.map( ( avatar, index ) =>
+        { userAvatars?.map( ( avatar, index ) =>
                 index < 4 ? (
                     <div
                         key={ index }
                         className="tooltip cursor-pointer"
                         data-tip={ __(
                             avatar?.name,
                             'wedocs-pro'
                         ) }
                     >
                         <img
                             src={ avatar?.url }
                             alt={ avatar?.name }
                             className="relative z-0 inline-block h-full w-7 rounded-full ring-2 ring-white"
                         />
                     </div>
                 ) : (
                     ''
                 )
             ) }
🧰 Tools
🪛 Biome (1.9.4)

[error] 45-65: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


67-73: Simplify additional contributors display with optional chaining.

Similar to the above comment, this can be simplified with better optional chaining.

-        { userAvatars && userAvatars?.length > 4 && (
+        { userAvatars?.length > 4 && (
             <div className="relative z-0 inline-block h-full w-7 rounded-full ring-2 ring-white bg-indigo-700 text-white">
                 <span className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 -mt-[1px]">
                     +{ userAvatars?.length - 4 }
                 </span>
             </div>
         ) }
includes/Hooks.php (1)

33-38: Clarify the post type hierarchy check.

The comment says "Check if this is a section post" but the code is actually checking if the post is a third-level document.

-    // Check if this is a section post.
+    // Check if this post is an article (has a section parent)
     $parent_id = wp_get_post_parent_id( $post->post_parent );

     if ( false === $parent_id ) {
         return;
     }
includes/WedocsContributor.php (3)

17-26: Consider using a more reliable method to initialize contributors.

Using an option to track initialization is simple but might cause issues if the option gets accidentally deleted.

 public function check_and_add_docs_contributors() {
     $contributors_added = get_option( 'wedocs_contributors_added', null );
 
-    if ( null === $contributors_added ) {
+    // Check if we need to initialize contributors
+    if ( null === $contributors_added || apply_filters( 'wedocs_force_contributors_init', false ) ) {
         $this->add_article_contributors();
         $this->add_documentation_contributors();
 
         update_option( 'wedocs_contributors_added', true );
     }
 }

35-50: Consider adding pagination for better performance with large datasets.

Retrieving all posts at once without pagination can lead to memory issues with large datasets.

 public function add_article_contributors() {
-    $args = array(
-        'post_type'      => 'docs',
-        'post_status'    => array( 'publish', 'private' ),
-        'posts_per_page' => -1,
-    );
-
-    $documentations = get_posts( $args );
-
-    foreach ( $documentations as $documentation ) {
-        $contributors = get_post_meta( $documentation->ID, 'wedocs_contributors', true );
-        if ( empty( $contributors ) && 0 !== $documentation->post_parent ) {
-            update_post_meta( $documentation->ID, 'wedocs_contributors', array( $documentation->post_author ) );
+    $paged = 1;
+    $batch_size = 100; // Process in batches for better memory management
+    
+    do {
+        $args = array(
+            'post_type'      => 'docs',
+            'post_status'    => array( 'publish', 'private' ),
+            'posts_per_page' => $batch_size,
+            'paged'          => $paged,
+        );
+        
+        $documentations = get_posts( $args );
+        
+        foreach ( $documentations as $documentation ) {
+            $contributors = get_post_meta( $documentation->ID, 'wedocs_contributors', true );
+            if ( empty( $contributors ) && 0 !== $documentation->post_parent ) {
+                update_post_meta( $documentation->ID, 'wedocs_contributors', array( $documentation->post_author ) );
+            }
         }
-    }
+        
+        $paged++;
+    } while ( count( $documentations ) === $batch_size );
 }

59-77: Apply similar pagination improvements for parent documentation processing.

Similar to the article contributors method, this one also retrieves all posts at once which could be optimized.

This method would benefit from the same batch processing approach recommended for the add_article_contributors method to avoid memory issues with large numbers of documents.

includes/functions.php (4)

583-604: Good implementation of contributor tracking

The function effectively updates the documentation's contributor list by identifying new contributors from articles and merging them with existing ones.

Consider adding validation to check if the article ID exists and is of type 'docs'. Also, you might want to handle the case where an article doesn't have a grandparent (when $ancestors is empty):

function wedocs_plugin_update_documentation_contributors( $article_id, $article_contributors ) {
+	if ( empty( $article_id ) || get_post_type( $article_id ) !== 'docs' ) {
+		return;
+	}
	$ancestors               = get_post_ancestors( $article_id );
+	if ( empty( $ancestors ) ) {
+		return;
+	}
	$grand_parent_id         = end( $ancestors );
	// Rest of the function...
}

606-645: Well-structured function with appropriate validation

The function properly validates inputs and handles different child types correctly. The separation of section and article retrieval logic is clean.

The PHPDoc could be more specific about the accepted values for $children_type:

/**
 * Get documentation children ids by using children type.
 *
 * @since 2.1.12
 *
 * @param int    $doc_id        Parent documentation id.
 * @param string $children_type Children type.
+ *                             Accepts 'article' or 'section' only.
 * @param array  $custom_args   Optional. Additional query arguments.
 *
 * @return array Children (article/section) ids array
 */

647-669: Efficiently aggregates contributors across documentation

The function correctly collects unique contributors from all related articles and includes the doc creator.

Consider validating the $doc_id parameter and using array casting more consistently:

function wedocs_plugin_get_documentation_contributors( $doc_id, $article_ids ) {
+	if ( empty( $doc_id ) || get_post_type( $doc_id ) !== 'docs' ) {
+		return array();
+	}
	$contributors = array( $doc_id );
+	$article_ids = (array) $article_ids;
	foreach ( $article_ids as $article_id ) {
		$article_contributors = get_post_meta( $article_id, 'wedocs_contributors', true );
-		foreach ( (array) $article_contributors as $contributor ) {
+		$article_contributors = (array) $article_contributors;
+		foreach ( $article_contributors as $contributor ) {
			if ( ! empty( $contributor ) && ! in_array( $contributor, $contributors ) ) {
				array_push( $contributors, absint( $contributor ) );
			}
		}
	}

	return $contributors;
}

671-671: Remove unnecessary empty line

There's an extra empty line at line 671 that could be removed for consistency.

-

/** Convert UTC Time zone to EST timezone
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45c464 and 89bd255.

📒 Files selected for processing (10)
  • includes/API/API.php (2 hunks)
  • includes/Hooks.php (1 hunks)
  • includes/WedocsContributor.php (1 hunks)
  • includes/functions.php (1 hunks)
  • package.json (1 hunks)
  • readme.txt (1 hunks)
  • src/components/Documentations/ContributorUsers.js (1 hunks)
  • src/components/ProPreviews/common/UpgradeButton.js (1 hunks)
  • src/components/ProPreviews/index.js (2 hunks)
  • wedocs.php (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/components/ProPreviews/index.js (1)
src/components/Documentations/ContributorUsers.js (1)
  • ContributorUsers (5-76)
includes/WedocsContributor.php (2)
wedocs.php (1)
  • WeDocs (58-316)
includes/functions.php (2)
  • wedocs_plugin_get_documentation_children_by_type (616-645)
  • wedocs_plugin_get_documentation_contributors (657-669)
🪛 Biome (1.9.4)
src/components/Documentations/ContributorUsers.js

[error] 45-65: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (13)
readme.txt (1)

8-8: Update Stable Tag for Release

Bumped Stable tag to 2.1.12 to align with the new contributor management features in this release. Please verify that the main plugin file header is also updated to version 2.1.12.

package.json (1)

3-3: Version number correctly updated.

The version bump from 2.1.11 to 2.1.12 is consistent with the feature additions for contributor management in this PR.

src/components/ProPreviews/common/UpgradeButton.js (1)

11-11: Improved upgrade URL with tracking parameters.

The upgrade button URL now includes UTM parameters, which will help track the effectiveness of upgrade prompts from the WordPress dashboard.

wedocs.php (5)

6-6: Version number correctly updated.

The version has been updated to 2.1.12 in both the plugin header and the VERSION constant, maintaining consistency with package.json.

Also applies to: 65-65


43-44: New classes imported for contributor functionality.

The imports for Hooks and WedocsContributor classes support the new contributor management feature.


117-124: New method added for managing contributor data.

The new method correctly initializes the WedocsContributor class and calls its contributor checking method.


185-185: Appropriate hook timing for contributor processing.

Using 'plugins_loaded' as the hook for checking contributors ensures all plugins are loaded before processing begins.


241-241: Hooks class properly initialized.

The Hooks class is correctly instantiated and stored in the plugin container.

src/components/ProPreviews/index.js (3)

4-4: Component import updated to new ContributorUsers component.

The import has been updated to use the new contributor display component from the Documentations directory.


226-226: Fixed syntax error in conditional block.

Proper closing brace added to fix the block structure of the if (!isProLoaded) condition.


228-246: Contributor display hooks modified to work with new component.

The hooks now:

  1. Accept document ID as a parameter
  2. Pass this ID to the ContributorUsers component
  3. Maintain the admin-only access check
  4. Are positioned outside the Pro feature condition, enabling contributor display in the free version

This implementation aligns with the PR objective to show contributors for docs and articles in the free version.

includes/API/API.php (1)

237-243: Clean API endpoint registration for specific document contributors.

The endpoint is properly registered with the correct namespace and path pattern, ensuring it follows the same structure as other endpoints in the file.

includes/Hooks.php (1)

12-14: Properly implemented hook registration.

The hook is registered correctly to capture documentation post saves.

Comment thread includes/API/API.php
Comment on lines 855 to +879
/**
* Check permissions for getting
* Get specific documentation contributors.
*
* @since 2.1.12
*
* @param \WP_REST_Request $request
*
* @return mixed
*/
public function get_specific_documentation_contributors( $request ) {
$id = absint( $request->get_param( 'id' ) );
$key = 'wedocs_contributors';

$contributor_ids = get_post_meta( $id, $key, true );

return rest_ensure_response( $contributor_ids );
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation and proper error handling to the contributor endpoint.

While the implementation is straightforward, it lacks proper validation and error handling.

Consider implementing these improvements:

 public function get_specific_documentation_contributors( $request ) {
     $id  = absint( $request->get_param( 'id' ) );
     $key = 'wedocs_contributors';
+
+    // Check if document exists and is valid
+    $post = get_post( $id );
+    if ( ! $post || 'docs' !== $post->post_type ) {
+        return new WP_Error( 
+            'wedocs_invalid_doc',
+            __( 'Invalid documentation ID.', 'wedocs' ),
+            array( 'status' => 404 )
+        );
+    }

     $contributor_ids = get_post_meta( $id, $key, true );
+    $contributor_ids = ! empty( $contributor_ids ) ? (array) $contributor_ids : array();
     
     return rest_ensure_response( $contributor_ids );
 }
🤖 Prompt for AI Agents
In includes/API/API.php around lines 863 to 879, the
get_specific_documentation_contributors method lacks validation and error
handling for the input and data retrieval. Add validation to ensure the 'id'
parameter is valid and corresponds to an existing post. If the 'id' is invalid
or no contributors are found, return an appropriate error response using
WP_Error with a relevant status code. This will improve robustness and provide
clear feedback to API consumers.

Comment on lines +9 to +19
useEffect( () => {
apiFetch( {
path: '/wp/v2/docs/' + id + '/contributors',
} )
.then( ( result ) => {
setContributors( [ ...contributors, ...result ] );
} )
.catch( ( err ) => {
console.log( err );
} );
}, [ id ] );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix spread logic in the contributors state update.

The current implementation could lead to duplicate contributors if the effect runs multiple times.

 useEffect( () => {
     apiFetch( {
         path: '/wp/v2/docs/' + id + '/contributors',
     } )
         .then( ( result ) => {
-            setContributors( [ ...contributors, ...result ] );
+            setContributors( result || [] );
         } )
         .catch( ( err ) => {
             console.log( err );
         } );
 }, [ id ] );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect( () => {
apiFetch( {
path: '/wp/v2/docs/' + id + '/contributors',
} )
.then( ( result ) => {
setContributors( [ ...contributors, ...result ] );
} )
.catch( ( err ) => {
console.log( err );
} );
}, [ id ] );
useEffect( () => {
apiFetch( {
path: '/wp/v2/docs/' + id + '/contributors',
} )
.then( ( result ) => {
setContributors( result || [] );
} )
.catch( ( err ) => {
console.log( err );
} );
}, [ id ] );
🤖 Prompt for AI Agents
In src/components/Documentations/ContributorUsers.js between lines 9 and 19, the
useEffect hook updates the contributors state by spreading the existing
contributors and the new result, which can cause duplicates if the effect runs
multiple times. To fix this, update the state by merging the existing
contributors and new results while removing duplicates, for example by using a
Set or filtering logic, ensuring each contributor appears only once in the
state.

Comment on lines +21 to +41
useEffect( () => {
contributors?.map( ( contributorId ) => {
apiFetch( {
path: '/wp/v2/users/' + contributorId,
} )
.then( ( result ) => {
const userName = result?.name,
avatarUrl = result?.avatar_urls?.[ '24' ];

userAvatars.push( {
name: userName,
url: avatarUrl,
} );

setUserAvatars( [ ...userAvatars ] );
} )
.catch( ( err ) => {
console.log( err );
} );
} );
}, [ contributors ] );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve user data fetching logic to avoid state mutation issues.

The current implementation has several issues:

  1. Directly mutates state with push()
  2. Uses map() without returning anything
  3. Could trigger multiple unnecessary re-renders
 useEffect( () => {
-    contributors?.map( ( contributorId ) => {
+    if (!contributors || !contributors.length) return;
+    
+    const fetchUserData = async () => {
+      try {
+        const avatarData = await Promise.all(contributors.map(async (contributorId) => {
+          const result = await apiFetch({ path: '/wp/v2/users/' + contributorId });
+          return {
+            name: result?.name,
+            url: result?.avatar_urls?.['24']
+          };
+        }));
+        setUserAvatars(avatarData);
+      } catch (err) {
+        console.error('Error fetching user data:', err);
+      }
+    };
+    
+    fetchUserData();
-        apiFetch( {
-            path: '/wp/v2/users/' + contributorId,
-        } )
-            .then( ( result ) => {
-                const userName = result?.name,
-                    avatarUrl = result?.avatar_urls?.[ '24' ];
-
-                userAvatars.push( {
-                    name: userName,
-                    url: avatarUrl,
-                } );
-
-                setUserAvatars( [ ...userAvatars ] );
-            } )
-            .catch( ( err ) => {
-                console.log( err );
-            } );
-    } );
 }, [ contributors ] );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect( () => {
contributors?.map( ( contributorId ) => {
apiFetch( {
path: '/wp/v2/users/' + contributorId,
} )
.then( ( result ) => {
const userName = result?.name,
avatarUrl = result?.avatar_urls?.[ '24' ];
userAvatars.push( {
name: userName,
url: avatarUrl,
} );
setUserAvatars( [ ...userAvatars ] );
} )
.catch( ( err ) => {
console.log( err );
} );
} );
}, [ contributors ] );
useEffect( () => {
if ( !contributors || !contributors.length ) {
return;
}
const fetchUserData = async () => {
try {
const avatarData = await Promise.all(
contributors.map( async ( contributorId ) => {
const result = await apiFetch( {
path: '/wp/v2/users/' + contributorId,
} );
return {
name: result?.name,
url: result?.avatar_urls?.[ '24' ],
};
} )
);
setUserAvatars( avatarData );
} catch ( err ) {
console.error( 'Error fetching user data:', err );
}
};
fetchUserData();
}, [ contributors ] );
🤖 Prompt for AI Agents
In src/components/Documentations/ContributorUsers.js around lines 21 to 41, the
useEffect hook directly mutates the userAvatars state array using push(), uses
map() without returning values, and causes multiple re-renders by calling
setUserAvatars inside each fetch. To fix this, avoid mutating state directly by
creating a new array, use Promise.all to fetch all user data concurrently,
collect the results into a new array, and then update the state once with the
complete array to minimize re-renders.

Comment thread includes/Hooks.php
Comment on lines +26 to +51
public function save_documentation_contributors( $post_id, $post ) {
// Check if this is a parent post.
if ( 0 === $post->post_parent ) {
$this->save_parent_contributors( $post );
return;
}

// Check if this is a section post.
$parent_id = wp_get_post_parent_id( $post->post_parent );

if ( false === $parent_id ) {
return;
}

$user_id = get_current_user_id();
$contributors = get_post_meta( $post_id, 'wedocs_contributors', true );
$contributors = ! empty( $contributors ) ? $contributors : array();

if ( ! in_array( $user_id, $contributors ) ) {
array_push( $contributors, $user_id );
}

// Save the doc contributors meta.
update_post_meta( $post_id, 'wedocs_contributors', (array) $contributors );
wedocs_plugin_update_documentation_contributors( $post_id, $contributors );
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add proper nonce verification and capability checks.

The current implementation doesn't verify if the post save is legitimate and doesn't check if the user has proper capabilities.

 public function save_documentation_contributors( $post_id, $post ) {
+    // Don't save on autosave
+    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
+        return;
+    }
+
+    // Check if user has permission to edit this post
+    if ( ! current_user_can( 'edit_post', $post_id ) ) {
+        return;
+    }
+
     // Check if this is a parent post.
     if ( 0 === $post->post_parent ) {
         $this->save_parent_contributors( $post );
         return;
     }

     // Check if this is a section post.
     $parent_id = wp_get_post_parent_id( $post->post_parent );

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In includes/Hooks.php around lines 26 to 51, the save_documentation_contributors
function lacks nonce verification and user capability checks, which are
necessary to ensure the post save action is legitimate and authorized. Add a
nonce verification step to validate the request's authenticity and include a
capability check to confirm the current user has permission to edit the post
before proceeding with saving contributors. This will secure the function
against unauthorized or malicious requests.

Comment thread includes/Hooks.php
Comment on lines +62 to +67
public function save_parent_contributors( $post ) {
$article_ids = wedocs_plugin_get_documentation_children_by_type( $post->ID );
$contributors = wedocs_plugin_get_documentation_contributors( $post->post_author, $article_ids );

update_post_meta( $post->ID, 'wedocs_contributors', (array) $contributors );
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure contributors data is properly handled.

The current implementation assumes the helper functions will return valid data without any error checking.

 public function save_parent_contributors( $post ) {
     $article_ids  = wedocs_plugin_get_documentation_children_by_type( $post->ID );
     $contributors = wedocs_plugin_get_documentation_contributors( $post->post_author, $article_ids );
 
+    // Ensure we have valid contributor data
+    $contributors = is_array( $contributors ) ? $contributors : array( $post->post_author );
     update_post_meta( $post->ID, 'wedocs_contributors', (array) $contributors );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function save_parent_contributors( $post ) {
$article_ids = wedocs_plugin_get_documentation_children_by_type( $post->ID );
$contributors = wedocs_plugin_get_documentation_contributors( $post->post_author, $article_ids );
update_post_meta( $post->ID, 'wedocs_contributors', (array) $contributors );
}
public function save_parent_contributors( $post ) {
$article_ids = wedocs_plugin_get_documentation_children_by_type( $post->ID );
$contributors = wedocs_plugin_get_documentation_contributors( $post->post_author, $article_ids );
// Ensure we have valid contributor data
$contributors = is_array( $contributors ) ? $contributors : array( $post->post_author );
update_post_meta( $post->ID, 'wedocs_contributors', (array) $contributors );
}
🤖 Prompt for AI Agents
In includes/Hooks.php around lines 62 to 67, the save_parent_contributors method
lacks error handling for the helper functions
wedocs_plugin_get_documentation_children_by_type and
wedocs_plugin_get_documentation_contributors. Add checks to verify that these
functions return valid, non-empty data before proceeding. If either returns
null, false, or an unexpected value, handle it gracefully by setting
contributors to an empty array or logging an error, ensuring update_post_meta is
called with valid data only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants