Skip to content

Google for Jobs & SEO

Google for Jobs surfaces job listings directly in Google search results with rich cards showing salary, location, and an "Apply" button. The Recruitly WordPress plugin stores all the structured data you need — this guide shows you how to output it as JSON-LD so Google picks it up.

How It Works

Google looks for JobPosting structured data (JSON-LD format) on each job page. When it finds valid data, your listing appears in the Google for Jobs widget — a dedicated panel at the top of search results for job-related queries.

Your WordPress job page → JSON-LD markup → Google crawls → Google for Jobs widget

Setup

Step 1 — Add the JSON-LD Snippet

Add this code to your theme's functions.php file. It generates structured data for each job post using the metadata synced by the Recruitly plugin.

php
function recruitly_google_jobs_schema() {
    if (!is_singular('job')) return;

    $post_id = get_the_ID();

    // ── Configure these for your agency ──
    $agency_name     = 'Your Agency Name';
    $currency        = 'GBP';   // GBP, USD, EUR, AUD, etc.
    $default_country = 'GB';    // 2-letter ISO country code

    // Employment type mapping: Recruitly type → Google type
    $type_map = [
        'Permanent'  => 'FULL_TIME',
        'Contract'   => 'CONTRACTOR',
        'Temporary'  => 'TEMPORARY',
        'Part-Time'  => 'PART_TIME',
        'Internship' => 'INTERN',
        'Volunteer'  => 'VOLUNTEER',
        'Per Diem'   => 'PER_DIEM',
    ];

    // ── Pull job metadata ──
    $title       = get_post_meta($post_id, 'webAdvertTitle', true) ?: get_the_title();
    $description = get_post_meta($post_id, 'mainResponsibilities', true) ?: get_the_excerpt();
    $job_type    = get_post_meta($post_id, 'jobType', true);
    $date_posted = get_post_meta($post_id, 'datePosted', true);
    $closing     = get_post_meta($post_id, 'closingDate', true);
    $salary_from = get_post_meta($post_id, 'salaryFrom', true);
    $salary_to   = get_post_meta($post_id, 'salaryTo', true);
    $salary_per  = get_post_meta($post_id, 'salaryPer', true);
    $city        = get_post_meta($post_id, 'city', true);
    $county      = get_post_meta($post_id, 'county', true);
    $country     = get_post_meta($post_id, 'country', true);
    $postcode    = get_post_meta($post_id, 'postcode', true);
    $is_remote   = get_post_meta($post_id, 'isRemote', true);

    // Unit mapping for salary period
    $unit_map = [
        'annum' => 'YEAR',
        'day'   => 'DAY',
        'hour'  => 'HOUR',
        'month' => 'MONTH',
        'week'  => 'WEEK',
    ];

    $schema = [
        '@context'      => 'https://schema.org/',
        '@type'         => 'JobPosting',
        'title'         => $title,
        'description'   => $description,
        'datePosted'    => $date_posted,
        'hiringOrganization' => [
            '@type' => 'Organization',
            'name'  => $agency_name,
        ],
        'jobLocation' => [
            '@type'   => 'Place',
            'address' => [
                '@type'           => 'PostalAddress',
                'addressLocality' => $city,
                'addressRegion'   => $county,
                'addressCountry'  => $country ?: $default_country,
                'postalCode'      => $postcode,
            ],
        ],
    ];

    if ($closing) {
        $schema['validThrough'] = $closing;
    }

    if ($job_type && isset($type_map[$job_type])) {
        $schema['employmentType'] = $type_map[$job_type];
    }

    if ($salary_from || $salary_to) {
        $schema['baseSalary'] = [
            '@type'    => 'MonetaryAmount',
            'currency' => $currency,
            'value'    => [
                '@type'    => 'QuantitativeValue',
                'minValue' => $salary_from,
                'maxValue' => $salary_to,
                'unitText' => isset($unit_map[$salary_per]) ? $unit_map[$salary_per] : 'YEAR',
            ],
        ];
    }

    if ($is_remote) {
        $schema['jobLocationType'] = 'TELECOMMUTE';
    }

    echo '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_SLASHES) . '</script>';
}
add_action('wp_head', 'recruitly_google_jobs_schema');

Step 2 — Configure Your Values

Update these variables at the top of the snippet:

VariableDescriptionExample
$agency_nameYour company/agency name'Acme Recruitment'
$currencyISO currency code'GBP', 'USD', 'EUR', 'AUD'
$default_countryFallback ISO country code'GB', 'US', 'AU'
$type_mapMap your Recruitly job types to Google's employment typesSee code above

Google accepts these employment types: FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM, OTHER.

Step 3 — Test Your Markup

Use Google's Rich Results Test to validate your job pages:

  1. Enter a job page URL
  2. Check that the JobPosting structured data is detected
  3. Fix any warnings (missing salary data is a warning, not an error)

Step 4 — Submit Your Sitemap

  1. Go to Google Search Console
  2. Add your site if not already registered
  3. Submit your XML sitemap (usually yoursite.com/sitemap.xml)
  4. Google will begin crawling your job pages within 3–7 days

Best Practices

  • Remove expired jobs — Google penalizes sites that show expired listings. Recruitly handles this automatically when you close a job in the CRM.
  • Include salary ranges — listings with salary data get ~30% more clicks in Google for Jobs.
  • Use standard job titles — "Senior Software Engineer" ranks better than "Code Ninja Level 3".
  • Complete location data — include city, region, country, and postcode for best geo-matching.
  • Mobile optimization — ensure your job pages are mobile-friendly, as most job searches happen on mobile.

Troubleshooting

Jobs not appearing in Google for Jobs?

  • Verify the JSON-LD is rendering correctly (View Source → search for application/ld+json)
  • Check the Rich Results Test for errors
  • Ensure your sitemap is submitted and pages are indexed
  • Allow 3–7 days after submission for Google to crawl
  • Confirm that closed/expired jobs are actually removed from your site

Recruitly — Recruitment CRM for Agencies