Managing Requests & Converting to Orders
After posting a buyer request, you’ll receive vendor proposals. This guide covers evaluating proposals, communicating with vendors, accepting offers, and converting proposals into orders.
Request Statuses
WP Sell Services uses 5 request statuses:
| Status | Description |
|---|---|
open | Active, accepting proposals |
in_review | Evaluating proposals, may still accept new ones |
hired | Accepted a proposal, order created |
expired | Past expiration date, no longer active |
cancelled | Buyer cancelled the request |
My Requests Dashboard
Your central hub for managing all buyer requests.

Accessing the Dashboard
- Log in to your account
- Navigate to Dashboard → My Requests
- View all requests and their status
Request Card Information
Each request displays:
- Title – Project name
- Status – Current stage
- Posted Date – When published
- Proposal Count – Number received (from
getproposalcount()) - Budget – Your specified amount or range
- Delivery Days – Target completion timeframe
- Expiration – When request expires
- Category – Service category assigned

Request Metadata
Requests are WordPress custom posts (wpss_request) with meta fields:
| Meta Key | Type | Description |
|---|---|---|
wpssstatus | string | Request status |
wpssbudget_type | string | ‘fixed’ or ‘range’ |
wpssbudget_min | float | Minimum budget |
wpssbudget_max | float | Maximum budget (range only) |
wpssdelivery_days | int | Expected delivery timeframe |
wpssattachments | array | Attachment IDs |
wpssskills_required | array | Required skill tags |
wpssexpires_at | datetime | Expiration timestamp |
wpsshiredvendorid | int | Vendor ID (when hired) |
wpssacceptedproposalid | int | Proposal ID (when hired) |
Managing Request Status
Updating Status
Only certain status transitions are allowed:
// Valid statuses
BuyerRequestService::STATUS_OPEN
BuyerRequestService::STATUS_IN_REVIEW
BuyerRequestService::STATUS_HIRED
BuyerRequestService::STATUS_EXPIRED
BuyerRequestService::STATUS_CANCELLED
Marking as Hired
When you accept a proposal:
$buyer_request_service->mark_hired(
$request_id,
$vendor_id,
$proposal_id
);
This automatically:
- Updates status to ‘hired’
- Stores vendor ID
- Stores accepted proposal ID
Viewing Proposals
Proposal Count
Get total proposals submitted:
$count = $buyer_request_service->get_proposal_count( $request_id );
Queries the wpss_proposals table.
Proposal Service
Proposals are managed by ProposalService, not BuyerRequestService.
To get proposals:
$proposal_service = new ProposalService();
$proposals = $proposal_service->get_by_request( $request_id );
Converting to Order
Acceptance Process
When you accept a proposal, the system creates a service order.
Method: converttoorder()
$result = $buyer_request_service->convert_to_order(
$request_id,
$proposal_id
);
What Happens Automatically
- Validation:
- Order Creation:
- Proposal Updates:
- Request Updates:
- Order Requirements:
- Conversation:
- Notification:
Return Value
Success:
[
'success' => true,
'message' => 'Order created successfully. Proceed to payment.',
'order_id' => 123,
'order_number' => 'WPSS-ABC12345',
]
With warnings:
[
'success' => true,
'order_id' => 123,
'order_number' => 'WPSS-ABC12345',
'warnings' => [
'Order requirements could not be saved.'
]
]
Failure:
[
'success' => false,
'message' => 'Error description'
]
Request Queries
Get Open Requests
$requests = $buyer_request_service->get_open( [
'posts_per_page' => 20,
'paged' => 1,
'category_id' => 0,
'budget_min' => 0,
'budget_max' => 0,
'order_by' => 'date',
'order' => 'DESC',
] );
Returns requests with:
- Status = ‘open’
- Not expired (expires_at > now OR no expiration)
Get User’s Requests
$requests = $buyer_request_service->get_by_buyer( $user_id, [
'posts_per_page' => 20,
'paged' => 1,
'status' => '', // Optional status filter
] );
Returns all requests where post_author = user ID.
Search Requests
$requests = $buyer_request_service->search( 'WordPress plugin', [
'posts_per_page' => 20,
'paged' => 1,
'status' => 'open',
] );
Searches post title and content.
Request Expiration
Default Expiration
When creating a request without expiration:
$default_days = get_option( 'wpss_request_expiry_days', 30 );
$expires_at = current_time('mysql') + $default_days days;
Default: 30 days from posting.
Expiring Old Requests
Background job runs expireoldrequests():
$expired_count = $buyer_request_service->expire_old_requests();
Finds requests with:
- Status = ‘open’
expires_at< current time
Updates status to ‘expired’.
Extending Expiration
Not implemented in base service. You must manually update:
$new_expiry = gmdate( 'Y-m-d H:i:s', strtotime( '+14 days' ) );
update_post_meta( $request_id, '_wpss_expires_at', $new_expiry );
Budget Types
Two budget types supported:
Fixed Budget
Single price amount:
[
'budget_type' => BuyerRequestService::BUDGET_FIXED,
'budget_min' => 500.00,
'budget_max' => 0, // Not used
]
Range Budget
Flexible price range:
[
'budget_type' => BuyerRequestService::BUDGET_RANGE,
'budget_min' => 400.00,
'budget_max' => 600.00,
]
Filtering Requests
By Category
Requests are assigned to service categories using WordPress taxonomy:
wp_set_object_terms(
$request_id,
[ $category_id ],
'wpss_service_category'
);
Filter by category in queries:
$requests = $buyer_request_service->get_open( [
'category_id' => 5,
] );
By Budget Range
Filter requests within budget range:
$requests = $buyer_request_service->get_open( [
'budget_min' => 500, // Requests with budget_min >= 500
'budget_max' => 1000, // Requests with budget_max <= 1000
] );
Request Attachments
Storing Attachments
Attachments are WordPress media library attachments:
[
'attachments' => [ 123, 456, 789 ], // Attachment IDs
]
Stored in wpssattachments meta as serialized array.
Accessing Attachments
$request = $buyer_request_service->get( $request_id );
$attachment_ids = $request->attachments; // Array of IDs
foreach ( $attachment_ids as $attachment_id ) {
$url = wp_get_attachment_url( $attachment_id );
$title = get_the_title( $attachment_id );
}
Skills Required
Optional skill tags for requests:
[
'skills_required' => [
'WordPress',
'React',
'PHP 8',
'REST API',
]
]
Stored in wpssskills_required meta.
Vendors can filter by matching skills.
Request Object Structure
When calling get(), you receive:
{
"id": 123,
"title": "Build WordPress Plugin",
"description": "Need custom plugin for...",
"author_id": 456,
"status": "open",
"budget_type": "range",
"budget_min": 500.00,
"budget_max": 800.00,
"delivery_days": 14,
"attachments": [789, 790],
"skills_required": ["WordPress", "PHP"],
"expires_at": "2026-03-15 10:30:00",
"created_at": "2026-02-12 10:30:00",
"proposal_count": 7,
"category": {
"term_id": 5,
"name": "Web Development",
"slug": "web-development"
}
}
WordPress Hooks
Action: wpssbuyerrequest_created
Fires when request is posted:
add_action( 'wpss_buyer_request_created', function( $post_id, $data ) {
// Notify matching vendors
// Log new request
}, 10, 2 );
Action: wpssbuyerrequest_updated
Fires when request is edited:
add_action( 'wpss_buyer_request_updated', function( $request_id, $data ) {
// Notify vendors of changes
}, 10, 2 );
Action: wpssbuyerrequeststatuschanged
Fires on status updates:
add_action( 'wpss_buyer_request_status_changed', function( $request_id, $status, $old_status ) {
// Track status changes
}, 10, 3 );
Action: wpssrequestconvertedtoorder
Fires when proposal accepted:
add_action( 'wpss_request_converted_to_order', function( $order_id, $request_id, $proposal_id, $request, $proposal ) {
// Handle order creation
// Send notifications
// Update stats
}, 10, 5 );
Filter: wpssproposalorder_revisions
Filter revision count for converted orders:
add_filter( 'wpss_proposal_order_revisions', function( $revisions, $proposal, $request ) {
// Default is 2
// Increase based on order value
if ( $proposal->proposed_price > 1000 ) {
return 5;
}
return $revisions;
}, 10, 3 );
Best Practices
Request Description
Write clear, detailed descriptions:
Good:
I need a WordPress plugin that integrates with Stripe to process recurring subscriptions.
Requirements:
- Admin panel to manage subscriptions
- Customer portal for self-service
- Email notifications for renewal
- Support for annual and monthly plans
- Compatible with WordPress 6.0+
Deliverables:
- Fully functional plugin
- Source code
- Installation documentation
Poor:
Need Stripe integration ASAP.
Budget Setting
Set realistic budgets:
Research First:
- Check similar services on marketplace
- Ask vendors for rough estimates
- Consider project complexity
Budget Range Benefits:
- Attracts more proposals
- Shows flexibility
- Vendors can justify pricing
Proposal Evaluation
Compare proposals on:
- Vendor Experience – Portfolio and reviews
- Proposal Quality – Understanding of requirements
- Price – Value for money, not just cheapest
- Timeline – Realistic delivery estimate
- Communication – Responsiveness and clarity
After Acceptance
- Pay Promptly – Don’t delay payment
- Provide Requirements – Give vendor everything needed
- Stay Available – Answer questions quickly
- Be Reasonable – Don’t change scope mid-project
Troubleshooting
Request Not Visible
Check:
- Request status is ‘open’
- Not expired (expires_at in future)
- Category assigned
- Post status is ‘publish’
Can’t Accept Proposal
Verify:
- Request is ‘open’ or ‘in_review’
- Proposal status is ‘pending’
- Proposal belongs to this request
- You are the request author
Order Creation Failed
Common Issues:
- Database insert failed (check permissions)
- Proposal already accepted
- Request already hired
- Invalid vendor or service ID
Check: Return value ‘message’ field for specific error.
Related Documentation
- Posting a Request – Creating buyer requests
- Proposal System – How proposals work
- Order Lifecycle – After order creation
- Payments & Checkout – Completing payment
Key Points:
- 5 request statuses, most common flow: open → in_review → hired
- Proposals live in separate
wpss_proposalstable - Converting proposal to order is automatic and comprehensive
- Expiration handled by background cron job
- All metadata stored in post meta with
wpssprefix
