├── resources └── locales │ ├── en │ └── default.po │ ├── default.pot │ ├── ru │ └── default.po │ ├── sv │ └── default.po │ ├── es │ └── default.po │ ├── nl │ └── default.po │ ├── fr │ └── default.po │ └── de │ └── default.po ├── .gitignore ├── sql ├── 0002.sql ├── 0004.sql ├── 0003.sql ├── 0005.sql ├── 0001.sql └── schema.sql ├── public ├── .htaccess ├── bootstrap │ ├── img │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ └── css │ │ ├── bootstrap-responsive.min.css │ │ └── bootstrap-responsive.css ├── js │ ├── timeago │ │ ├── jquery.timeago.tr.js │ │ ├── jquery.timeago.it.js │ │ ├── jquery.timeago.fr-short.js │ │ ├── jquery.timeago.hy.js │ │ ├── jquery.timeago.ja.js │ │ ├── jquery.timeago.ko.js │ │ ├── jquery.timeago.en-short.js │ │ ├── jquery.timeago.es-short.js │ │ ├── jquery.timeago.ro.js │ │ ├── jquery.timeago.pt-br-short.js │ │ ├── jquery.timeago.bg.js │ │ ├── jquery.timeago.sk.js │ │ ├── jquery.timeago.da.js │ │ ├── jquery.timeago.es.js │ │ ├── jquery.timeago.zh-CN.js │ │ ├── jquery.timeago.gl.js │ │ ├── jquery.timeago.no.js │ │ ├── jquery.timeago.pt.js │ │ ├── jquery.timeago.zh-TW.js │ │ ├── jquery.timeago.pt-br.js │ │ ├── jquery.timeago.ca.js │ │ ├── jquery.timeago.lt.js │ │ ├── jquery.timeago.de.js │ │ ├── jquery.timeago.si.js │ │ ├── jquery.timeago.sv.js │ │ ├── jquery.timeago.el.js │ │ ├── jquery.timeago.is.js │ │ ├── jquery.timeago.cy.js │ │ ├── jquery.timeago.id.js │ │ ├── jquery.timeago.rw.js │ │ ├── jquery.timeago.mk.js │ │ ├── jquery.timeago.fr.js │ │ ├── jquery.timeago.hu.js │ │ ├── jquery.timeago.jv.js │ │ ├── jquery.timeago.th.js │ │ ├── jquery.timeago.en.js │ │ ├── jquery.timeago.vi.js │ │ ├── jquery.timeago.nl.js │ │ ├── jquery.timeago.he.js │ │ ├── jquery.timeago.dv.js │ │ ├── jquery.timeago.uz.js │ │ ├── jquery.timeago.fa.js │ │ ├── jquery.timeago.pl.js │ │ ├── jquery.timeago.fi.js │ │ ├── README.md │ │ ├── jquery.timeago.et.js │ │ ├── jquery.timeago.cs.js │ │ ├── jquery.timeago.ky.js │ │ ├── jquery.timeago.ru.js │ │ ├── jquery.timeago.uk.js │ │ ├── jquery.timeago.bs.js │ │ ├── jquery.timeago.sl.js │ │ ├── jquery.timeago.rs.js │ │ ├── jquery.timeago.hr.js │ │ └── jquery.timeago.ar.js │ └── jquery.timeago.js ├── index.php └── css │ └── style.css ├── test.php ├── views ├── post.php ├── webmention-error.php ├── members.php ├── posts.php ├── index.php ├── webmention.php ├── _post-row.php ├── submit.php ├── layout.php ├── calendar.php ├── comment-full.php └── submit-full.php ├── README.md ├── composer.json ├── controllers ├── middleware.php ├── static.php ├── controllers.php └── webmention.php ├── lib ├── config.template.php ├── mf2.php └── helpers.php └── LICENSE.txt /resources/locales/en/default.po: -------------------------------------------------------------------------------- 1 | msgid "submitted ... from" 2 | msgstr "from" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.phar 3 | lib/config.php 4 | .DS_Store 5 | .idea/ 6 | -------------------------------------------------------------------------------- /sql/0002.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE posts 2 | ADD COLUMN `lang` char(2) DEFAULT 'en' AFTER id; 3 | -------------------------------------------------------------------------------- /sql/0004.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE posts 2 | ADD COLUMN `deleted` TINYINT(4) NOT NULL DEFAULT '0'; 3 | 4 | 5 | -------------------------------------------------------------------------------- /sql/0003.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE posts 2 | ADD COLUMN `tzoffset` int(11) NOT NULL DEFAULT 0 AFTER post_date; 3 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteRule ^ index.php [QSA,L] 4 | -------------------------------------------------------------------------------- /public/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/IndieNews/main/public/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /public/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/IndieNews/main/public/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | 2 | = $this->fetch('_post-row.php', [ 3 | 'post' => $post, 4 | 'position' => '', 5 | 'view' => 'single' 6 | ]) ?> 7 | 8 | -------------------------------------------------------------------------------- /views/webmention-error.php: -------------------------------------------------------------------------------- 1 |
= __('Error') ?>: = $error ?>
= htmlspecialchars($description) ?>
10 | 11 |= __('People who have submitted posts in the last year') ?>
7 | 8 |= __('There are no posts submitted to the English feed yet! As soon as you {0}submit a post{1} it will show up here.', ['','']) ?>
22 |= __('IndieNews is a community-curated list of articles relevant to the {0}Indie Web{1}.', ['', '']) ?>
4 |Want to see a new language? You can add a translation as a pull request! Copy the Locale file to a new folder, fill it out for your language, and submit a pull request!
17 |= __('Once you\'ve written a post with the proper markup, you will need to send a Webmention to submit it to IndieNews. Your software should do that automatically if it supports {0}, but you can also use the form below.', ['Webmention']) ?>
8 |= __('Write a post on your own site, and mark it up with the Microformats markup for an {0}.', 'h-entry') ?>
8 | 9 |= __('To submit someone else\'s post, create a {0} post on your site linking to it.', 'bookmark') ?>
10 | 11 |= __('Somewhere on the page you are submitting, add a {0} or {1} link to {2}the IndieNews home page{3} for your language.', ['u-syndication', 'u-category', '', '']) ?>
14 | 15 |= __('If your website sends {0} automatically, then your post will be submitted as soon as you post it to your website! Otherwise, you can enter your post\'s URL below.', ['Webmentions']) ?> 18 | 19 |
= __('IndieNews will fetch the page from your site and look for the {1} markup to find the post title and author.', ['Webmention', 'h-entry']) ?>
20 | 21 |34 | = __('Detailed instructions on how to submit a post') ?> 35 |
36 | 37 || = strftime('%A',strtotime(sprintf(($start==1?'2007-10':'2008-06').'-%02d',$i+1))) ?> | 9 | 10 |
|---|
| '."\n"; 20 | } 21 | } 22 | for($i = 1; $i <= $date->format('t'); $i++) { 23 | $thisDay = mktime(0,0,0,$month,$i,$year); 24 | if(strftime('%w',$thisDay) == $start) 25 | echo ' | '."\n";
31 |
32 | echo ' ' . $i . ' ' . "\n";
33 |
34 | if(array_key_exists($i, $calendar)) {
35 | foreach($calendar[$i] as $post) {
36 | echo '';
37 | echo '';
38 | if(shouldDisplayPostName($post->title)) {
39 | echo htmlspecialchars($post->title);
40 | } else {
41 | echo display_url($post->href);
42 | }
43 | echo ''."\n";
44 | if(shouldDisplayPostName($post->title))
45 | echo ' ';
46 | echo ' ';
47 | }
48 | }
49 |
50 | echo ' | '."\n";
51 | if( strftime(($start==1?'%u':'%w'),$thisDay) == ($start==1?7:6) )
52 | echo ''."\n";
53 | }
54 | if( $lastDayOfWeek < ($start==1?7:6) )
55 | {
56 | for( $i=$lastDayOfWeek; $i<($start==1?7:6); $i++ )
57 | {
58 | echo ''."\n"; 59 | } 60 | echo ''."\n"; 61 | } 62 | ?> 63 | |
'; print_r($a); echo ''; 132 | } 133 | 134 | function irc_notice($msg) { 135 | if(isset(Config::$ircURL)) { 136 | $ch = curl_init(Config::$ircURL); 137 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 138 | curl_setopt($ch, CURLOPT_POST, true); 139 | curl_setopt($ch, CURLOPT_HTTPHEADER, [ 140 | 'Authorization: Bearer ' . Config::$ircToken 141 | ]); 142 | curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array( 143 | 'content' => $msg, 144 | 'channel' => Config::$ircChannel 145 | ))); 146 | curl_exec($ch); 147 | } 148 | } 149 | 150 | /** 151 | * Converts base 10 to base 60. 152 | * http://tantek.pbworks.com/NewBase60 153 | * @param int $n 154 | * @return string 155 | */ 156 | function b10to60($n) 157 | { 158 | $s = ""; 159 | $m = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ_abcdefghijkmnopqrstuvwxyz"; 160 | if ($n==0) 161 | return 0; 162 | 163 | while ($n>0) 164 | { 165 | $d = $n % 60; 166 | $s = $m[$d] . $s; 167 | $n = ($n-$d)/60; 168 | } 169 | return $s; 170 | } 171 | 172 | /** 173 | * Converts base 60 to base 10, with error checking 174 | * http://tantek.pbworks.com/NewBase60 175 | * @param string $s 176 | * @return int 177 | */ 178 | function b60to10($s) 179 | { 180 | $n = 0; 181 | for($i = 0; $i < strlen($s); $i++) // iterate from first to last char of $s 182 | { 183 | $c = ord($s[$i]); // put current ASCII of char into $c 184 | if ($c>=48 && $c<=57) { $c=$c-48; } 185 | else if ($c>=65 && $c<=72) { $c-=55; } 186 | else if ($c==73 || $c==108) { $c=1; } // typo capital I, lowercase l to 1 187 | else if ($c>=74 && $c<=78) { $c-=56; } 188 | else if ($c==79) { $c=0; } // error correct typo capital O to 0 189 | else if ($c>=80 && $c<=90) { $c-=57; } 190 | else if ($c==95) { $c=34; } // underscore 191 | else if ($c>=97 && $c<=107) { $c-=62; } 192 | else if ($c>=109 && $c<=122) { $c-=63; } 193 | else { $c = 0; } // treat all other noise as 0 194 | $n = (60 * $n) + $c; 195 | } 196 | return $n; 197 | } 198 | -------------------------------------------------------------------------------- /controllers/controllers.php: -------------------------------------------------------------------------------- 1 | redirect('/home.json', '/en.json', 301); 7 | $app->redirect('/newest.json', '/en.json', 301); 8 | 9 | // Redirect post IDs to the post URL version 10 | $app->get('/post/{id:[0-9]+}{format:|\.json}', function($request, $response, $args) { 11 | $post = ORM::for_table('posts') 12 | ->where('id', $args['id']) 13 | ->where('deleted', 0) 14 | ->find_one(); 15 | 16 | if(!$post) 17 | return $response->withStatus(404); 18 | 19 | $url = Config::$baseURL . '/post/'. slugForURL($post->href) . ($args['format']); 20 | 21 | return $response 22 | ->withHeader('Location', $url) 23 | ->withStatus(302); 24 | }); 25 | 26 | // Language-specific feeds 27 | $app->get('/{lang:'.LANG_REGEX.'}{format:|\.json|\.jf2}', function($request, $response, $args) { 28 | 29 | $params = $request->getQueryParams(); 30 | 31 | $format = formatFromRouteArgs($args); 32 | 33 | I18n::setLocale($args['lang']); 34 | 35 | // Get posts ordered by date submitted 36 | $posts = ORM::for_table('posts') 37 | ->where('lang', $args['lang']) 38 | ->where('deleted', 0) 39 | ->order_by_desc('date_submitted'); 40 | 41 | if(array_key_exists('before', $params)) { 42 | $before = date('Y-m-d H:i:s', b60to10($params['before'])); 43 | $posts = $posts->where_lt('date_submitted', $before); 44 | } 45 | 46 | $posts = $posts->limit(20)->find_many(); 47 | 48 | $atomFeed = ''; 49 | $webSubTags = '' . "\n" . ''; 50 | 51 | $renderer = new PhpRenderer(__DIR__.'/../views/'); 52 | $renderer->setLayout('layout.php'); 53 | 54 | $temp = $renderer->render(new \Slim\Psr7\Response(), "posts.php", [ 55 | 'title' => 'IndieNews ' . $args['lang'], 56 | 'posts' => $posts, 57 | 'lang' => $args['lang'], 58 | 'meta' => $atomFeed.$webSubTags, 59 | ]); 60 | 61 | $html = $temp->getBody()->__toString(); 62 | 63 | $response = $response->withAddedHeader('Link', '<' . Config::$baseURL . '/'.$args['lang'].'/webmention>; rel="webmention"'); 64 | $response = $response->withAddedHeader('Link', '<' . Config::$baseURL . '/'.$args['lang'].'>; rel="self"'); 65 | $response = $response->withAddedHeader('Link', '<' . Config::$hubURL . '>; rel="hub"'); 66 | 67 | return respondWithFormat($response, $html, $format); 68 | }); 69 | 70 | 71 | $app->get('/{lang:'.LANG_REGEX.'}/{year:\d{4}}/{month:\d{2}}', function($request, $response, $args) { 72 | 73 | $year = $args['year']; 74 | $month = $args['month']; 75 | $lang = $args['lang']; 76 | 77 | I18n::setLocale($args['lang']); 78 | setlocale(LC_ALL, localeFromLangCode($args['lang'])); 79 | 80 | $date = new DateTime($year.'-'.$month.'-01'); 81 | 82 | $posts = ORM::for_table('posts') 83 | ->where('lang', $lang) 84 | ->where('deleted', 0) 85 | ->where_lte('date_submitted', $date->format('Y-m-t').' 23:59:59') 86 | ->where_gte('date_submitted', $date->format('Y-m-01')) 87 | ->order_by_asc('date_submitted') 88 | ->find_many(); 89 | 90 | $prev = false; 91 | $next = false; 92 | 93 | $prevPost = ORM::for_table('posts') 94 | ->where('lang', $lang) 95 | ->where('deleted', 0) 96 | ->where_lt('date_submitted', $date->format('Y-m-01')) 97 | ->order_by_desc('date_submitted') 98 | ->find_one(); 99 | if($prevPost) { 100 | $prev = new DateTime($prevPost->date_submitted); 101 | } 102 | 103 | $nextPost = ORM::for_table('posts') 104 | ->where('lang', $lang) 105 | ->where('deleted', 0) 106 | ->where_gt('date_submitted', $date->format('Y-m-t').' 23:59:59') 107 | ->order_by_asc('date_submitted') 108 | ->find_one(); 109 | if($nextPost) { 110 | $next = new DateTime($nextPost->date_submitted); 111 | } 112 | 113 | $calendar = []; 114 | foreach($posts as $post) { 115 | $postDate = $post->post_date ?: $post->date_submitted; 116 | $day = printLocalDate('j', $postDate, $post->tzoffset); 117 | if(!array_key_exists($day, $calendar)) 118 | $calendar[(int)$day] = []; 119 | $calendar[(int)$day][] = $post; 120 | } 121 | ksort($calendar); 122 | 123 | return render($response, 'calendar', [ 124 | 'title' => 'IndieNews ' . $lang, 125 | 'date' => $date, 126 | 'year' => $year, 127 | 'month' => $month, 128 | 'calendar' => $calendar, 129 | 'meta' => '', 130 | 'lang' => $lang, 131 | 'next' => $next, 132 | 'prev' => $prev 133 | ]); 134 | }); 135 | 136 | 137 | 138 | 139 | // Language-specific submit instructions 140 | $app->get('/{lang:'.LANG_REGEX.'}/submit', function($request, $response, $args) { 141 | I18n::setLocale($args['lang']); 142 | 143 | return render($response, 'submit', array( 144 | 'title' => __('About IndieNews'), 145 | 'meta' => '', 146 | 'lang' => $args['lang'] 147 | )); 148 | }); 149 | 150 | 151 | $app->get('/{lang:'.LANG_REGEX.'}/members', function($request, $response, $args) { 152 | I18n::setLocale($args['lang']); 153 | 154 | $users = ORM::for_table('users') 155 | ->select('users.*') 156 | ->select_expr('COUNT(posts.id) AS num_posts') 157 | ->join('posts', ['posts.user_id', '=', 'users.id']) 158 | ->where('posts.lang', $args['lang']) 159 | ->where('posts.deleted', 0) 160 | ->where_gt('posts.date_submitted', date('Y-m-d H:i:s', strtotime('1 year ago'))) 161 | ->group_by('users.id') 162 | ->order_by_desc('num_posts') 163 | ->find_many(); 164 | 165 | return render($response, 'members', array( 166 | 'title' => __('IndieNews Members'), 167 | 'meta' => '', 168 | 'lang' => $args['lang'], 169 | 'users' => $users 170 | )); 171 | }); 172 | 173 | 174 | // Language-specific permalinks 175 | $app->get('/{lang:'.LANG_REGEX.'}/{slug:.*?}{format:|\.json|\.jf2}', function($request, $response, $args) { 176 | $format = formatFromRouteArgs($args); 177 | $slug = $args['slug']; 178 | 179 | I18n::setLocale($args['lang']); 180 | 181 | $post = ORM::for_table('posts') 182 | ->where_in('href', array('http://'.$slug,'https://'.$slug)) 183 | ->where('deleted', 0) 184 | ->find_one(); 185 | $posts = array($post); 186 | 187 | $response = $response->withAddedHeader('Link', '<' . Config::$baseURL . '/'.$args['lang'].'/webmention>; rel="webmention"'); 188 | 189 | if(!$post) { 190 | return $response->withStatus(404); 191 | } 192 | 193 | $renderer = new PhpRenderer(__DIR__.'/../views/'); 194 | $renderer->setLayout('layout.php'); 195 | 196 | $temp = $renderer->render(new \Slim\Psr7\Response(), "post.php", [ 197 | 'title' => $post->title, 198 | 'post' => $post, 199 | 'view' => 'single', 200 | 'meta' => '', 201 | 'lang' => $args['lang'] 202 | ]); 203 | 204 | $html = $temp->getBody()->__toString(); 205 | 206 | return respondWithFormat($response, $html, $format); 207 | }); 208 | -------------------------------------------------------------------------------- /views/comment-full.php: -------------------------------------------------------------------------------- 1 |
In order to comment on a post, you do not need an IndieNews account. Instead, you 7 | can only submit comments as posts from your own site, by linking to the IndieNews page 8 | you wish to comment on and sending a notification using the 9 | webmention protocol!
10 | 11 | 12 |Create a new post on your site, and mark it up with the Microformats markup for 15 | an h-entry.
16 | 17 | 18 | 19 |Somewhere in the h-entry, add a link to the original post you are commenting on 22 | (not the IndieNews URL) with the class "u-in-reply-to". 23 | This usually looks something like the following:
24 | 25 |<a href="http://aaronparecki.com/notes/2013/04/25/1" class="u-in-reply-to" rel="in-reply-to">
26 | In Reply To @aaronpk
27 | </a>
28 |
29 |
30 |
31 | Inside the h-entry, add a link to the IndieNews URL for the post with the class 34 | u-syndication. This usually 35 | looks something like the following:
36 | 37 |<a href="https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1" class="u-syndication" rel="syndication">Also posted on IndieNews</a>
38 |
39 | You can construct the IndieNews URL before it's posted to IndieNews by following the 40 | convention IndieNews uses for building its permalinks. Follow the example above, or 41 | read the full instructions on constructing post URLs. 42 | 43 | 44 | 45 |
Make a POST request to news.indieweb.org/webmention with two parameters,
50 | source and target, where target is
51 | https://news.indieweb.org/post/example.com/100 and source is
52 | http://example.com/100 assuming you are submitting a page on your site with
53 | the url http://example.com/100.
POST /webmention HTTP/1.1
56 | Host: news.indieweb.org
57 |
58 | target=https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1/original-post-discovery
59 | &source=http://aaronparecki.com/notes/2013/04/25/1/original-post-discovery
60 |
61 |
62 | {
65 | "result": "success",
66 | "notices": [
67 | ],
68 | "data": {
69 | "title": "A demonstration of Original Post Discovery #indieweb",
70 | "author": "aaronparecki.com",
71 | "date": "2013-04-26T03:22:39+00:00"
72 | },
73 | "source": "http://aaronparecki.com/notes/2013/04/25/1/original-post-discovery",
74 | "target": "https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1/original-post-discovery",
75 | "href": "https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1/original-post-discovery"
76 | }
77 |
78 |
79 | This webmention endpoint returns more data than is technically required for a WebMention to succeed. It will 80 | return data that is useful for debugging purposes while you're initially trying it out.
81 | 82 |result - Will be equal to "success" if the submission was acceptednotices - An array of string messages if there was anything that needs attention in your submission. These are not errors, but will indicate if microformat markup was not present or invalid.data - This object shows the values extracted from the page, including title, author and date.source - The source URL sent in the initial request.target - The target URL sent in the initial request.href - The permalink to this submission on news.indieweb.org.canonical - If you accidentally linked your "in-reply-to" to the IndieNews URL, this field will tell you the canonical URL of the post you were actually replying to.curl https://news.indieweb.org/webmention -i \
96 | -d target=https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1/original-post-discovery \
97 | -d source=http://aaronparecki.com/notes/2013/04/25/1/original-post-discovery
98 |
99 |
100 | <?php
102 | $ch = curl_init("https://news.indieweb.org/webmention");
103 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
104 | curl_setopt($ch, CURLOPT_POST, true);
105 | curl_setopt($ch, CURLOPT_POSTFIELDS, array(
106 | 'target' => 'https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1/original-post-discovery',
107 | 'source' => 'http://aaronparecki.com/notes/2013/04/25/1/original-post-discovery'
108 | ));
109 | echo curl_exec($ch);
110 | ?>
111 |
112 | require 'rest-client'
114 | require 'json'
115 |
116 | data = JSON.parse RestClient.post "https://news.indieweb.org/webmention", {
117 | 'target' => 'https://news.indieweb.org/post/aaronparecki.com/notes/2013/04/25/1/original-post-discovery',
118 | 'source' => 'http://aaronparecki.com/notes/2013/04/25/1/original-post-discovery'
119 | }
120 | jj data
121 |
122 |
123 | If you update the post (for example trying to debug the microformats markup, or changing the post 126 | title), you can re-send the webmention. The existing post will be updated with the new information found.
127 | 128 | 129 |Your page must be marked up with an h-entry 132 | or an h-event, IndieNews will 133 | use the name in the entry as the title of the submission.
134 | 135 |If an h-card is present, 136 | author information will be pulled from there, otherwise it will fall back to using the domain name as the author.
137 | 138 | 139 |If you use a client which automatically sends pingbacks to 142 | any links found in the post, then you can use the same flow as the WebMention flow but send a Pingback instead! 143 | You can find the pingback endpoint using the normal pingback discovery mechanism.
144 | 145 |Note that the rich debugging response will not be present in the pingback reply.
146 | 147 |IndieNews is a community-curated list of articles relevant to the Indie Web.
4 |In order to submit a post, you do not need an IndieNews account. Instead, you can only submit 12 | posts from your own site by linking to the IndieNews site and sending a notification 13 | using the webmention protocol!
14 | 15 | 16 |Create a new post on your site, and mark it up with the Microformats markup for 19 | an h-entry.
20 | 21 |If you are submitting your own post, that's all you have to do.
22 | 23 |To submit someone else's post, you can post a bookmark on your site and submit that 24 | URL to IndieNews! Post an h-entry as normal, then include a 25 | u-bookmark-of property 26 | linking to the actual URL you want to submit.
27 | 28 | 29 |Inside the h-entry, add a link to the IndieNews home page for your language with the class 32 | u-syndication or 33 | u-category. This usually 34 | looks something like the following:
35 | 36 |<a href="https://news.indieweb.org/en" class="u-syndication">
37 | Also posted on IndieNews
38 | </a>
39 |
40 | <a href="https://news.indieweb.org/en" class="u-category">#indienews</a>
41 |
42 |
43 | If your website sends Webmentions automatically, then you don't need to worry about this step. Otherwise, follow the instructions below to send a Webmention, or just use the Webmention form available at the IndieNews Webmention endpoint.
46 | 47 |Make a POST request to https://news.indieweb.org/en/webmention with two parameters,
50 | source and target, where target is
51 | https://news.indieweb.org/en and source is
52 | http://example.com/100 assuming you are submitting a page on your site with
53 | the url http://example.com/100.
Note that each language's home page has a unique Webmention endpoint, so you should 56 | do the Webmention endpoint discovery as normal to find it.
57 | 58 |POST /en/webmention HTTP/1.1
59 | Host: news.indieweb.org
60 |
61 | target=https://news.indieweb.org/en
62 | &source=https://aaronparecki.com/2013/04/25/4/original-post-discovery
63 |
64 |
65 |
66 | HTTP/1.1 201 Created
69 | Location: https://news.indieweb.org/en/aaronparecki.com/2013/04/25/4/original-post-discovery
70 |
71 | {
72 | "result": "success",
73 | "notices": [
74 | ],
75 | "data": {
76 | "title": "A demonstration of Original Post Discovery #indieweb",
77 | "author": "aaronparecki.com",
78 | "date": "2013-04-26T03:22:39+00:00"
79 | },
80 | "source": "https://aaronparecki.com/2013/04/25/4/original-post-discovery",
81 | "url": "https://news.indieweb.org/en/aaronparecki.com/2013/04/25/4/original-post-discovery"
82 | }
83 |
84 |
85 | You can find the permalink of your syndication by looking for the Location header in the response. You can then update your post with that URL so that your post always links to the IndieNews permalink instead of the IndieNews home page.
This webmention endpoint also returns more data that is useful for debugging purposes while you're initially trying it out.
88 | 89 |result - Will be equal to "success" if the submission was acceptednotices - An array of string messages if there was anything that needs attention in your submission. These are not errors, but will indicate if microformat markup was not present or invalid.data - This object shows the values extracted from the page, including title, author and date.source - The source URL sent in the initial requesturl - The permalink to this submission on news.indieweb.org.curl https://news.indieweb.org/en/webmention -i \
101 | -d target=https://news.indieweb.org/en \
102 | -d source=https://aaronparecki.com/2013/04/25/4/original-post-discovery
103 |
104 |
105 | <?php
107 | $ch = curl_init("https://news.indieweb.org/en/webmention");
108 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
109 | curl_setopt($ch, CURLOPT_POST, true);
110 | curl_setopt($ch, CURLOPT_POSTFIELDS, array(
111 | 'target' => 'https://news.indieweb.org/en',
112 | 'source' => 'https://aaronparecki.com/2013/04/25/4/original-post-discovery'
113 | ));
114 | echo curl_exec($ch);
115 | ?>
116 |
117 | require 'rest-client'
119 | require 'json'
120 |
121 | data = JSON.parse RestClient.post "https://news.indieweb.org/en/webmention", {
122 | 'target' => 'https://news.indieweb.org/en',
123 | 'source' => 'https://aaronparecki.com/2013/04/25/4/original-post-discovery'
124 | }
125 | jj data
126 |
127 |
128 | If you update the post (for example trying to debug the microformats markup, or changing the post 131 | title), you can re-send the webmention. The existing IndieNews post will be updated with the new information found.
132 | 133 | 134 |Your page must be marked up with an h-entry 137 | or an h-event, IndieNews will 138 | use the name in the entry as the title of the submission.
139 | 140 |If an h-card is present, 141 | author information will be pulled from there, otherwise it will fall back to using the domain name as the author.
142 | 143 | 144 |If you use a client which automatically sends pingbacks to 147 | any links found in the post, then you can use the same flow as the WebMention flow but send a Pingback instead! 148 | You can find the pingback endpoint using the normal pingback discovery mechanism.
149 | 150 |Note that the rich debugging response will not be present in the pingback reply.
151 | 152 |