Build a Department Service Finder
Build a searchable WordPress service directory with a reusable plugin.
Introduction
30 Second Summary
People often know what help they need without knowing which department handles it. Long service lists make the answer harder to find.
In this project, you will build a searchable Department Service Finder inside a real WordPress page. Visitors can narrow services from four departments by keyword or department without reloading the page.
What You'll Build
You'll demo a polished service page where a search for website leaves only Marketing's Website update request card visible.
By the end of this project, you'll have:
- A reusable service directory that filters four departments by keyword or department.
- An SEO-friendly page at /department-services/ that stays readable on narrow screens.
- A public portfolio demo that anyone can launch through GitHub and WordPress Playground.
- Secret Mission: Accessible live feedback that announces the match count. It also explains when no services match.
Are there any prerequisites?
No prior plugin development experience is required. Step 1 guides you through each free setup task.
Before We Start
Before any hands-on work begins, lock in the purpose of your project. Your one-sentence goal will connect the Department Service Finder to the skills you want to demonstrate.
Set Up the Portfolio Workspace
Your service finder needs a free workspace you can recreate whenever you want. Preparing it now keeps setup from interrupting the first working plugin in the next step.
You will prepare a public home on GitHub. WordPress Playground gives the plugin a browser-based test site.
In this step, get ready to:
- Confirm that Visual Studio Code, Windows PowerShell, and Microsoft Edge open on Windows.
- Create a free GitHub account with a public repository named department-service-finder.
- Build the local folder structure and load a fresh WordPress Playground site.
Confirm your Windows tools
Visual Studio Code manages your project files. Windows PowerShell handles the plugin archive later.
Microsoft Edge runs the browser-based WordPress site where you test the plugin.
- Press the Windows key to open Windows Search.
- Type Visual Studio Code and press Enter.
- Return to Windows Search by pressing the Windows key.
- Type Windows PowerShell and press Enter.
Two Tools Ready
Visual Studio Code should show an editor window. Windows PowerShell should show a prompt where you can run commands later.
- Return to Windows Search by pressing the Windows key.
- Type Microsoft Edge and press Enter.
✔️ Microsoft Edge Opens
Your desktop toolkit is ready. You can now edit files, package the plugin, and test it in a browser.
ⓧ Microsoft Edge Is Missing
A missing browser is quick to resolve. Microsoft provides an official Windows download.
- Open the official Download Microsoft Edge page in another browser.
- Select the Windows download offered on the page.
- Complete the installation prompts.
- Launch Microsoft Edge through Windows Search.
One of the Tools Will Not Open?
- Search again using the full product name shown above.
- Confirm that you selected the desktop application in the search results.
Help me diagnose why one of my Windows tools will not open.
Create your public GitHub repository
The repository gives your finished plugin a public destination. It starts empty because you have not created the source files yet.
Creating an account means handling a password. Your password stays between you and GitHub throughout this project.
- Switch back to Microsoft Edge.
- Open the official GitHub sign-up page.
- Follow the prompts to create your personal account.
- Verify your email address using the message GitHub sends.
- Return to GitHub and sign in.
Why Verify Your Email?
GitHub requires a verified email address for basic tasks such as creating a repository. Verification unlocks the repository workflow you need next.
- Open New repository from GitHub's create menu.
- Enter department-service-finder as the repository name.
- Choose Public visibility.
- Leave every optional initialization choice blank to keep the repository empty.
- Click Create repository.
That is your public destination ready. You should see the empty repository setup page with department-service-finder at the top.
Repository Creation Blocked?
- Confirm that you completed the email verification message from GitHub.
- Reload GitHub after completing verification.
- Check that the repository name is exactly department-service-finder.
Help me create my empty public GitHub repository.
Create the local workspace and open Playground
The local workspace keeps the portfolio files separate from the installable plugin. The nested folder structure also gives the plugin a dedicated place for its future assets.
- Switch back to Visual Studio Code.
- Click File in the top menu bar.
- Select Open Folder....
- Select your Desktop in the folder picker.
- Click New Folder.
- Enter department-service-finder-portfolio as the folder name.
- Click Select Folder to open it in Visual Studio Code.
- Choose Yes, I trust the authors if the Workspace Trust dialog appears.
What Is a Workspace?
A Visual Studio Code workspace is the folder currently open in the editor. The Explorer sidebar displays everything stored inside that folder.
- Right-click department-service-finder-portfolio in the Explorer sidebar.
- Select New Folder.
- Type department-service-finder and press Enter.
- Right-click the new department-service-finder folder.
- Select New Folder.
- Type assets and press Enter.
You should see department-service-finder-portfolio at the top of the Explorer. Inside it, department-service-finder should contain the empty assets folder.
Folders in the Wrong Place?
- Confirm that department-service-finder is nested inside department-service-finder-portfolio.
- Confirm that assets is nested inside department-service-finder.
- Move any misplaced folder into its correct parent using the Explorer sidebar.
Help me correct my Visual Studio Code folder structure.
- Switch back to Microsoft Edge.
- Open the official WordPress Playground website.
You should see a fresh WordPress site running entirely in the browser. Playground needs no server setup or account.
Before the final check, which two open windows should prove that your local and browser tools are ready?
- Switch to Windows PowerShell.
You should see a normal PowerShell prompt ready to accept a command.
- Return to Microsoft Edge.
You should still see the fresh WordPress Playground site. This confirms that your local tooling and browser test environment are ready.
✔️ Awesome, I've Got Everything
Your portfolio workspace is ready. You now have a local folder structure, a public repository, and a fresh browser-based WordPress site.
ⓧ I'd Like to Double Check the Workspace
Your finished setup should match this checklist:
- A public empty GitHub repository named department-service-finder exists on main.
- A fresh browser-based WordPress site is open in Microsoft Edge.
- The local Visual Studio Code workspace folder department-service-finder-portfolio exists.
- The plugin folder department-service-finder-portfolio/department-service-finder exists.
- The assets folder department-service-finder-portfolio/department-service-finder/assets exists.
- The local folders contain no plugin source files yet.
Your workspace is ready for the first build. Next, you will create the shortcode directory and watch it render inside WordPress.
Build the First Shortcode Directory
Your portfolio workspace is ready. Now you need a working page that proves WordPress can load your own plugin code.
A shortcode lets a page request reusable output from a plugin. You will build the first PHP version of the service directory around that boundary.
This baseline renders real department services inside the browser. Its first test gives you a concrete usability problem to inspect before adding interactivity.
In this step, get ready to:
- Create the plugin file with four department services.
- Package the plugin as a ZIP archive.
- Launch the shortcode on a published WordPress page.
Create the shortcode plugin
Semantic HTML gives the directory meaningful sections plus service articles. The PHP arrays keep the department content separate from the markup that displays it.
Why use a shortcode plugin?
A plugin keeps reusable functionality independent from the site's design. The service finder can survive a future theme change.
A custom block would add a separate build workflow. A shortcode keeps this first plugin focused on PHP plus the browser output it returns.
The file is assembled in four connected chunks. Each chunk ends at a data or markup boundary.
- Use the New File control in the VS Code Explorer to create department-service-finder.php inside the existing department-service-finder folder.
- Begin the plugin header plus the first two service records by pasting this code:
<?php
/**
* Plugin Name: Department Service Finder
* Description: Adds a searchable directory of services for multiple departments.
* Author: Your Name
*/
function dsf_render_service_finder() {
$services = array(
array(
'department' => 'Information Technology',
'department_key' => 'it',
'title' => 'Account access support',
'description' => 'Get help with passwords, permissions, and account access.',
'response' => 'Within one business day',
),
array(
'department' => 'Human Resources',
'department_key' => 'hr',
'title' => 'New starter onboarding',
'description' => 'Request the checklist, forms, and orientation details for a new employee.',
'response' => 'Within two business days',
),
What does this code do?
- The plugin header gives WordPress the name plus description that appear on its plugin screen.
- The dsf_render_service_finder() callback starts a list of service records that the shortcode can render.
- Each service stores its department plus title plus description plus typical response time.
- Continue the $services array with the Marketing plus Facilities records by pasting this code directly below the previous chunk:
array(
'department' => 'Marketing',
'department_key' => 'marketing',
'title' => 'Website update request',
'description' => 'Submit a content, campaign, or landing-page change for review.',
'response' => 'Within three business days',
),
array(
'department' => 'Facilities',
'department_key' => 'facilities',
'title' => 'Workspace maintenance',
'description' => 'Report a repair, access, or office equipment issue.',
'response' => 'Within one business day',
),
);
$departments = array(
'it' => 'Information Technology',
'hr' => 'Human Resources',
'marketing' => 'Marketing',
'facilities' => 'Facilities',
);
How is the directory data organized?
- The remaining records complete the four-department service list.
- The $departments lookup pairs each stored department key with the label that visitors see.
- The shorter keys become predictable filter values once the controls gain behavior.
- Save department-service-finder.php.
- Confirm department-service-finder.php appears inside the department-service-finder folder in the VS Code Explorer.
Your plugin source file now exists with all four service records plus the department lookup.
- Add the directory heading plus search controls directly below the $departments array by pasting this code:
$output = '<section class="dsf-finder" data-dsf-finder aria-labelledby="dsf-title">';
$output .= '<h2 id="dsf-title">Find a department service</h2>';
$output .= '<p>Search common internal services or filter the directory by department.</p>';
$output .= '<div class="dsf-controls">';
$output .= '<div><label for="dsf-search">Search services</label><input id="dsf-search" type="search" data-dsf-search autocomplete="off" placeholder="Try website or password"></div>';
$output .= '<div><label for="dsf-department">Department</label><select id="dsf-department" data-dsf-department><option value="">All departments</option>';
foreach ( $departments as $department_key => $department_name ) {
$output .= '<option value="' . esc_attr( $department_key ) . '">' . esc_html( $department_name ) . '</option>';
}
$output .= '</select></div></div>';
$output .= '<div class="dsf-grid">';
What does the control markup provide?
- The outer section connects its heading through aria-labelledby so the directory has an accessible name.
- The search input gives visitors a place to enter a service need.
- The department loop turns every item in $departments into a selector option.
- The data-dsf-finder attribute gives later browser code a stable way to locate this directory.
- Finish the service cards plus shortcode registration by pasting this code directly below the previous chunk:
foreach ( $services as $service ) {
$output .= '<article class="dsf-card" data-dsf-card data-department="' . esc_attr( $service['department_key'] ) . '">';
$output .= '<p class="dsf-department">' . esc_html( $service['department'] ) . '</p>';
$output .= '<h3>' . esc_html( $service['title'] ) . '</h3>';
$output .= '<p>' . esc_html( $service['description'] ) . '</p>';
$output .= '<p class="dsf-response"><strong>Typical response:</strong> ' . esc_html( $service['response'] ) . '</p>';
$output .= '</article>';
}
$output .= '</div></section>';
return $output;
}
add_shortcode( 'department_service_finder', 'dsf_render_service_finder' );
How does the shortcode render services?
- The service loop creates one semantic article for each record in $services.
- The esc_attr plus esc_html calls prepare dynamic values for safe HTML output.
- The callback returns the complete section so WordPress can insert it into page content.
- The add_shortcode() call connects department_service_finder to the callback.
- Save department-service-finder.php.
- Compare your saved file with the complete reference below.
✔️ Awesome, I've got everything!
Great. Your complete PHP plugin file is saved inside the existing plugin folder.
ⓧ I'd like to double check the full code
Use this complete reference to check every line in department-service-finder.php.
<?php
/**
* Plugin Name: Department Service Finder
* Description: Adds a searchable directory of services for multiple departments.
* Author: Your Name
*/
function dsf_render_service_finder() {
$services = array(
array(
'department' => 'Information Technology',
'department_key' => 'it',
'title' => 'Account access support',
'description' => 'Get help with passwords, permissions, and account access.',
'response' => 'Within one business day',
),
array(
'department' => 'Human Resources',
'department_key' => 'hr',
'title' => 'New starter onboarding',
'description' => 'Request the checklist, forms, and orientation details for a new employee.',
'response' => 'Within two business days',
),
array(
'department' => 'Marketing',
'department_key' => 'marketing',
'title' => 'Website update request',
'description' => 'Submit a content, campaign, or landing-page change for review.',
'response' => 'Within three business days',
),
array(
'department' => 'Facilities',
'department_key' => 'facilities',
'title' => 'Workspace maintenance',
'description' => 'Report a repair, access, or office equipment issue.',
'response' => 'Within one business day',
),
);
$departments = array(
'it' => 'Information Technology',
'hr' => 'Human Resources',
'marketing' => 'Marketing',
'facilities' => 'Facilities',
);
$output = '<section class="dsf-finder" data-dsf-finder aria-labelledby="dsf-title">';
$output .= '<h2 id="dsf-title">Find a department service</h2>';
$output .= '<p>Search common internal services or filter the directory by department.</p>';
$output .= '<div class="dsf-controls">';
$output .= '<div><label for="dsf-search">Search services</label><input id="dsf-search" type="search" data-dsf-search autocomplete="off" placeholder="Try website or password"></div>';
$output .= '<div><label for="dsf-department">Department</label><select id="dsf-department" data-dsf-department><option value="">All departments</option>';
foreach ( $departments as $department_key => $department_name ) {
$output .= '<option value="' . esc_attr( $department_key ) . '">' . esc_html( $department_name ) . '</option>';
}
$output .= '</select></div></div>';
$output .= '<div class="dsf-grid">';
foreach ( $services as $service ) {
$output .= '<article class="dsf-card" data-dsf-card data-department="' . esc_attr( $service['department_key'] ) . '">';
$output .= '<p class="dsf-department">' . esc_html( $service['department'] ) . '</p>';
$output .= '<h3>' . esc_html( $service['title'] ) . '</h3>';
$output .= '<p>' . esc_html( $service['description'] ) . '</p>';
$output .= '<p class="dsf-response"><strong>Typical response:</strong> ' . esc_html( $service['response'] ) . '</p>';
$output .= '</article>';
}
$output .= '</div></section>';
return $output;
}
add_shortcode( 'department_service_finder', 'dsf_render_service_finder' );
What should match?
The complete file contains one plugin header plus two arrays plus one rendering callback plus one shortcode registration. Matching this reference ensures the ZIP contains the exact first version of the plugin.
Does the PHP file look incomplete?
Confirm all four chunks appear in one department-service-finder.php file. Check that the final line registers department_service_finder.
Make sure the file sits directly inside the department-service-finder folder instead of its assets folder.
help me compare my PHP plugin file with the required Department Service Finder structure
Package and install the plugin
WordPress installs an uploaded plugin from a ZIP archive. Including the outer department-service-finder folder gives WordPress one complete plugin directory to install.
- Return to the Windows PowerShell terminal in VS Code.
- Confirm the terminal prompt ends in department-service-finder-portfolio.
- Create the plugin ZIP by running this command:
Compress-Archive -Path .\department-service-finder -DestinationPath .\department-service-finder.zip -Force
What does this command do?
Compress-Archive packages the complete plugin folder as department-service-finder.zip. The -Force flag replaces an older archive with the rebuilt version.
- Refresh the VS Code Explorer.
- Confirm department-service-finder.zip appears inside department-service-finder-portfolio.
The archive is now ready for WordPress Playground.
ZIP file missing?
Check that Windows PowerShell is inside department-service-finder-portfolio before running the command. The folder must contain the nested department-service-finder directory.
help me find why my Department Service Finder ZIP was not created
- Switch back to the WordPress Playground site in Microsoft Edge.
- Select Plugins in the WordPress admin menu.
- Click Add New.
- Click Upload Plugin.
- Choose department-service-finder.zip from the department-service-finder-portfolio folder.
- Click Install Now.
You should see Plugin installed successfully. when WordPress finishes unpacking the archive.
- Click Activate Plugin.
The Department Service Finder is now active in your browser-based WordPress site.
Plugin installation failed?
Confirm the ZIP contains the outer department-service-finder folder. That folder must contain department-service-finder.php directly inside it.
Rebuild the archive after saving the PHP file if WordPress cannot identify the plugin.
help me debug why WordPress Playground cannot install my plugin ZIP
Publish and test the directory
Activating the plugin makes its shortcode available. A page still needs to request that shortcode before visitors can see the directory.
- Select Pages in the WordPress admin menu.
- Click Add New.
- Enter Department Services as the page title.
- Type /shortcode into the page content area.
- Press Enter to insert the Shortcode block.
- Enter [department_service_finder] inside the Shortcode block.
- Click Publish.
- Confirm the publication if WordPress asks for confirmation.
- Use the published page link to open the Department Services page.
You should see a Find a department service heading plus a search field plus a department selector. Four unstyled service cards appear below the controls.
Before you test the controls, consider how many cards you expect to remain after a search for website.
- Type website into the Search services field.
All four service cards remain visible. The search field accepts text without changing the directory.
- Choose Marketing from the Department selector.
All four cards still remain visible. The selector changes value without filtering the service list.
Why did the controls fall short?
This shortfall is intentional. The HTML renders the controls plus service cards correctly.
No JavaScript listens for search or department changes in this first version. The browser therefore has no instruction to hide a card.
That is the first working directory complete. Next, you will add responsive CSS plus filtering behavior so the controls produce a visible result.
Add Search, Filters, and Responsive Styling
Your WordPress page now renders four department services. However, the controls still make a promise they cannot keep. Every card remains visible when a visitor searches or chooses a department.
In this step, CSS turns the raw markup into a responsive directory. JavaScript connects each control to the cards in the DOM. Visitors get immediate results without reloading the page.
In this step, get ready to:
- Style the service directory for wide and narrow screens.
- Connect keyword search to each card's visible state.
- Verify combined search and department filtering in the rebuilt plugin.
Add responsive directory styles
The existing HTML already provides classes for the finder, controls, grid, and cards. Your stylesheet can target those classes without changing the shortcode markup.
- Switch back to Visual Studio Code.
- Select the assets folder in the Explorer sidebar.
- Click the New File icon in the Explorer sidebar.
- Enter style.css as the file name.
- Add the finder container and control panel by pasting this first chunk:
.dsf-finder {
--dsf-primary: #1d4ed8;
--dsf-text: #172033;
--dsf-muted: #526078;
--dsf-border: #d8e0ec;
max-width: 1100px;
margin: 2rem auto;
color: var(--dsf-text);
}
.dsf-finder * {
box-sizing: border-box;
}
.dsf-controls {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1rem;
margin: 1.5rem 0;
padding: 1rem;
border: 1px solid var(--dsf-border);
border-radius: 0.75rem;
background: #f8fafc;
}
What does this CSS do?
- The custom properties keep the plugin's colors consistent across later selectors.
- The maximum width keeps long lines and cards readable on wide screens.
- The controls use a two-column grid with more space for keyword search.
- Save style.css.
- Confirm that style.css appears inside the assets folder in the Explorer sidebar.
File in the wrong folder?
Confirm that the Explorer path reads department-service-finder/assets/style.css. The PHP file and assets folder must share the same plugin folder.
Ask for help if the file appeared beside the plugin folder instead of inside it: help me place style.css in the correct WordPress plugin folder
- Add the labels, form controls, and keyboard focus styles by pasting this code at the end of style.css:
.dsf-controls label {
display: block;
margin-bottom: 0.35rem;
font-weight: 700;
}
.dsf-controls input,
.dsf-controls select {
width: 100%;
min-height: 2.75rem;
padding: 0.65rem 0.75rem;
border: 1px solid #94a3b8;
border-radius: 0.5rem;
background: #ffffff;
color: var(--dsf-text);
font: inherit;
}
.dsf-controls input:focus,
.dsf-controls select:focus {
outline: 3px solid #bfdbfe;
border-color: var(--dsf-primary);
}
How do the controls stay usable?
- Block labels make each field name easy to scan above its control.
- The shared input rules give both controls the same size and typography.
- The focus rules create a visible outline for keyboard users.
- Save style.css.
- Confirm that the final selector in the file is .dsf-controls select:focus.
Seeing CSS warnings?
Check that each selector has an opening brace and a closing brace. Confirm that the input selector ends with a comma before the select selector.
Use this if Visual Studio Code still highlights the chunk as invalid: help me debug the control styles in style.css
- Add the two-column card grid and card presentation by pasting this code at the end of style.css:
.dsf-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
}
.dsf-card {
padding: 1.25rem;
border: 1px solid var(--dsf-border);
border-top: 0.35rem solid var(--dsf-primary);
border-radius: 0.75rem;
background: #ffffff;
box-shadow: 0 0.35rem 1rem rgba(15, 23, 42, 0.08);
}
.dsf-card[hidden] {
display: none;
}
How will cards respond to filtering?
- The grid displays cards in two equal columns when space allows.
- The card rules create clear boundaries between department services.
- The attribute selector removes cards after JavaScript sets their hidden state.
- Save style.css.
- Confirm that the file now includes the .dsf-card[hidden] selector.
Hidden cards still taking space?
Confirm that hidden appears inside square brackets in the selector. The rule must set display: none.
Use this for help with the hidden-card selector: help me check why hidden service cards still occupy grid space
- Finish the card typography and mobile breakpoint by pasting this code at the end of style.css:
.dsf-card h3 {
margin: 0.35rem 0 0.65rem;
}
.dsf-department {
margin: 0;
color: var(--dsf-primary);
font-size: 0.8rem;
font-weight: 800;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.dsf-response {
margin-bottom: 0;
color: var(--dsf-muted);
}
@media (max-width: 640px) {
.dsf-controls,
.dsf-grid {
grid-template-columns: 1fr;
}
}
What changes on narrow screens?
- Department names use compact uppercase text to separate them from service titles.
- Response details use a muted color to keep the service title prominent.
- The media query switches the controls and cards to one column below 640px.
- Save style.css.
- Confirm that the file ends with the @media (max-width: 640px) rule.
Mobile rule incomplete?
Confirm that both .dsf-controls and .dsf-grid appear inside the media query. Both selectors must use a single grid column.
Use this if the final braces are difficult to match: help me check the mobile media query in style.css
✔️ Awesome, I've got everything!
Great. Save style.css before you continue.
ⓧ I'd like to double check the full code
Compare your complete style.css file with this reference:
.dsf-finder {
--dsf-primary: #1d4ed8;
--dsf-text: #172033;
--dsf-muted: #526078;
--dsf-border: #d8e0ec;
max-width: 1100px;
margin: 2rem auto;
color: var(--dsf-text);
}
.dsf-finder * {
box-sizing: border-box;
}
.dsf-controls {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1rem;
margin: 1.5rem 0;
padding: 1rem;
border: 1px solid var(--dsf-border);
border-radius: 0.75rem;
background: #f8fafc;
}
.dsf-controls label {
display: block;
margin-bottom: 0.35rem;
font-weight: 700;
}
.dsf-controls input,
.dsf-controls select {
width: 100%;
min-height: 2.75rem;
padding: 0.65rem 0.75rem;
border: 1px solid #94a3b8;
border-radius: 0.5rem;
background: #ffffff;
color: var(--dsf-text);
font: inherit;
}
.dsf-controls input:focus,
.dsf-controls select:focus {
outline: 3px solid #bfdbfe;
border-color: var(--dsf-primary);
}
.dsf-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
}
.dsf-card {
padding: 1.25rem;
border: 1px solid var(--dsf-border);
border-top: 0.35rem solid var(--dsf-primary);
border-radius: 0.75rem;
background: #ffffff;
box-shadow: 0 0.35rem 1rem rgba(15, 23, 42, 0.08);
}
.dsf-card[hidden] {
display: none;
}
.dsf-card h3 {
margin: 0.35rem 0 0.65rem;
}
.dsf-department {
margin: 0;
color: var(--dsf-primary);
font-size: 0.8rem;
font-weight: 800;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.dsf-response {
margin-bottom: 0;
color: var(--dsf-muted);
}
@media (max-width: 640px) {
.dsf-controls,
.dsf-grid {
grid-template-columns: 1fr;
}
}
This reference combines the four CSS chunks into the exact finished stylesheet.
Connect the filtering controls
Each service card already contains searchable text and a data-department value. The script reads those values whenever either control changes.
- Select the assets folder in the Explorer sidebar.
- Click the New File icon in the Explorer sidebar.
- Enter script.js as the file name.
- Add the filtering behavior by pasting this code:
document.addEventListener('DOMContentLoaded', () => {
const finder = document.querySelector('[data-dsf-finder]');
if (!finder) {
return;
}
const searchInput = finder.querySelector('[data-dsf-search]');
const departmentSelect = finder.querySelector('[data-dsf-department]');
const cards = Array.from(finder.querySelectorAll('[data-dsf-card]'));
function filterServices() {
const searchTerm = searchInput.value.trim().toLowerCase();
const department = departmentSelect.value;
cards.forEach((card) => {
const matchesSearch = card.textContent.toLowerCase().includes(searchTerm);
const matchesDepartment = !department || card.dataset.department === department;
card.hidden = !(matchesSearch && matchesDepartment);
});
}
searchInput.addEventListener('input', filterServices);
departmentSelect.addEventListener('change', filterServices);
});
How does filtering work?
- The DOMContentLoaded listener waits until the service directory is available.
- The finder reference keeps every lookup inside this plugin's section.
- The filterServices() function compares normalized card text with the search term.
- The same function compares each card's department value with the selected department.
- A card stays visible only when both comparisons pass.
- Save script.js.
- Confirm that script.js appears beside style.css in the assets folder.
Script showing syntax errors?
Check the closing braces at the bottom of script.js. The function closes before the two event listeners.
Use this if Visual Studio Code still highlights an error: help me debug the filterServices function
✔️ Awesome, I've got everything!
Your filtering script is ready. Save script.js before moving on.
ⓧ I'd like to double check the full code
Compare your complete script.js file with this reference:
document.addEventListener('DOMContentLoaded', () => {
const finder = document.querySelector('[data-dsf-finder]');
if (!finder) {
return;
}
const searchInput = finder.querySelector('[data-dsf-search]');
const departmentSelect = finder.querySelector('[data-dsf-department]');
const cards = Array.from(finder.querySelectorAll('[data-dsf-card]'));
function filterServices() {
const searchTerm = searchInput.value.trim().toLowerCase();
const department = departmentSelect.value;
cards.forEach((card) => {
const matchesSearch = card.textContent.toLowerCase().includes(searchTerm);
const matchesDepartment = !department || card.dataset.department === department;
card.hidden = !(matchesSearch && matchesDepartment);
});
}
searchInput.addEventListener('input', filterServices);
departmentSelect.addEventListener('change', filterServices);
});
This reference contains the complete filtering script used by the finished plugin.
Load the assets and test the filters
The new files exist locally, but WordPress needs their URLs before a page can load them. An enqueue function registers both assets through the page-loading hook.
- Return to department-service-finder.php in Visual Studio Code.
- Find function dsf_render_service_finder() {.
- Insert the asset-loading function immediately above that line by pasting this code:
function dsf_enqueue_assets() {
$base_url = plugin_dir_url( __FILE__ );
wp_enqueue_style(
'department-service-finder',
$base_url . 'assets/style.css',
array(),
false,
'all'
);
wp_enqueue_script(
'department-service-finder',
$base_url . 'assets/script.js',
array(),
false,
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
}
add_action( 'wp_enqueue_scripts', 'dsf_enqueue_assets' );
What does the enqueue function do?
- The plugin_dir_url() call builds the public URL for the current plugin folder.
- The wp_enqueue_style() call loads assets/style.css.
- The wp_enqueue_script() call loads assets/script.js with deferred execution in the footer.
- The wp_enqueue_scripts hook runs the function during front-end page loading.
- Save department-service-finder.php.
- Confirm that dsf_enqueue_assets() appears above dsf_render_service_finder().
PHP function in the wrong place?
Keep the plugin header at the top of the file. Place dsf_enqueue_assets() after that header and before dsf_render_service_finder().
Use this if braces or function placement look incorrect: help me place the enqueue function in my plugin file
✔️ Awesome, I've got everything!
All three plugin files are ready. Save them before rebuilding the ZIP.
ⓧ I'd like to double check the full code
Compare your complete department-service-finder.php file with this reference:
<?php
/**
* Plugin Name: Department Service Finder
* Description: Adds a searchable directory of services for multiple departments.
* Author: Your Name
*/
function dsf_enqueue_assets() {
$base_url = plugin_dir_url( __FILE__ );
wp_enqueue_style(
'department-service-finder',
$base_url . 'assets/style.css',
array(),
false,
'all'
);
wp_enqueue_script(
'department-service-finder',
$base_url . 'assets/script.js',
array(),
false,
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
}
add_action( 'wp_enqueue_scripts', 'dsf_enqueue_assets' );
function dsf_render_service_finder() {
$services = array(
array(
'department' => 'Information Technology',
'department_key' => 'it',
'title' => 'Account access support',
'description' => 'Get help with passwords, permissions, and account access.',
'response' => 'Within one business day',
),
array(
'department' => 'Human Resources',
'department_key' => 'hr',
'title' => 'New starter onboarding',
'description' => 'Request the checklist, forms, and orientation details for a new employee.',
'response' => 'Within two business days',
),
array(
'department' => 'Marketing',
'department_key' => 'marketing',
'title' => 'Website update request',
'description' => 'Submit a content, campaign, or landing-page change for review.',
'response' => 'Within three business days',
),
array(
'department' => 'Facilities',
'department_key' => 'facilities',
'title' => 'Workspace maintenance',
'description' => 'Report a repair, access, or office equipment issue.',
'response' => 'Within one business day',
),
);
$departments = array(
'it' => 'Information Technology',
'hr' => 'Human Resources',
'marketing' => 'Marketing',
'facilities' => 'Facilities',
);
$output = '<section class="dsf-finder" data-dsf-finder aria-labelledby="dsf-title">';
$output .= '<h2 id="dsf-title">Find a department service</h2>';
$output .= '<p>Search common internal services or filter the directory by department.</p>';
$output .= '<div class="dsf-controls">';
$output .= '<div><label for="dsf-search">Search services</label><input id="dsf-search" type="search" data-dsf-search autocomplete="off" placeholder="Try website or password"></div>';
$output .= '<div><label for="dsf-department">Department</label><select id="dsf-department" data-dsf-department><option value="">All departments</option>';
foreach ( $departments as $department_key => $department_name ) {
$output .= '<option value="' . esc_attr( $department_key ) . '">' . esc_html( $department_name ) . '</option>';
}
$output .= '</select></div></div>';
$output .= '<div class="dsf-grid">';
foreach ( $services as $service ) {
$output .= '<article class="dsf-card" data-dsf-card data-department="' . esc_attr( $service['department_key'] ) . '">';
$output .= '<p class="dsf-department">' . esc_html( $service['department'] ) . '</p>';
$output .= '<h3>' . esc_html( $service['title'] ) . '</h3>';
$output .= '<p>' . esc_html( $service['description'] ) . '</p>';
$output .= '<p class="dsf-response"><strong>Typical response:</strong> ' . esc_html( $service['response'] ) . '</p>';
$output .= '</article>';
}
$output .= '</div></section>';
return $output;
}
add_shortcode( 'department_service_finder', 'dsf_render_service_finder' );
This reference preserves the original shortcode code and adds the completed enqueue function above it.
The next upload replaces the existing plugin files in your temporary Playground site. Your published Department Services page remains in place.
- Return to Windows PowerShell from earlier.
- Rebuild department-service-finder.zip by running this command:
Compress-Archive -Path .\department-service-finder -DestinationPath .\department-service-finder.zip -Force
What does this command do?
The command compresses the complete department-service-finder folder. The -Force option replaces the older ZIP with the rebuilt version.
- Confirm that the timestamp for department-service-finder.zip has updated in the Visual Studio Code Explorer sidebar.
- Return to the WordPress administration area in Microsoft Edge.
- Select Plugins from the administration menu.
- Click Add New.
- Click Upload Plugin.
- Choose the rebuilt department-service-finder.zip file.
- Click Install Now.
- Click Replace current with uploaded when WordPress reports that the plugin is already installed.
The rebuilt plugin now supplies the page with its stylesheet and filtering script. Time to test each visible change.
- Return to the published Department Services page.
- Refresh the page.
- Narrow the Microsoft Edge window until the cards form one column.
You should see the controls stack above a single column of service cards. Widen the window again to restore the two-column card grid.
- Enter password in the Search services field.
You should see only the Account access support card. This proves keyword search can match text inside a service card.
- Clear the Search services field.
- Select Facilities from the Department selector.
You should see only the Workspace maintenance card. This proves the department value filters the directory independently.
- Select All departments from the Department selector.
Before you combine the controls, do you expect the search term and department selection to narrow the same set of cards?
- Enter website in the Search services field.
- Select Marketing from the Department selector.
You should see only the Website update request card. The page stays loaded while the script hides the other three cards.
Filters or styles missing?
Confirm that the rebuilt ZIP contains department-service-finder.php plus the assets folder. That folder must contain both style.css and script.js.
If the cards are styled but never hide, compare the selectors in script.js with the existing data-dsf-finder, data-dsf-search, data-dsf-department, and data-dsf-card attributes.
Use this for targeted debugging help: help me debug why my WordPress service finder is not styling or filtering cards
You did it. The directory now responds to both visitor inputs and adapts to narrow screens.
Your service finder is now interactive and responsive. Next, you will improve its page structure and prevent these assets from loading where the shortcode is absent.
Improve SEO and Conditional Asset Loading
Your WordPress Playground directory now responds to search terms and department choices. Visitors can reach the right service without reloading the page.
However, the current page has an unclear URL. Its plugin files also load on pages that never use the directory. This step improves SEO through a readable page structure. It also limits asset requests to the page containing the shortcode.
In this step, get ready to:
- Give the Department Services page a readable URL with descriptive content.
- Prevent the plugin assets from loading on unrelated pages.
- Verify conditional loading through the Microsoft Edge Network panel.
Create a readable service page
A readable permalink gives the directory a clear address. Descriptive introductory text tells visitors what they can find before they reach the controls.
- Return to the WordPress Playground dashboard from earlier.
- Select Settings in the left navigation.
- Select Permalinks.
- Choose Post name.
- Save the permalink setting with the button at the bottom of the page.
WordPress now uses page names in its URLs. This gives the service directory a readable address instead of a numeric query.
- Return to the Department Services page editor from earlier.
- Keep Department Services as the page title.
- Set the page slug to department-services with the editor's permalink control.
- Add a paragraph immediately before the Shortcode block.
- Fill the new paragraph by copying this text:
Find the right support service across Information Technology, Human Resources, Marketing, and Facilities.
Why This Page Structure Matters
- The /department-services/ permalink gives people a readable clue about the page before they open it.
- The introductory paragraph gives visitors useful context before the directory.
- The page title provides the H1 heading.
- The shortcode provides the H2 heading.
- Each service card provides an H3 heading.
- This heading order creates a clear semantic HTML structure.
- Save the updated page.
- Return to the published Department Services page.
You should see the introductory paragraph above the directory. The address should end with /department-services/.
The visible heading order starts with Department Services. It continues with Find a department service before reaching each service-card title.
Add conditional asset checks
The current enqueue function requests the plugin stylesheet and script across the site. Conditional asset loading checks the current page before those requests are added.
- Switch back to Visual Studio Code.
- Select department-service-finder/department-service-finder.php in the Explorer sidebar.
- Find the $base_url = plugin_dir_url( __FILE__ ); line inside dsf_enqueue_assets().
- Paste these checks directly above that line:
if ( ! is_singular() ) {
return;
}
global $post;
if ( ! isset( $post->post_content ) || ! has_shortcode( $post->post_content, 'department_service_finder' ) ) {
return;
}
What Do These Checks Do?
- The is_singular() check limits the next test to a single page or post.
- The global $post line makes the current post available inside the function.
- The isset( $post->post_content ) check confirms that the current post has readable content.
- The has_shortcode() check looks for department_service_finder in that content.
- An unrelated page reaches return before either asset is enqueued.
- The existing script enqueue keeps its defer strategy and footer placement.
- Save department-service-finder/department-service-finder.php.
✔️ Awesome, I've got everything!
Great. The function now exits before loading assets on pages without the service finder shortcode.
ⓧ I'd like to double check the full code
<?php
/**
* Plugin Name: Department Service Finder
* Description: Adds a searchable directory of services for multiple departments.
* Author: Your Name
*/
function dsf_enqueue_assets() {
if ( ! is_singular() ) {
return;
}
global $post;
if ( ! isset( $post->post_content ) || ! has_shortcode( $post->post_content, 'department_service_finder' ) ) {
return;
}
$base_url = plugin_dir_url( __FILE__ );
wp_enqueue_style(
'department-service-finder',
$base_url . 'assets/style.css',
array(),
false,
'all'
);
wp_enqueue_script(
'department-service-finder',
$base_url . 'assets/script.js',
array(),
false,
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
}
add_action( 'wp_enqueue_scripts', 'dsf_enqueue_assets' );
function dsf_render_service_finder() {
$services = array(
array(
'department' => 'Information Technology',
'department_key' => 'it',
'title' => 'Account access support',
'description' => 'Get help with passwords, permissions, and account access.',
'response' => 'Within one business day',
),
array(
'department' => 'Human Resources',
'department_key' => 'hr',
'title' => 'New starter onboarding',
'description' => 'Request the checklist, forms, and orientation details for a new employee.',
'response' => 'Within two business days',
),
array(
'department' => 'Marketing',
'department_key' => 'marketing',
'title' => 'Website update request',
'description' => 'Submit a content, campaign, or landing-page change for review.',
'response' => 'Within three business days',
),
array(
'department' => 'Facilities',
'department_key' => 'facilities',
'title' => 'Workspace maintenance',
'description' => 'Report a repair, access, or office equipment issue.',
'response' => 'Within one business day',
),
);
$departments = array(
'it' => 'Information Technology',
'hr' => 'Human Resources',
'marketing' => 'Marketing',
'facilities' => 'Facilities',
);
$output = '<section class="dsf-finder" data-dsf-finder aria-labelledby="dsf-title">';
$output .= '<h2 id="dsf-title">Find a department service</h2>';
$output .= '<p>Search common internal services or filter the directory by department.</p>';
$output .= '<div class="dsf-controls">';
$output .= '<div><label for="dsf-search">Search services</label><input id="dsf-search" type="search" data-dsf-search autocomplete="off" placeholder="Try website or password"></div>';
$output .= '<div><label for="dsf-department">Department</label><select id="dsf-department" data-dsf-department><option value="">All departments</option>';
foreach ( $departments as $department_key => $department_name ) {
$output .= '<option value="' . esc_attr( $department_key ) . '">' . esc_html( $department_name ) . '</option>';
}
$output .= '</select></div></div>';
$output .= '<div class="dsf-grid">';
foreach ( $services as $service ) {
$output .= '<article class="dsf-card" data-dsf-card data-department="' . esc_attr( $service['department_key'] ) . '">';
$output .= '<p class="dsf-department">' . esc_html( $service['department'] ) . '</p>';
$output .= '<h3>' . esc_html( $service['title'] ) . '</h3>';
$output .= '<p>' . esc_html( $service['description'] ) . '</p>';
$output .= '<p class="dsf-response"><strong>Typical response:</strong> ' . esc_html( $service['response'] ) . '</p>';
$output .= '</article>';
}
$output .= '</div></section>';
return $output;
}
add_shortcode( 'department_service_finder', 'dsf_render_service_finder' );
Rebuild and verify the plugin
WordPress Playground still has the previous ZIP contents. Rebuilding the archive carries the conditional checks into the browser-based site.
- Return to the Windows PowerShell terminal from earlier.
- Confirm the terminal prompt points to the department-service-finder-portfolio folder.
- Rebuild the plugin ZIP by running this command:
Compress-Archive -Path .\department-service-finder -DestinationPath .\department-service-finder.zip -Force
What Does This Command Do?
The Compress-Archive command packages the complete department-service-finder folder. Including the folder keeps the plugin files together under the expected directory name.
The -Force flag replaces the previous department-service-finder.zip archive.
- Return to the WordPress Playground dashboard from earlier.
- Select Plugins in the left navigation.
- Select Add New.
- Select Upload Plugin.
- Choose the rebuilt department-service-finder.zip file.
Replacing the existing plugin can feel risky, but this upload only updates the files inside the same plugin folder.
- Select Install Now.
- Approve the replacement prompt so WordPress overwrites the current plugin files.
- Confirm that Department Service Finder remains active.
- Select Activate Plugin if WordPress shows that option.
The active plugin now contains the conditional checks. A page without the shortcode gives you the comparison needed to prove they work.
- Select Pages in the WordPress dashboard.
- Select Add New.
- Enter Blank Comparison as the page title.
- Keep the page content empty.
- Select Publish.
- Open the published Blank Comparison page.
The blank page provides a clean control case. Any service finder request on this page would show that the conditional check is still too broad.
- Predict which page should request the plugin assets before you reload either page.
- Return to the published Department Services page.
- Press F12 to open Microsoft Edge DevTools.
- Select the Network panel.
- Refresh the Department Services page.
- Enter department-service-finder in the Network filter.
You should see matching requests for assets/style.css and assets/script.js. This proves the shortcode page still receives both assets.
- Navigate to the published Blank Comparison page while DevTools remains open.
- Clear the request list with the Network panel's clear control.
- Refresh the Blank Comparison page.
You should see no requests matching department-service-finder. The early returns have removed unnecessary CSS and JavaScript from the blank page.
- Predict how the controls and cards should change below the mobile breakpoint.
- Return to the Department Services page.
- Use the DevTools responsive viewport control to set the width below 640px.
- Type website into the search field.
- Choose Marketing from the department selector.
You should see the controls stacked in one column. Only the Website update request card should remain visible in the single-column grid.
Assets Loading on the Wrong Page?
If the blank page still requests the plugin files, confirm that both early-return checks sit above $base_url inside dsf_enqueue_assets(). Rebuild the ZIP after saving the PHP file.
If the service page has no styling or filtering, confirm that its Shortcode block still contains [department_service_finder].
Help me diagnose the conditional asset loading checks.
Strong result. Your directory now has a readable page structure without making unrelated pages download its assets. Next up, you will publish the source and a one-click demo through GitHub.
Publish a One-Click Portfolio Demo
Your service finder now has a readable URL. It also loads its assets only on the page that needs them.
A browser session cannot show employers your work later. In this step, you will publish the source on GitHub.
A Blueprint recreates the finished WordPress Playground page from one link.
In this step, get ready to:
- Create a valid blueprint.json file for the reproducible demo.
- Write a README.md file with a one-click demo link.
- Publish a working demo from your public GitHub repository.
Create the Blueprint and README
A Blueprint is a JSON recipe that prepares a fresh WordPress site. Your recipe installs the plugin from GitHub.
The README explains what the plugin does. It also carries the public launch link.
- Return to Visual Studio Code.
- Use the new-file control to create blueprint.json inside the department-service-finder-portfolio folder.
- Use the new-file control to create README.md inside the department-service-finder-portfolio folder.
You should now see both files beside the department-service-finder plugin folder in Visual Studio Code.
- Use the complete references in the second tab to populate both files.
✔️ Awesome, I've got everything!
Confirm that both files are inside department-service-finder-portfolio before personalizing the URLs.
ⓧ I'd like to double check the full code
{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"landingPage": "/department-services/",
"preferredVersions": {
"php": "8.3",
"wp": "latest"
},
"features": {
"networking": true
},
"steps": [
{
"step": "installPlugin",
"pluginData": {
"resource": "git:directory",
"url": "https://github.com/your-github-username/department-service-finder",
"ref": "HEAD",
"path": "department-service-finder"
},
"options": {
"activate": true,
"targetFolderName": "department-service-finder"
}
},
{
"step": "runPHP",
"code": "<?php require_once '/wordpress/wp-load.php'; $page_id = wp_insert_post( array( 'post_title' => 'Department Services', 'post_name' => 'department-services', 'post_content' => '<p>Find the right support service across Information Technology, Human Resources, Marketing, and Facilities.</p>[department_service_finder]', 'post_status' => 'publish', 'post_type' => 'page', 'comment_status' => 'closed' ) ); if ( $page_id ) { update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', $page_id ); } ?>"
},
{
"step": "setSiteOptions",
"options": {
"blogname": "Department Services Hub",
"blogdescription": "Find support across internal departments",
"permalink_structure": "/%postname%/"
}
}
]
}
What does this Blueprint do?
- The $schema value connects the file to the official Blueprint structure.
- The installPlugin step downloads the department-service-finder directory from the public repository.
- The plugin activation option makes the shortcode available in the fresh site.
- The runPHP step creates the published Department Services page.
- The setSiteOptions step applies the readable /%postname%/ permalink structure.
- The preferred PHP version is 8.3.
# Department Service Finder
A custom WordPress plugin that presents services from Information Technology, Human Resources, Marketing, and Facilities in one searchable directory.
## Live demo
[Launch the WordPress Playground demo](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/your-github-username/department-service-finder/main/blueprint.json)
## Features
- Reusable `[department_service_finder]` shortcode
- Semantic department service cards
- Keyword search and department filtering
- Responsive keyboard-friendly controls
- Conditional CSS and JavaScript loading
- Reproducible WordPress Playground setup
## Local installation
1. Compress the `department-service-finder` folder as a ZIP file.
2. In WordPress admin, open Plugins > Add New > Upload Plugin.
3. Install and activate the ZIP.
4. Add `[department_service_finder]` to a Shortcode block on a page.
## Portfolio talking points
- Built reusable WordPress functionality without editing WordPress core.
- Combined PHP, semantic HTML, CSS, and JavaScript in one maintainable plugin.
- Tested a non-working first version, added interactivity, and verified conditional asset loading.
- Used readable permalinks and descriptive page content for basic SEO.
What does the README provide?
The file uses Markdown to document the plugin. Its demo link sends Playground to the public blueprint.json file on main.
The feature list describes the finished behavior. The portfolio talking points connect that behavior to the work behind it.
- Return to the GitHub repository page from earlier.
- Record the account name from the repository URL here: your GitHub username.
- Switch back to Visual Studio Code.
- Replace every occurrence of your-github-username in blueprint.json with your GitHub username.
- Replace every occurrence of your-github-username in README.md with your GitHub username.
The repository source URL now points to your plugin. The README launch URL now points to your Blueprint.
- Save blueprint.json.
- Save README.md.
- Check blueprint.json for red JSON syntax markers in Visual Studio Code.
- Search the workspace for your-github-username.
Visual Studio Code should show no JSON syntax problems. Your workspace search should return no remaining username placeholders.
Seeing a JSON syntax problem?
Compare every double quote against the reference. Check the commas between objects carefully.
Confirm that each opening brace has a closing brace. Also confirm that the PHP inside code remains one quoted JSON value.
Help me find the syntax error in my Blueprint.
Upload the portfolio files to GitHub
The public repository is the durable copy of your project. Playground reads the Blueprint and plugin source from this location whenever someone launches the demo.
- Return to the empty public department-service-finder repository from earlier.
- Click Add file.
- Select Upload files.
- Drag the department-service-finder plugin folder into the upload area.
You should see the plugin files listed with their assets directory paths preserved.
- Drag blueprint.json into the upload area.
- Drag README.md into the upload area.
The upload list should now contain the plugin directory plus both portfolio files.
- Set the upload to commit to main.
- Use the page's commit control to add the uploaded files to main.
You should return to the repository file list. It should show department-service-finder, blueprint.json and README.md on main.
Good work. Your source now has a public home that survives the current Playground session.
Missing files after the upload?
Confirm that you uploaded the department-service-finder folder itself. The Blueprint expects that exact directory name.
Check that blueprint.json and README.md appear at the top level of main.
Help me fix my GitHub upload structure.
Test the demo in a private window
A fresh private session proves that the demo works without your existing Playground state. It also proves that the public repository contains everything the Blueprint needs.
- Copy the repository address from the signed-in Microsoft Edge window.
- Open a private Microsoft Edge window from the browser menu.
- Paste the repository address into the private window's address bar.
Before you launch the demo, do you expect the repository to recreate the finished service page without using your existing Playground session?
- Click Launch the WordPress Playground demo in the rendered README.
The fresh Playground session should land at /department-services/. You should see the introductory text above four service cards.
Before you test the controls, which card do you expect to remain when both filters target Marketing website work?
- Enter website in the Search services field.
- Choose Marketing from the Department selector.
You should see only the Website update request card. The visible change confirms that the public demo loaded the finished JavaScript.
Demo not loading correctly?
Confirm that the repository visibility is Public. Playground must be able to download the source without your GitHub session.
Search both portfolio files for your-github-username again. Any remaining occurrence points the demo at the wrong repository.
Confirm that main contains blueprint.json. Confirm that the plugin remains inside the department-service-finder directory.
Help me debug why my public Playground demo is not loading the plugin.
That is the portfolio proof complete. Anyone with the README link can now launch your service finder in a fresh WordPress site.
Secret mission
Add Live Results Feedback
Your filters change the visible cards, but visitors have to count the remaining results themselves. In this Secret Mission, you will add an accessible live summary that reports the match count and explains when no services match.
Clean Up Your Resources
Clean Up Your Resources
Your local files, GitHub Free repository, plus WordPress Playground demo cost $0 to keep. Choose the cleanup option that matches what you want to do next.
Resources you used:
- A local department-service-finder-portfolio folder contains the plugin source plus department-service-finder.zip.
- A public GitHub repository named department-service-finder contains the final source. The repository also contains README.md plus blueprint.json.
- A browser-based WordPress Playground session serves the /department-services/ demo.
Keep everything running
No action is needed. Choose this if you want the source plus one-click demo to remain available.
- Leave the public department-service-finder repository available so new demo sessions can install the plugin.
- Keep department-service-finder-portfolio in its current location for future changes.
- Keep the public demo link in README.md available for future testing.
Pause - I'll come back to this later
Pausing keeps your source intact while ending the active browser work. WordPress Playground has no local server process to stop.
- Close the WordPress Playground browser tab.
- Stop sharing the demo link until you return.
- Resume later by opening the public demo link from README.md.
Delete - I don't want to use this again
Permanent deletion can feel risky. You can keep any resource by leaving its deletion item unticked.
- Close the WordPress Playground browser tab.
- Close the department-service-finder-portfolio workspace in Visual Studio Code.
- Delete the department-service-finder-portfolio folder from its saved location in File Explorer.
- Search File Explorer for department-service-finder-portfolio to verify the local copy is gone.
You should no longer see the project folder. Its nested plugin files plus rebuilt ZIP are now removed from your computer.
The public demo pulls its files from the GitHub repository. Deleting the repository stops new demo sessions from loading those files.
- Return to the department-service-finder repository from earlier.
- Use the repository settings to locate its permanent deletion controls.
- Delete the repository by completing GitHub's confirmation prompts.
- Open the former repository URL in a private Microsoft Edge window.
You should no longer see the public source repository. The one-click demo can no longer start from that repository.
Nice Work!
Nice Work!
You did it! Your Department Service Finder is now a public WordPress plugin demo with working search filters. Its live results feedback makes every filter change clear.
You've learned how to:
- Built a reusable shortcode plugin that renders a semantic service directory for four departments.
- Connected keyword search to the service cards with JavaScript. Added a department filter that combines with each search term. Verified the solution against the deliberately inactive first version.
- Improved the service page with a readable permalink. Kept plugin assets off unrelated pages through conditional asset loading. Published the source in a public GitHub repository with a one-click WordPress Playground demo.
- Completed the Secret Mission by adding accessible live results feedback. The summary now reports the match count or explains that no services match.
Ready to quiz yourself?