Skip to content

Commit cb56fdc

Browse files
Merge pull request #66 from timja/seo-2
[WEBSITE-405] Use plugin-specific title and description in response metadata
2 parents 7b08cf7 + a40b229 commit cb56fdc

File tree

4 files changed

+28
-2
lines changed

4 files changed

+28
-2
lines changed

app/commons/helper.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ export function cleanTitle(title) {
1515
.replace(' for Jenkins','')
1616
.replace('Hudson ','');
1717
}
18+
19+
export const defaultPluginSiteTitle = 'Jenkins Plugins';
20+
export const pluginSiteTitleSuffix = 'Jenkins plugin';

app/components/Main.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Views from './Views';
1010
import { actions } from '../actions';
1111
import { isFiltered, showFilter, showResults, view } from '../selectors';
1212
import { createSelector } from 'reselect';
13+
import { defaultPluginSiteTitle } from '../commons/helper';
1314

1415
class Main extends React.PureComponent {
1516

@@ -77,6 +78,10 @@ class Main extends React.PureComponent {
7778
}
7879

7980
render() {
81+
if (typeof document !== 'undefined') {
82+
document.title = defaultPluginSiteTitle;
83+
}
84+
8085
return (
8186
<div>
8287
<div className={classNames(styles.ItemFinder, this.props.view, { showResults: this.props.showResults },

app/components/PluginDetail.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import moment from 'moment';
66
import LineChart from './LineChart';
77
import NotFound from './NotFound';
88
import Spinner from './Spinner';
9-
import { cleanTitle } from '../commons/helper';
9+
import { cleanTitle, pluginSiteTitleSuffix } from '../commons/helper';
1010
import { firstVisit, isFetchingPlugin, labels, plugin } from '../selectors';
1111
import { actions } from '../actions';
1212
import { createSelector } from 'reselect';
@@ -314,6 +314,10 @@ class PluginDetail extends React.PureComponent {
314314
return <NotFound/>;
315315
}
316316
}
317+
318+
if (typeof document !== 'undefined') {
319+
document.title = `${cleanTitle(plugin.title)} - ${pluginSiteTitleSuffix}`;
320+
}
317321
const beforeClose = this.closeDialog;
318322
return (
319323
<ModalView hideOnOverlayClicked isVisible ignoreEscapeKey {...{beforeClose}}>

server.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import fs from 'fs';
1515
import unirest from 'unirest';
1616
import cheerio from 'cheerio';
1717
import schedule from 'node-schedule';
18+
import { cleanTitle, defaultPluginSiteTitle, pluginSiteTitleSuffix } from './app/commons/helper';
1819

1920
const app = express();
2021
const port = 5000;
@@ -35,6 +36,10 @@ app.use(jsPath, express.static('./dist/client'));
3536
app.engine('hbs', exphbs({extname: '.hbs'}));
3637
app.set('view engine', 'hbs');
3738

39+
40+
const defaultPluginSiteDescription = 'Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software';
41+
const defaultPluginOpenGraphImage = 'https://jenkins.io/images/logo-title-opengraph.png'
42+
3843
const downloadHeader = () => {
3944
var headerFile = __HEADER_FILE__;
4045
if (headerFile !== null && headerFile !== undefined) {
@@ -57,6 +62,8 @@ const downloadHeader = () => {
5762
$('head').prepend('{{> header }}');
5863
// Even though we're supplying our own this one still causes a conflict.
5964
$('link[href="https://jenkins.io/css/font-icons.css"]').remove();
65+
// Prevents: Access to resource at 'https://jenkins.io/site.webmanifest' from origin 'https://plugins.jenkins.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
66+
$('link[href="https://jenkins.io/site.webmanifest"]').remove();
6067
$('head').append('<script>window.__REDUX_STATE__ = {{{reduxState}}};</script>');
6168
$('#grid-box').append('{{{rendered}}}');
6269
$('#grid-box').after('<script type="text/javascript" src="{{jsPath}}/main.js"></script>');
@@ -113,15 +120,22 @@ app.get('*', (req, res, next) => {
113120
const pluginSiteApiVersion = store.getState().data.info.commit.substring(0, 7);
114121
const reduxState = JSON.stringify(store.getState()).replace(/</g, '\\x3c');
115122
const pluginNotFound = req.url !== '/' && store.getState().ui.plugin === null;
123+
const title = store.getState().ui.plugin && store.getState().ui.plugin.title ? `${cleanTitle(store.getState().ui.plugin.title)} - ${pluginSiteTitleSuffix}` : defaultPluginSiteTitle;
124+
const description = store.getState().ui.plugin && store.getState().ui.plugin.excerpt ? store.getState().ui.plugin.excerpt : defaultPluginSiteDescription;
125+
const opengraphImage = defaultPluginOpenGraphImage; // TODO WEBSITE-645 add support for plugins to provide their own OG imag
126+
116127
res.status(pluginNotFound ? 404 : 200).render('index', {
117128
rendered,
129+
title,
130+
description,
118131
reduxState,
132+
opengraphImage,
119133
jsPath,
120134
pluginSiteVersion,
121135
pluginSiteApiVersion
122136
});
123137
}).catch((err) => {
124-
console.error(chalk.red(error));
138+
console.error(chalk.red(err));
125139
res.sendStatus(404);
126140
});
127141
}

0 commit comments

Comments
 (0)